org.sfm.reflect.asm.AsmFactory Maven / Gradle / Ivy
package org.sfm.reflect.asm;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicLong;
import org.objectweb.asm.Opcodes;
import org.sfm.jdbc.JdbcMapper;
import org.sfm.map.FieldMapper;
import org.sfm.reflect.Getter;
import org.sfm.reflect.Instantiator;
import org.sfm.reflect.Setter;
public class AsmFactory implements Opcodes {
private static class FactoryClassLoader extends ClassLoader {
public FactoryClassLoader(final ClassLoader parent) {
super(parent);
}
private final Map> classes = new HashMap>();
@Override
protected Class> findClass(final String name) throws ClassNotFoundException {
final Class> type = classes.get(name);
if (type != null) {
return type;
} else {
return super.findClass(name);
}
}
public Class> registerGetter(final String name, final byte[] bytes) {
Class> type = classes.get(name);
if (type == null) {
type = defineClass(name, bytes, 0, bytes.length);
return type;
} else {
throw new RuntimeException("Setter " + name + " already defined");
}
}
}
private final FactoryClassLoader factoryClassLoader;
private final Map> setters = new HashMap>();
private final Map> instantiators = new HashMap>();
public AsmFactory() {
this(Thread.currentThread().getContextClassLoader());
}
public AsmFactory(ClassLoader cl) {
factoryClassLoader = new FactoryClassLoader(cl);
}
@SuppressWarnings("unchecked")
public Setter createSetter(final Method m) throws Exception {
Setter setter = (Setter) setters.get(m);
if (setter == null) {
final String className = generateClassName(m);
final byte[] bytes = generateClass(m, className);
final Class> type = factoryClassLoader.registerGetter(className, bytes);
setter = (Setter) type.newInstance();
setters.put(m, setter);
}
return setter;
}
private byte[] generateClass(final Method m, final String className) throws Exception {
final Class> propertyType = m.getParameterTypes()[0];
if (AsmUtils.primitivesClassAndWrapper.contains(propertyType)) {
return SetterBuilder.createPrimitiveSetter(className, m);
} else {
return SetterBuilder.createObjectSetter(className, m);
}
}
@SuppressWarnings("unchecked")
public Instantiator createEmptyArgsInstatiantor(final Class source, final Class target) throws Exception {
InstantiatorKey instantiatorKey = new InstantiatorKey(target);
Instantiator instantiator = (Instantiator) instantiators.get(instantiatorKey);
if (instantiator == null) {
final String className = generateInstantiatorClassName(instantiatorKey);
final byte[] bytes = ConstructorBuilder.createEmptyConstructor(className, source, target);
final Class> type = factoryClassLoader.registerGetter(className, bytes);
instantiator = (Instantiator) type.newInstance();
instantiators.put(instantiatorKey, instantiator);
}
return instantiator;
}
@SuppressWarnings("unchecked")
public Instantiator createInstatiantor(final Class source, final ConstructorDefinition constructorDefinition,final Map> injections) throws Exception {
InstantiatorKey instantiatorKey = new InstantiatorKey(constructorDefinition, injections.keySet());
Instantiator instantiator = (Instantiator) instantiators.get(instantiatorKey);
if (instantiator == null) {
final String className = generateInstantiatorClassName(instantiatorKey);
final byte[] bytes = InstantiatorBuilder.createInstantiator(className, source, constructorDefinition, injections);
final Class> type = factoryClassLoader.registerGetter(className, bytes);
Map> getterPerName = new HashMap<>();
for(Entry> e : injections.entrySet()) {
getterPerName.put(e.getKey().getName(), e.getValue());
}
instantiator = (Instantiator) type.getConstructor(Map.class).newInstance(getterPerName);
instantiators.put(instantiatorKey, instantiator);
}
return instantiator;
}
@SuppressWarnings("unchecked")
public JdbcMapper createJdbcMapper(final FieldMapper[] mappers, final Instantiator instantiator, final Class target) throws Exception {
final String className = generateClassName(mappers, ResultSet.class, target);
final byte[] bytes = JdbcMapperBuilder.dump(className, mappers, instantiator, target);
final Class> type = factoryClassLoader.registerGetter(className, bytes);
return (JdbcMapper) type.getDeclaredConstructors()[0].newInstance(mappers, instantiator);
}
private final AtomicLong classNumber = new AtomicLong();
private String generateInstantiatorClassName(final InstantiatorKey key) {
StringBuilder sb = new StringBuilder();
sb.append( "org.sfm.reflect.asm.")
.append(key.getConstructor().getDeclaringClass().getPackage().getName())
.append(".AsmInstantiator").append(key.getConstructor().getDeclaringClass().getSimpleName());
String[] injectedParams = key.getInjectedParams();
if (injectedParams != null) {
for(String str : injectedParams) {
sb.append(str.substring(0, Math.min(str.length(), 3)));
}
}
sb.append(Long.toHexString(classNumber.getAndIncrement()));
return sb.toString();
}
private String generateClassName(final Method m) {
return "org.sfm.reflect.asm." + m.getDeclaringClass().getPackage().getName() +
".AsmSetter" + m.getName()
+ m.getDeclaringClass().getSimpleName()
+ m.getParameterTypes()[0].getSimpleName()
;
}
private String generateClassName(final FieldMapper[] mappers, final Class source, final Class target) {
return "org.sfm.reflect.asm." + target.getPackage().getName() +
".AsmMapper" + source.getSimpleName() + "2" + target.getSimpleName() + mappers.length + "_" + classNumber.getAndIncrement();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy