Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only parse persistence.xml at build time #31

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -175,6 +176,7 @@ private final class ProcessorContextImpl implements ProcessorContext {
private final Set<String> resourceBundles = new HashSet<>();
private final Set<String> runtimeInitializedClasses = new HashSet<>();
private final Set<List<String>> proxyClasses = new HashSet<>();
private final Map<String, Object> properties = new HashMap<>();

@Override
public BytecodeRecorder addStaticInitTask(int priority) {
Expand Down Expand Up @@ -301,6 +303,16 @@ public boolean isCapabilityPresent(String capability) {
return capabilities.contains(capability);
}

@Override
public <T> void setProperty(String key, T value) {
properties.put(key, value);
}

@Override
public <T> T getProperty(String key) {
return (T) properties.get(key);
}


void writeMainClass() throws IOException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,8 @@ public interface ProcessorContext {
* @return
*/
boolean isCapabilityPresent(String capability);

<T> void setProperty(String key, T value);

<T> T getProperty(String key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class RuntimePriority {
public static final int JAXRS_DEPLOYMENT = 350;
public static final int ARC_DEPLOYMENT = 300;
public static final int UNDERTOW_DEPLOY = 400;
public static final int JPA_DEPLOYMENT = 500;
public static final int BEAN_VALIDATION_DEPLOYMENT = 600;
public static final int TRANSACTIONS_DEPLOYMENT = 700;
public static final int DATASOURCE_DEPLOYMENT = 700;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.jboss.shamrock.deployment.codegen;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.function.Function;

import org.jboss.shamrock.runtime.InjectionInstance;

Expand Down Expand Up @@ -38,6 +41,16 @@ public interface BytecodeRecorder extends AutoCloseable {
*/
<F, T> void registerSubstitution(Class<F> from, Class<T> to, Class<? extends ObjectSubstitution<F, T>> substitution);

/**
* Registers a way to construct an object via a non-default constructor. Each object may only have at most one
* non-default constructor registered
*
* @param constructor The constructor
* @param parameters A function that maps the object to a list of constructor parameters
* @param <T> The type of the object
*/
<T> void registerNonDefaultConstructor(Constructor<T> constructor, Function<T, List<Object>> parameters);

/**
* Creates an instance factory that can be used to create an injected instance.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import static org.jboss.protean.gizmo.MethodDescriptor.ofMethod;

import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -18,14 +20,17 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import org.apache.commons.beanutils.PropertyUtils;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.invocation.proxy.ProxyConfiguration;
import org.jboss.invocation.proxy.ProxyFactory;
import org.jboss.protean.gizmo.BranchResult;
import org.jboss.protean.gizmo.CatchBlockCreator;
import org.jboss.protean.gizmo.ClassCreator;
import org.jboss.protean.gizmo.ExceptionTable;
import org.jboss.protean.gizmo.MethodCreator;
import org.jboss.protean.gizmo.MethodDescriptor;
import org.jboss.protean.gizmo.ResultHandle;
Expand All @@ -40,6 +45,8 @@
public class BytecodeRecorderImpl implements BytecodeRecorder {

private static final AtomicInteger COUNT = new AtomicInteger();
private static final MethodDescriptor COLLECTION_ADD = ofMethod(Collection.class, "add", boolean.class, Object.class);
private static final MethodDescriptor MAP_PUT = ofMethod(Map.class, "put", Object.class, Object.class, Object.class);

private final ClassLoader classLoader;
private final String className;
Expand All @@ -51,6 +58,7 @@ public class BytecodeRecorderImpl implements BytecodeRecorder {
private final Map<Class, ProxyFactory<?>> returnValueProxy = new HashMap<>();
private final IdentityHashMap<Class<?>, String> classProxies = new IdentityHashMap<>();
private final Map<Class<?>, SubstitutionHolder> substitutions = new HashMap<>();
private final Map<Class<?>, NonDefaultConstructorHolder> nonDefaulConstructors = new HashMap<>();

public BytecodeRecorderImpl(ClassLoader classLoader, String className, Class<?> serviceType, ClassOutput classOutput) {
this.classLoader = classLoader;
Expand Down Expand Up @@ -86,6 +94,11 @@ public <F, T> void registerSubstitution(Class<F> from, Class<T> to, Class<? exte
substitutions.put(from, new SubstitutionHolder(from, to, substitution));
}

@Override
public <T> void registerNonDefaultConstructor(Constructor<T> constructor, Function<T, List<Object>> parameters) {
nonDefaulConstructors.put(constructor.getDeclaringClass(), new NonDefaultConstructorHolder(constructor, (Function<Object, List<Object>>) parameters));
}

@Override
public InjectionInstance<?> newInstanceFactory(String className) {
NewInstance instance = new NewInstance(className);
Expand Down Expand Up @@ -307,6 +320,14 @@ private ResultHandle loadObjectInstance(MethodCreator method, Object param, Map<
} else {
out = method.load((String) param);
}
} else if (param instanceof URL) {
String url = ((URL) param).toExternalForm();
ExceptionTable et = method.addTryCatch();
out = method.newInstance(MethodDescriptor.ofConstructor(URL.class, String.class), method.load(url));
CatchBlockCreator malformed = et.addCatchClause(MalformedURLException.class);
malformed.throwException(RuntimeException.class, "Malformed URL", malformed.getCaughtException());
et.complete();

} else if (param instanceof Enum) {
Enum e = (Enum) param;
ResultHandle nm = method.load(e.name());
Expand Down Expand Up @@ -361,28 +382,77 @@ private ResultHandle loadObjectInstance(MethodCreator method, Object param, Map<
method.writeArrayValue(out, method.load(i), component);
}
} else {
try {
param.getClass().getDeclaredConstructor();
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to serialize objects of type " + param.getClass() + " to bytecode as it has no default constructor");
if(nonDefaulConstructors.containsKey(param.getClass())) {
NonDefaultConstructorHolder holder = nonDefaulConstructors.get(param.getClass());
List<Object> params = holder.paramGenerator.apply(param);
if(params.size() != holder.constructor.getParameterCount()) {
throw new RuntimeException("Unable to serialize " + param + " as the wrong number of parameters were generated for " + holder.constructor);
}
List<ResultHandle> handles = new ArrayList<>();
int count = 0;
for(Object i : params) {
handles.add(loadObjectInstance(method, i, returnValueResults, holder.constructor.getParameterTypes()[count++]));
}
out = method.newInstance(ofConstructor(holder.constructor.getDeclaringClass(), holder.constructor.getParameterTypes()), handles.toArray(new ResultHandle[handles.size()]));
} else {
try {
param.getClass().getDeclaredConstructor();
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to serialize objects of type " + param.getClass() + " to bytecode as it has no default constructor");
}

out = method.newInstance(ofConstructor(param.getClass()));
}
out = method.newInstance(ofConstructor(param.getClass()));
if (param instanceof Collection) {
for (Object i : (Collection) param) {
ResultHandle val = loadObjectInstance(method, i, returnValueResults, i.getClass());
method.invokeInterfaceMethod(ofMethod(Collection.class, "add", boolean.class, Object.class), out, val);
method.invokeInterfaceMethod(COLLECTION_ADD, out, val);
}
}
if (param instanceof Map) {
for (Map.Entry<?, ?> i : ((Map<?, ?>) param).entrySet()) {
ResultHandle key = loadObjectInstance(method, i.getKey(), returnValueResults, i.getKey().getClass());
ResultHandle val = loadObjectInstance(method, i.getValue(), returnValueResults, i.getValue().getClass());
method.invokeInterfaceMethod(ofMethod(Map.class, "put", Object.class, Object.class, Object.class), out, key, val);
method.invokeInterfaceMethod(MAP_PUT, out, key, val);
}
}
PropertyDescriptor[] desc = PropertyUtils.getPropertyDescriptors(param);
for (PropertyDescriptor i : desc) {
if (i.getReadMethod() != null && i.getWriteMethod() != null) {
if(i.getReadMethod() != null && i.getWriteMethod() == null ) {
try {
//read only prop, we may still be able to do stuff with it if it is a collection
if(Collection.class.isAssignableFrom(i.getPropertyType())) {
//special case, a collection with only a read method
//we assume we can just add to the connection

Collection propertyValue = (Collection) PropertyUtils.getProperty(param, i.getName());
if(!propertyValue.isEmpty()) {
ResultHandle prop = method.invokeVirtualMethod(MethodDescriptor.ofMethod(i.getReadMethod()), out);
for (Object c : propertyValue) {
ResultHandle toAdd = loadObjectInstance(method, c, returnValueResults, Object.class);
method.invokeInterfaceMethod(COLLECTION_ADD, prop, toAdd);
}
}

} else if(Map.class.isAssignableFrom(i.getPropertyType())) {
//special case, a map with only a read method
//we assume we can just add to the map

Map<Object, Object> propertyValue = (Map<Object, Object>)PropertyUtils.getProperty(param, i.getName());
if(!propertyValue.isEmpty()) {
ResultHandle prop = method.invokeVirtualMethod(MethodDescriptor.ofMethod(i.getReadMethod()), out);
for (Map.Entry<Object, Object> entry : propertyValue.entrySet()) {
ResultHandle key = loadObjectInstance(method, entry.getKey(), returnValueResults, Object.class);
ResultHandle val = loadObjectInstance(method, entry.getValue(), returnValueResults, Object.class);
method.invokeInterfaceMethod(MAP_PUT, prop, key, val);
}
}
}

} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (i.getReadMethod() != null && i.getWriteMethod() != null) {
try {
Object propertyValue = PropertyUtils.getProperty(param, i.getName());
if (propertyValue == null) {
Expand Down Expand Up @@ -465,4 +535,14 @@ static final class SubstitutionHolder {
}
}

static final class NonDefaultConstructorHolder {
final Constructor<?> constructor;
final Function<Object, List<Object>> paramGenerator;

NonDefaultConstructorHolder(Constructor<?> constructor, Function<Object, List<Object>> paramGenerator) {
this.constructor = constructor;
this.paramGenerator = paramGenerator;
}
}

}
5 changes: 0 additions & 5 deletions examples/strict/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,6 @@
<artifactId>shamrock-graal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>

<build>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,19 @@ public void seetup() throws Exception {

try (Connection con = dataSource.getConnection()) {
try (Statement statement = con.createStatement()) {
try {
statement.execute("drop table a");
statement.execute("drop table tx");
} catch (Exception ignored) {

}
statement.execute("create table a (b int)");
statement.execute("create table tx (b int)");
}
}
}


public void doInit() {

}
Expand Down
Loading