package net.contextfw.web.commons.cloud.internal.serializer;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import net.contextfw.web.application.WebApplicationException;
import net.contextfw.web.application.scope.Provided;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;
public class DependencyMapper extends MapperWrapper {
private static final String RAWTYPES = "rawtypes";
private final Injector injector;
private ClassLoader classLoader;
@Override
public SingleValueConverter getConverterFromItemType(
String fieldName,
@SuppressWarnings(RAWTYPES)
Class type,
@SuppressWarnings(RAWTYPES)
Class definedIn) {
try {
Field field = definedIn.getDeclaredField(fieldName);
if (Provider.class.isAssignableFrom(type)) {
if (field.getGenericType() instanceof ParameterizedType) {
ParameterizedType genericType = (ParameterizedType) field.getGenericType();
Type actualType = genericType.getActualTypeArguments()[0];
if (actualType instanceof Class) {
return new ProviderConverter(injector,
(Class<?>) genericType.getActualTypeArguments()[0], classLoader);
} else if (actualType instanceof TypeVariable) {
return new ProviderConverter(injector, type, classLoader);
}
}
} else if (field.isAnnotationPresent(Provided.class)) {
return new ProvidedConverter(injector, field.getType(), classLoader);
}
} catch (SecurityException e) {
throw new WebApplicationException(e);
} catch (NoSuchFieldException e) {
throw new WebApplicationException(e);
}
return super.getConverterFromItemType(fieldName, type, definedIn);
}
@Override
public SingleValueConverter getConverterFromAttribute(
@SuppressWarnings(RAWTYPES)
Class definedIn,
String attribute,
@SuppressWarnings(RAWTYPES)
Class type) {
try {
Field field = definedIn.getDeclaredField(attribute);
if (field.isAnnotationPresent(Provided.class)) {
return new ProvidedConverter(injector, type, classLoader);
}
} catch (SecurityException e) {
throw new WebApplicationException(e);
} catch (NoSuchFieldException e) {
throw new WebApplicationException(e);
}
if (Provider.class.isAssignableFrom(type)) {
return new ProviderConverter(injector, null, classLoader);
} else {
return super.getConverterFromAttribute(definedIn, attribute, type);
}
}
public DependencyMapper(Mapper wrapped,
Injector injector,
ClassLoader classLoader) {
super(wrapped);
this.injector = injector;
this.classLoader = classLoader;
}
}