org.sfm.reflect.asm.AsmFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simpleFlatMapper Show documentation
Show all versions of simpleFlatMapper Show documentation
Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.
package org.sfm.reflect.asm;
import org.sfm.jdbc.JdbcMapper;
import org.sfm.map.MappingContextFactory;
import org.sfm.map.RowHandlerErrorHandler;
import org.sfm.map.FieldMapper;
import org.sfm.reflect.*;
import java.lang.reflect.Constructor;
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.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
public class AsmFactory {
private final FactoryClassLoader factoryClassLoader;
private final ConcurrentMap> setterCache = new ConcurrentHashMap>();
private final ConcurrentMap> getterCache = new ConcurrentHashMap>();
private final ConcurrentMap>> instantiatorCache = new ConcurrentHashMap>>();
public AsmFactory(ClassLoader cl) {
factoryClassLoader = new FactoryClassLoader(cl);
}
@SuppressWarnings("unchecked")
public Setter createSetter(final Method m) throws Exception {
Setter setter = (Setter) setterCache.get(m);
if (setter == null) {
final String className = generateClassNameForSetter(m);
final byte[] bytes = generateSetterByteCodes(m, className);
final Class> type = factoryClassLoader.registerClass(className, bytes);
setter = (Setter) type.newInstance();
setterCache.putIfAbsent(m, setter);
}
return setter;
}
@SuppressWarnings("unchecked")
public Getter createGetter(final Method m) throws Exception {
Getter getter = (Getter) getterCache.get(m);
if (getter == null) {
final String className = generateClassNameForGetter(m);
final byte[] bytes = generateGetterByteCodes(m, className);
final Class> type = factoryClassLoader.registerClass(className, bytes);
getter = (Getter) type.newInstance();
getterCache.putIfAbsent(m, getter);
}
return getter;
}
private byte[] generateGetterByteCodes(final Method m, final String className) throws Exception {
final Class> propertyType = m.getReturnType();
if (AsmUtils.primitivesClassAndWrapper.contains(propertyType)) {
return GetterBuilder.createPrimitiveGetter(className, m);
} else {
return GetterBuilder.createObjectGetter(className, m);
}
}
private byte[] generateSetterByteCodes(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 createEmptyArgsInstantiator(final Class source, final Class extends T> target) throws Exception {
InstantiatorKey instantiatorKey = new InstantiatorKey(target, source);
Class extends Instantiator, ?>> instantiatorType = instantiatorCache.get(instantiatorKey);
if (instantiatorType == null) {
final String className = generateClassNameForInstantiator(instantiatorKey);
final byte[] bytes = ConstructorBuilder.createEmptyConstructor(className, source, target);
instantiatorType = (Class extends Instantiator, ?>>) factoryClassLoader.registerClass(className, bytes);
instantiatorCache.putIfAbsent(instantiatorKey, instantiatorType);
}
return (Instantiator) instantiatorType.newInstance();
}
@SuppressWarnings("unchecked")
public Instantiator createInstantiator(final Class> source, final ConstructorDefinition constructorDefinition, final Map> injections) throws Exception {
InstantiatorKey instantiatorKey = new InstantiatorKey(constructorDefinition, injections.keySet(), source);
Class extends Instantiator, ?>> instantiator = instantiatorCache.get(instantiatorKey);
if (instantiator == null) {
final String className = generateClassNameForInstantiator(instantiatorKey);
final byte[] bytes = InstantiatorBuilder.createInstantiator(className, source, constructorDefinition, injections);
instantiator = (Class extends Instantiator, ?>>) factoryClassLoader.registerClass(className, bytes);
instantiatorCache.put(instantiatorKey, instantiator);
}
Map> getterPerName = new HashMap>();
for(Entry> e : injections.entrySet()) {
getterPerName.put(e.getKey().getName(), e.getValue());
}
return (Instantiator) instantiator.getConstructor(Map.class).newInstance(getterPerName);
}
@SuppressWarnings("unchecked")
public JdbcMapper createJdbcMapper(final FieldMapper[] mappers, final FieldMapper[] constructorMappers, final Instantiator instantiator, final Class target, RowHandlerErrorHandler errorHandler, MappingContextFactory mappingContextFactory) throws Exception {
final String className = generateClassNameForJdbcMapper(mappers, constructorMappers, ResultSet.class, target);
final byte[] bytes = JdbcMapperAsmBuilder.dump(className, mappers, constructorMappers, target);
final Class> type = factoryClassLoader.registerClass(className, bytes);
final Constructor> constructor = type.getDeclaredConstructors()[0];
return (JdbcMapper) constructor.newInstance(mappers, constructorMappers, instantiator, errorHandler, mappingContextFactory);
}
private final AtomicLong classNumber = new AtomicLong();
private String generateClassNameForInstantiator(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(replaceArray(key.getSource().getSimpleName()));
sb.append(Long.toHexString(classNumber.getAndIncrement()));
return sb.toString();
}
private String replaceArray(String simpleName) {
return simpleName.replace('[', 's').replace(']', '_');
}
private String generateClassNameForSetter(final Method m) {
return "org.sfm.reflect.asm." + m.getDeclaringClass().getPackage().getName() +
".AsmSetter" + m.getName()
+ replaceArray(m.getDeclaringClass().getSimpleName())
+ replaceArray(m.getParameterTypes()[0].getSimpleName())
;
}
private String generateClassNameForGetter(final Method m) {
return "org.sfm.reflect.asm." + m.getDeclaringClass().getPackage().getName() +
".AsmGetter" + m.getName()
+ replaceArray(m.getDeclaringClass().getSimpleName())
;
}
private String generateClassNameForJdbcMapper(final FieldMapper[] mappers,final FieldMapper[] mappers2, final Class source, final Class target) {
return "org.sfm.reflect.asm." + getPackageName(target) +
".AsmMapper" + replaceArray(source.getSimpleName()) + "2" + replaceArray(target.getSimpleName()) + mappers.length + "_"+ mappers2.length + "_" + classNumber.getAndIncrement();
}
private String getPackageName(Class target) {
Package targetPackage = target.getPackage();
return targetPackage != null ? targetPackage.getName() : ".null";
}
}