se.l4.commons.serialization.internal.reflection.FactoryDefinition Maven / Gradle / Ivy
The newest version!
package se.l4.commons.serialization.internal.reflection;
import java.beans.ConstructorProperties;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.members.ResolvedConstructor;
import com.google.common.base.Defaults;
import com.google.common.base.MoreObjects;
import com.google.common.primitives.Primitives;
import se.l4.commons.serialization.Expose;
import se.l4.commons.serialization.Factory;
import se.l4.commons.serialization.SerializationException;
import se.l4.commons.serialization.SerializerCollection;
/**
* Factory that can be used to create an instance of a certain object.
*
* @author Andreas Holstenson
*
*/
public class FactoryDefinition
{
private final SerializerCollection collection;
final Argument[] arguments;
private final boolean hasSerializedFields;
private final boolean isInjectable;
private final Constructor> raw;
public FactoryDefinition(SerializerCollection collection,
Map fields,
Map nonRenamed,
ResolvedConstructor constructor)
{
this.collection = collection;
List args = new ArrayList<>();
raw = constructor.getRawMember();
ConstructorProperties cp = raw.getAnnotation(ConstructorProperties.class);
String[] names = cp == null ? null : cp.value();
Annotation[][] annotations = raw.getParameterAnnotations();
boolean hasSerializedFields = false;
for(int i=0, n=constructor.getArgumentCount(); i data)
{
if(! hasSerializedFields)
{
return 0;
}
int score = 0;
for(Argument arg : arguments)
{
if(arg instanceof FactoryDefinition.SerializedArgument)
{
if(data.containsKey(((SerializedArgument) arg).name))
{
score++;
}
}
}
return score;
}
/**
* Create a new instance using the given deserialized data. The data
* is only used if this factory has any serialized fields.
*
* @param data
* @return
*/
@SuppressWarnings("unchecked")
public T create(Map data)
{
Object[] args = new Object[arguments.length];
for(int i=0, n=args.length; i data);
}
class SerializedArgument
implements Argument
{
final Class> type;
final String name;
public SerializedArgument(Class> type, String name)
{
this.type = type;
this.name = name;
}
@Override
public Object getValue(Map data)
{
Object value = data.get(name);
if(value == null && type.isPrimitive())
{
return Defaults.defaultValue(type);
}
return value;
}
}
private class InjectedArgument
implements Argument
{
private final Class> type;
private final Annotation[] annotations;
public InjectedArgument(Class> type, Annotation[] annotations)
{
this.type = type;
this.annotations = annotations;
}
@Override
public Object getValue(Map data)
{
return collection.getInstanceFactory()
.create(type, annotations);
}
}
@Override
public String toString()
{
return MoreObjects.toStringHelper(this)
.add("constructor", raw)
.toString();
}
}