package genson.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public abstract class BeanCreator
extends genson.
Wrapper<AnnotatedElement
> implements Comparable
<BeanCreator
> {
// The type of object it can create
protected final Class
<?> ofClass
;
protected final Map
<String, BeanCreatorProperty
> parameters
;
protected final Map
<String, BeanCreatorProperty
> paramsAndAliases
;
public BeanCreator
(Class
<?> ofClass, Class
<?> declaringClass, Class
<?> concreteClass,
1.5.0/docs/api/java/lang/String.html">String[] parameterNames,
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] types,
5+0%2Fdocs%2Fapi+Annotation">Annotation[][] anns
) {
this.
ofClass = ofClass
;
this.
parameters =
new LinkedHashMap
<String, BeanCreatorProperty
>(parameterNames.
length);
for (int i =
0; i
< parameterNames.
length; i++
) {
this.
parameters.
put(parameterNames
[i
],
new BeanCreatorProperty
(parameterNames
[i
],
types
[i
], i, anns
[i
], declaringClass, concreteClass,
this));
}
paramsAndAliases =
new LinkedHashMap
<String, BeanCreatorProperty
>();
for (BeanCreatorProperty p : parameters.
values()) {
paramsAndAliases.
put(p.
getName(), p
);
for (1.5.0/docs/api/java/lang/String.html">String alias : p.
aliases()) paramsAndAliases.
put(alias, p
);
}
}
public int contains
(List
<String
> properties
) {
int cnt =
0;
for (1.5.0/docs/api/java/lang/String.html">String prop : properties
)
if (parameters.
containsKey(prop
)) cnt++
;
return cnt
;
}
public int compareTo
(BeanCreator o
) {
int comp = o.
priority() - priority
();
return comp
!= 0
? comp : parameters.
size() - o.
parameters.
size();
}
public abstract 5+0%2Fdocs%2Fapi+Object">Object create
(5+0%2Fdocs%2Fapi+Object">Object...
args);
protected abstract 1.5.0/docs/api/java/lang/String.html">String signature
();
public abstract int priority
();
protected genson.
JsonBindingException couldNotCreate
(1.5.0/docs/api/java/lang/Exception.html">Exception e
) {
return new genson.
JsonBindingException("Could not create bean of type " + ofClass.
getName()
+
" using creator " + signature
(), e
);
}
public Map
<String, BeanCreatorProperty
> getProperties
() {
return new LinkedHashMap
<String, BeanCreatorProperty
>(parameters
);
}
public abstract int getModifiers
();
public static class ConstructorBeanCreator
extends BeanCreator
{
protected final Constructor
<?> constructor
;
public ConstructorBeanCreator
(Class
<?> ofClass, Constructor
<?> constructor,
1.5.0/docs/api/java/lang/String.html">String[] parameterNames,
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] expandedParameterTypes
) {
// We can use the same class, as anyway we don't want to use constructors
super(ofClass, ofClass, ofClass, parameterNames, expandedParameterTypes, constructor.
getParameterAnnotations());
this.
constructor = constructor
;
if (!constructor.
isAccessible()) {
constructor.
setAccessible(true);
}
decorate
(constructor
);
}
public 5+0%2Fdocs%2Fapi+Object">Object create
(5+0%2Fdocs%2Fapi+Object">Object...
args) {
try {
return constructor.
newInstance(args
);
} catch (1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException e
) {
throw couldNotCreate
(e
);
} catch (1.5.0/docs/api/java/lang/InstantiationException.html">InstantiationException e
) {
throw couldNotCreate
(e
);
} catch (1.5.0/docs/api/java/lang/IllegalAccessException.html">IllegalAccessException e
) {
throw couldNotCreate
(e
);
} catch (1.5.0/docs/api/java/lang/reflect/InvocationTargetException.html">InvocationTargetException e
) {
throw couldNotCreate
(e
);
}
}
@
1.5.0/docs/api/java/lang/Override.html">Override
protected 1.5.0/docs/api/java/lang/String.html">String signature
() {
return constructor.
toGenericString();
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int priority
() {
return 50;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int getModifiers
() {
return constructor.
getModifiers();
}
}
public static class MethodBeanCreator
extends BeanCreator
{
protected final 1.5.0/docs/api/java/lang/reflect/Method.html">Method _creator
;
public MethodBeanCreator
(1.5.0/docs/api/java/lang/reflect/Method.html">Method method,
1.5.0/docs/api/java/lang/String.html">String[] parameterNames,
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] expandedParameterTypes, Class
<?> concreteClass
) {
super(method.
getReturnType(), method.
getDeclaringClass(), concreteClass, parameterNames,
expandedParameterTypes, method.
getParameterAnnotations());
if (!1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isStatic(method.
getModifiers()))
throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException("Only static methods can be used as creators!");
this._creator = method
;
if (!_creator.
isAccessible()) {
_creator.
setAccessible(true);
}
decorate
(_creator
);
}
public 5+0%2Fdocs%2Fapi+Object">Object create
(5+0%2Fdocs%2Fapi+Object">Object...
args) {
try {
// we will handle only static method creators
return ofClass.
cast(_creator.
invoke(null, args
));
} catch (1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException e
) {
throw couldNotCreate
(e
);
} catch (1.5.0/docs/api/java/lang/IllegalAccessException.html">IllegalAccessException e
) {
throw couldNotCreate
(e
);
} catch (1.5.0/docs/api/java/lang/reflect/InvocationTargetException.html">InvocationTargetException e
) {
throw couldNotCreate
(e
);
}
}
@
1.5.0/docs/api/java/lang/Override.html">Override
protected 1.5.0/docs/api/java/lang/String.html">String signature
() {
return _creator.
toGenericString();
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int priority
() {
return 100;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int getModifiers
() {
return _creator.
getModifiers();
}
}
public static class BeanCreatorProperty
extends genson.
reflect.
PropertyMutator {
protected final int index
;
protected final 5+0%2Fdocs%2Fapi+Annotation">Annotation[] annotations
;
protected final BeanCreator creator
;
protected final boolean doThrowMutateException
;
protected BeanCreatorProperty
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Type.html">Type type,
int index,
5+0%2Fdocs%2Fapi+Annotation">Annotation[] annotations,
Class
<?> declaringClass, Class
<?> concreteClass, BeanCreator creator
) {
this(name, type, index, annotations, declaringClass, concreteClass, creator,
false);
}
protected BeanCreatorProperty
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Type.html">Type type,
int index,
5+0%2Fdocs%2Fapi+Annotation">Annotation[] annotations,
Class
<?> declaringClass, Class
<?> concreteClass, BeanCreator creator,
boolean doThrowMutateException
) {
super(name, type, declaringClass, concreteClass, annotations, 0
);
this.
index = index
;
this.
annotations = annotations
;
this.
creator = creator
;
this.
doThrowMutateException = doThrowMutateException
;
}
public int getIndex
() {
return index
;
}
public 5+0%2Fdocs%2Fapi+Annotation">Annotation[] getAnnotations
() {
return annotations
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int priority
() {
return -
1000;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public 1.5.0/docs/api/java/lang/String.html">String signature
() {
return new 1.5.0/docs/api/java/lang/StringBuilder.html">StringBuilder(type.
toString()).
append(' ').
append(name
).
append(" from ")
.
append(creator.
signature()).
toString();
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int getModifiers
() {
return creator.
getModifiers();
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public void mutate
(5+0%2Fdocs%2Fapi+Object">Object target,
5+0%2Fdocs%2Fapi+Object">Object value
) {
if (doThrowMutateException
) {
throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException(
"Method mutate should not be called on a mutator of type "
+ getClass
().
getName()
+
", this property exists only as constructor parameter!");
}
}
}
}