package org.simpleflatmapper.reflect;
import org.simpleflatmapper.reflect.asm.AsmInstantiatorDefinitionFactory;
import org.simpleflatmapper.reflect.asm.AsmFactory;
import org.simpleflatmapper.reflect.impl.BuilderInstantiatorDefinitionFactory;
import org.simpleflatmapper.reflect.impl.JavaLangClassMetaFactoryProducer;
import org.simpleflatmapper.reflect.instantiator.InstantiatorDefinitions;
import org.simpleflatmapper.reflect.meta.AliasProvider;
import org.simpleflatmapper.reflect.meta.AliasProviderService;
import org.simpleflatmapper.reflect.meta.ArrayClassMeta;
import org.simpleflatmapper.reflect.meta.ClassMeta;
import org.simpleflatmapper.reflect.meta.FastTupleClassMeta;
import org.simpleflatmapper.reflect.meta.MapClassMeta;
import org.simpleflatmapper.reflect.meta.ObjectClassMeta;
//IFJAVA8_START
import org.simpleflatmapper.reflect.meta.OptionalClassMeta;
//IFJAVA8_END
import org.simpleflatmapper.reflect.meta.TupleClassMeta;
import org.simpleflatmapper.util.Consumer;
import org.simpleflatmapper.util.ProducerServiceLoader;
import org.simpleflatmapper.util.TupleHelper;
import org.simpleflatmapper.util.TypeHelper;
import org.simpleflatmapper.util.UnaryFactory;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.simpleflatmapper.util.Asserts.requireNonNull;
public class ReflectionService {
private static final UnaryFactory<ReflectionService, ClassMeta<?>>[] predefined =
getPredifinedClassMetaFactory();
@SuppressWarnings("unchecked")
private static UnaryFactory<ReflectionService, ClassMeta<?>>[] getPredifinedClassMetaFactory() {
final List<UnaryFactory<ReflectionService, ClassMeta<?>>> list = new ArrayList<UnaryFactory<ReflectionService, ClassMeta<?>>>();
Consumer<UnaryFactory<ReflectionService, ClassMeta<?>>> consumer = new Consumer<UnaryFactory<ReflectionService, ClassMeta<?>>>() {
@Override
public void accept(UnaryFactory<ReflectionService, ClassMeta<?>> reflectionServiceClassMetaUnaryFactory) {
list.add(reflectionServiceClassMetaUnaryFactory);
}
};
new JavaLangClassMetaFactoryProducer().produce(consumer);
ProducerServiceLoader.produceFromServiceLoader(
ClassMetaFactoryProducer.class,
consumer
);
return list.toArray(new UnaryFactory[0]);
}
private final ObjectSetterFactory objectSetterFactory;
private final ObjectGetterFactory objectGetterFactory;
private final InstantiatorFactory instantiatorFactory;
private final AsmFactory asmFactory;
private final AliasProvider aliasProvider;
private final ConcurrentMap<Type, ClassMeta<?>> metaCache = new ConcurrentHashMap<Type, ClassMeta<?>>();
public ReflectionService(final AsmFactory asmFactory) {
this(
new ObjectSetterFactory(asmFactory),
new ObjectGetterFactory(asmFactory),
new InstantiatorFactory(asmFactory),
asmFactory,
AliasProviderService.getAliasProvider()
);
}
private ReflectionService(ObjectSetterFactory objectSetterFactory,
ObjectGetterFactory objectGetterFactory,
InstantiatorFactory instantiatorFactory,
AsmFactory asmFactory,
AliasProvider aliasProvider) {
this.objectSetterFactory = objectSetterFactory;
this.objectGetterFactory = objectGetterFactory;
this.instantiatorFactory = instantiatorFactory;
this.asmFactory = asmFactory;
this.aliasProvider = aliasProvider;
initPredefined();
}
private void initPredefined() {
for (UnaryFactory<ReflectionService, ClassMeta<?>> factory : predefined) {
ClassMeta<?> classMeta = factory.newInstance(this);
metaCache.put(classMeta.getType(), classMeta);
}
}
public ObjectSetterFactory getObjectSetterFactory() {
return objectSetterFactory;
}
public InstantiatorFactory getInstantiatorFactory() {
return instantiatorFactory;
}
public boolean isAsmActivated() {
return asmFactory != null;
}
public AsmFactory getAsmFactory() {
return asmFactory;
}
public <T> ClassMeta<T> getClassMeta(Class<T> target) {
return getClassMeta((Type)target);
}
@SuppressWarnings("unchecked")
public <T> ClassMeta<T> getClassMeta(Type target) {
requireNonNull("target", target);
ClassMeta<T> meta = (ClassMeta<T>) metaCache.get(target);
if (meta == null) {
meta = newClassMeta(target);
requireNonNull("meta", meta);
metaCache.putIfAbsent(target, meta);
}
return meta;
}
@SuppressWarnings("unchecked")
private <T> ClassMeta<T> newClassMeta(Type target) {
Class<T> clazz = TypeHelper.toClass(target);
if (clazz.isArray()) {
return newArrayMeta(clazz);
//IFJAVA8_START
} else if (Optional.class.isAssignableFrom(clazz)) {
return new OptionalClassMeta(target, this);
//IFJAVA8_END
} else if (TupleHelper.isTuple(target)) {
return new TupleClassMeta<T>(target, this);
} else if (isFastTuple(clazz)) {
return new FastTupleClassMeta<T>(target, this);
} else if (Map.class.isAssignableFrom(clazz)) {
return (ClassMeta<T>) newMapMeta(target);
} else if (Collection.class.isAssignableFrom(clazz) || Iterable.class.equals(clazz)) {
return newCollectionMeta(target);
}
return new ObjectClassMeta<T>(target, this);
}
public <T> ClassMeta<T> getClassMetaExtraInstantiator(Type target, Member builderInstantiator) {
return new ObjectClassMeta<T>(target, builderInstantiator, this);
}
private <K, V> ClassMeta<Map<K,V>> newMapMeta(Type type) {
TypeHelper.MapEntryTypes types = TypeHelper.getKeyValueTypeOfMap(type);
return new MapClassMeta<Map<K, V>, K, V>(type, types.getKeyType(), types.getValueType(), this);
}
private <T, E> ClassMeta<T> newArrayMeta(Class<T> clazz) {
return new ArrayClassMeta<T, E>(clazz, clazz.getComponentType(), this);
}
private <T, E> ClassMeta<T> newCollectionMeta(Type type) {
return new ArrayClassMeta<T, E>(type, TypeHelper.getComponentTypeOfListOrArray(type), this);
}
private <T> boolean isFastTuple(Class<T> clazz) {
Class<?> superClass = clazz.getSuperclass();
return superClass != null && "com.boundary.tuple.FastTuple".equals(superClass.getName());
}
public String getColumnName(Method method) {
return aliasProvider.getAliasForMethod(method);
}
public String getColumnName(Field field) {
return aliasProvider.getAliasForField(field);
}
public List<InstantiatorDefinition> extractInstantiator(Type target) throws IOException {
return extractInstantiator(target, null);
}
public List<InstantiatorDefinition> extractInstantiator(Type target, Member extraInstantiator) throws IOException {
List<InstantiatorDefinition> list;
if (!ReflectionInstantiatorDefinitionFactory.areParameterNamePresent(target)) {
try {
list = AsmInstantiatorDefinitionFactory.extractDefinitions(target);
} catch(IOException e) {
// no access to class file
list = ReflectionInstantiatorDefinitionFactory.extractDefinitions(target);
}
} else {
list = ReflectionInstantiatorDefinitionFactory.extractDefinitions(target);
}
if (extraInstantiator == null) {
list.addAll(BuilderInstantiatorDefinitionFactory.extractDefinitions(target));
} else {
if (extraInstantiator instanceof Method && TypeHelper.areEquals(target, ((Method)extraInstantiator).getGenericReturnType())) {
// factory method
list.add(ReflectionInstantiatorDefinitionFactory.definition(((Method)extraInstantiator)));
} else {
final BuilderInstantiatorDefinition builder =
BuilderInstantiatorDefinitionFactory.getDefinitionForBuilder(extraInstantiator, target);
if (builder == null) {
throw new IllegalArgumentException("Could not find any setters or build method on builder " + extraInstantiator);
}
list.add(builder);
}
}
Collections.sort(list, InstantiatorDefinitions.COMPARATOR);
return list;
}
public static ReflectionService newInstance() {
return newInstance(true);
}
private static final AsmFactory _asmFactory = new AsmFactory(Thread.currentThread().getContextClassLoader());
public static ReflectionService newInstance(boolean useAsmGeneration) {
return new ReflectionService(useAsmGeneration && canSeeSetterFromContextClassLoader() ? _asmFactory : null);
}
public static ReflectionService disableAsm() {
return newInstance(false);
}
private static boolean canSeeSetterFromContextClassLoader() {
try {
Class.forName(Setter.class.getName(), false, Thread.currentThread().getContextClassLoader());
return true;
} catch(Exception e) {
return false;
}
}
public ObjectGetterFactory getObjectGetterFactory() {
return objectGetterFactory;
}
public boolean hasAsmFactory() {
return asmFactory != null;
}
public ReflectionService withAliasProvider(AliasProvider aliasProvider) {
return new ReflectionService(
objectSetterFactory,
objectGetterFactory,
instantiatorFactory,
asmFactory,
aliasProvider);
}
public interface ClassMetaFactoryProducer extends ProducerServiceLoader.Producer<UnaryFactory<ReflectionService, ClassMeta<?>>> {
}
}