com.owlike.genson.convert.BasicConvertersFactory Maven / Gradle / Ivy
package com.owlike.genson.convert;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.owlike.genson.Context;
import com.owlike.genson.Converter;
import com.owlike.genson.Deserializer;
import com.owlike.genson.Factory;
import com.owlike.genson.Genson;
import com.owlike.genson.Operations;
import com.owlike.genson.Serializer;
import com.owlike.genson.Wrapper;
import com.owlike.genson.reflect.BeanDescriptorProvider;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
/**
* This is the base factory that will create converters based on the default ones and on custom
* Serializer, Deserializer and Converter. But it also uses factories (default and custom) and
* {@link com.owlike.genson.reflect.BeanDescriptorProvider BeanDescriptorProvider} that is
* responsible of creating bean converters.
*
* When you ask for a Converter it will
*
*
* - Lookup in the registered Serializers for one that is parameterized with the current type, if
* found we finished (it takes the first one, so the order matters).
* - Else we will try the factories by searching the ones that can create and instance of
* Serializer<CurrentType> (again the order is very important). We continue while they return
* null.
* - If no factory could create an instance we will use BeanDescriptorProvider.
*
*
* - We apply all the same logic a second time for Deserializer.
* - If they are both an instance of Converter then we return one of them
* - Otherwise we will wrap both into a Converter.
*
*
* Note that the create method from the registered factories will only be called if the type with
* which they are parameterized is assignable from the current type. For example, if we look for a
* serializer of Integer then Factory<Converter<Integer>> and Factory<Serializer<Object>> match
* both, the first registered will be used.
*
* @author eugen
*/
public class BasicConvertersFactory implements Factory> {
private final Map> serializersMap;
private final Map> deserializersMap;
private final List> factories;
private final BeanDescriptorProvider beanDescriptorProvider;
public BasicConvertersFactory(Map> serializersMap,
Map> deserializersMap, List> factories,
BeanDescriptorProvider beanDescriptorProvider) {
this.serializersMap = serializersMap;
this.deserializersMap = deserializersMap;
this.factories = factories;
this.beanDescriptorProvider = beanDescriptorProvider;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public Converter create(Type type, Genson genson) {
Converter converter = null;
Serializer serializer = provide(Serializer.class, type, serializersMap, genson);
Deserializer deserializer = provide(Deserializer.class, type, deserializersMap, genson);
if (serializer instanceof Converter && deserializer instanceof Converter) {
converter = (Converter) deserializer;
} else {
converter = new DelegatedConverter(serializer, deserializer);
}
return converter;
}
@SuppressWarnings("unchecked")
protected T provide(Class forClass, Type withParameterType,
Map fromTypeMap, Genson genson) {
if (fromTypeMap.containsKey(withParameterType)) return fromTypeMap.get(withParameterType);
Type wrappedParameterType = withParameterType;
if (withParameterType instanceof Class && ((Class) withParameterType).isPrimitive())
wrappedParameterType = TypeUtil.wrap((Class) withParameterType);
for (Iterator> it = factories.iterator(); it.hasNext(); ) {
Factory factory = it.next();
Object object;
Type factoryType = TypeUtil.lookupGenericType(Factory.class, factory.getClass());
factoryType = TypeUtil.expandType(factoryType, factory.getClass());
// it is a parameterized type and we want the parameter corresponding to Serializer from
// Factory>
factoryType = TypeUtil.typeOf(0, factoryType);
Type factoryParameter = TypeUtil.typeOf(0, factoryType);
if (forClass.isAssignableFrom(TypeUtil.getRawClass(factoryType))
&& TypeUtil.match(wrappedParameterType, factoryParameter, false)
&& (object = factory.create(withParameterType, genson)) != null) {
return forClass.cast(object);
}
}
return (T) beanDescriptorProvider.provide(TypeUtil.getRawClass(withParameterType),
withParameterType, genson);
}
private class DelegatedConverter extends Wrapper> implements Converter {
private final Serializer serializer;
private final Deserializer deserializer;
public DelegatedConverter(Serializer serializer, Deserializer deserializer) {
this.serializer = serializer;
this.deserializer = deserializer;
}
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
serializer.serialize(obj, writer, ctx);
}
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
return deserializer.deserialize(reader, ctx);
}
@Override
public A getAnnotation(Class aClass) {
A a = null;
if (serializer != null) a = toAnnotatedElement(serializer).getAnnotation(aClass);
if (deserializer != null && a == null)
a = toAnnotatedElement(deserializer).getAnnotation(aClass);
return a;
}
@Override
public Annotation[] getAnnotations() {
if (serializer != null && deserializer != null)
return Operations.union(Annotation[].class, toAnnotatedElement(serializer)
.getAnnotations(), toAnnotatedElement(deserializer).getAnnotations());
if (serializer != null) return toAnnotatedElement(serializer).getAnnotations();
if (deserializer != null) return toAnnotatedElement(deserializer).getAnnotations();
return new Annotation[0];
}
@Override
public Annotation[] getDeclaredAnnotations() {
if (serializer != null && deserializer != null)
return Operations.union(Annotation[].class, toAnnotatedElement(serializer)
.getDeclaredAnnotations(), toAnnotatedElement(deserializer)
.getDeclaredAnnotations());
if (serializer != null) return toAnnotatedElement(serializer).getDeclaredAnnotations();
if (deserializer != null)
return toAnnotatedElement(deserializer).getDeclaredAnnotations();
return new Annotation[0];
}
@Override
public boolean isAnnotationPresent(Class annotationClass) {
if (serializer != null)
return toAnnotatedElement(serializer).isAnnotationPresent(annotationClass);
if (deserializer != null)
return toAnnotatedElement(deserializer).isAnnotationPresent(annotationClass);
return false;
}
}
}