package com.owlike.genson.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.
owlike.
genson.
Trilean.
FALSE;
import static com.
owlike.
genson.
Trilean.
TRUE;
import static com.
owlike.
genson.
reflect.
TypeUtil.
*;
import com.owlike.genson.*;
import com.owlike.genson.annotation.JsonCreator;
import com.owlike.genson.reflect.PropertyAccessor.MethodAccessor;
import com.owlike.genson.reflect.PropertyMutator.MethodMutator;
/**
* This class constructs BeanDescriptors for the {@link com.owlike.genson.BeanView BeanView}
* mechanism. This class is mainly intended for internal use. It can be directly used if needed to
* get a BeanDescriptor instance for a BeanView (for example if you want to deserialize into an
* existing object and apply a BeanView). Extending BeanViewDescriptorProvider should be avoided.
*
* @author eugen
*/
public class BeanViewDescriptorProvider
extends BaseBeanDescriptorProvider
{
private Map
<Class
<?>, BeanView
<?>> views
;
private Map
<Class
<?>, BeanDescriptor
<?>> descriptors =
new ConcurrentHashMap
<Class
<?>, BeanDescriptor
<?>>();
public BeanViewDescriptorProvider
(ContextualConverterFactory ctxConverterFactory,
Map
<Class
<?>, BeanView
<?>> views, BeanPropertyFactory propertyFactory,
BeanMutatorAccessorResolver mutatorAccessorResolver,
PropertyNameResolver nameResolver
) {
super(ctxConverterFactory, propertyFactory, mutatorAccessorResolver, nameResolver,
true,
false,
true);
this.
views = views
;
}
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("unchecked")
@
1.5.0/docs/api/java/lang/Override.html">Override
public <T
> BeanDescriptor
<T
> provide
(Class
<T
> ofClass,
1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType, Genson genson
) {
Class
<?> rawClass = getRawClass
(ofType
);
if (!BeanView.
class.
isAssignableFrom(rawClass
))
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException("Expected argument of type "
+ BeanView.
class.
getName() +
" but provided " + rawClass
);
BeanDescriptor
<T
> descriptor =
(BeanDescriptor
<T
>) descriptors.
get(rawClass
);
if (descriptor ==
null) {
Class
<?> parameterizedTypeForBeanView =
getRawClass
(expandType
(BeanView.
class.
getTypeParameters()[0
], ofType
));
if (!ofClass.
isAssignableFrom(parameterizedTypeForBeanView
)) {
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException(
"Expected type for ofClass parameter is " + parameterizedTypeForBeanView
+
" but provided is " + ofClass
);
}
try {
if (!views.
containsKey(rawClass
)) {
Constructor
<BeanView
<T
>> ctr =
(Constructor
<BeanView
<T
>>) rawClass.
getDeclaredConstructor();
if (!ctr.
isAccessible()) ctr.
setAccessible(true);
views.
put(rawClass, ctr.
newInstance());
}
descriptor =
super.
provide(ofClass, ofType, genson
);
descriptors.
put(rawClass, descriptor
);
} catch (1.5.0/docs/api/java/lang/SecurityException.html">SecurityException e
) {
throw couldNotInstantiateBeanView
(ofClass, e
);
} catch (1.5.0/docs/api/java/lang/NoSuchMethodException.html">NoSuchMethodException e
) {
throw couldNotInstantiateBeanView
(ofClass, e
);
} catch (1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException e
) {
throw couldNotInstantiateBeanView
(ofClass, e
);
} catch (1.5.0/docs/api/java/lang/InstantiationException.html">InstantiationException e
) {
throw couldNotInstantiateBeanView
(ofClass, e
);
} catch (1.5.0/docs/api/java/lang/IllegalAccessException.html">IllegalAccessException e
) {
throw couldNotInstantiateBeanView
(ofClass, e
);
} catch (1.5.0/docs/api/java/lang/reflect/InvocationTargetException.html">InvocationTargetException e
) {
throw couldNotInstantiateBeanView
(ofClass, e
);
}
}
return descriptor
;
}
private JsonBindingException couldNotInstantiateBeanView
(Class
<?> beanViewClass,
1.5.0/docs/api/java/lang/Exception.html">Exception e
) {
return new JsonBindingException
("Could not instantiate BeanView "
+ beanViewClass.
getName()
+
", BeanView implementations must have a public no arg constructor.", e
);
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public List
<BeanCreator
> provideBeanCreators
(1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType, Genson genson
) {
List
<BeanCreator
> creators =
new ArrayList
<BeanCreator
>();
for (Class
<?> clazz = getRawClass
(ofType
); clazz
!=
null && !5+0%2Fdocs%2Fapi+Object">Object.
class.
equals(clazz
); clazz =
clazz.
getSuperclass()) {
provideMethodCreators
(clazz, creators, ofType, genson
);
}
1.5.0/docs/api/java/lang/reflect/Type.html">Type viewForType = TypeUtil.
expandType(BeanView.
class.
getTypeParameters()[0
], ofType
);
List
<BeanCreator
> oCtrs =
super.
provideBeanCreators(viewForType, genson
);
creators.
addAll(oCtrs
);
return creators
;
}
public static class BeanViewPropertyFactory
implements BeanPropertyFactory
{
private final Map
<Class
<?>, BeanView
<?>> views
;
public BeanViewPropertyFactory
(Map
<Class
<?>, BeanView
<?>> views
) {
this.
views = views
;
}
public PropertyAccessor createAccessor
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Method.html">Method method,
1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType,
Genson genson
) {
// the target bean must be first (and single) parameter for beanview accessors
BeanView
<?> beanview = views.
get(getRawClass
(ofType
));
if (beanview
!=
null) {
1.5.0/docs/api/java/lang/reflect/Type.html">Type superTypeWithParameter =
TypeUtil.
lookupGenericType(BeanView.
class, beanview.
getClass());
Class
<?> tClass =
getRawClass
(typeOf
(0,
expandType
(superTypeWithParameter, beanview.
getClass())));
1.5.0/docs/api/java/lang/reflect/Type.html">Type type = expandType
(method.
getGenericReturnType(), ofType
);
return new BeanViewPropertyAccessor
(name, method, type, beanview, tClass
);
} else return null;
}
public PropertyMutator createMutator
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Method.html">Method method,
1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType, Genson genson
) {
// the target bean must be second parameter for beanview mutators
BeanView
<?> beanview = views.
get(getRawClass
(ofType
));
if (beanview
!=
null) {
1.5.0/docs/api/java/lang/reflect/Type.html">Type superTypeWithParameter =
TypeUtil.
lookupGenericType(BeanView.
class, beanview.
getClass());
Class
<?> tClass =
getRawClass
(typeOf
(0,
expandType
(superTypeWithParameter, beanview.
getClass())));
1.5.0/docs/api/java/lang/reflect/Type.html">Type type = expandType
(method.
getGenericParameterTypes()[0
], ofType
);
return new BeanViewPropertyMutator
(name, method, type, beanview, tClass
);
} else return null;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public PropertyAccessor createAccessor
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Field.html">Field field,
1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType,
Genson genson
) {
return null;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public BeanCreator createCreator
(1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType, Constructor
<?> ctr,
1.5.0/docs/api/java/lang/String.html">String[] resolvedNames, Genson genson
) {
return null;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public BeanCreator createCreator
(1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType,
1.5.0/docs/api/java/lang/reflect/Method.html">Method method,
1.5.0/docs/api/java/lang/String.html">String[] resolvedNames, Genson genson
) {
return null;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public PropertyMutator createMutator
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Field.html">Field field,
1.5.0/docs/api/java/lang/reflect/Type.html">Type ofType,
Genson genson
) {
return null;
}
}
public static class BeanViewMutatorAccessorResolver
implements BeanMutatorAccessorResolver
{
public Trilean isAccessor
(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class
<?> baseClass
) {
return FALSE
;
}
public Trilean isAccessor
(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class
<?> baseClass
) {
1.5.0/docs/api/java/lang/reflect/Type.html">Type expectedType = TypeUtil.
lookupGenericType(BeanView.
class, baseClass
);
expectedType = TypeUtil.
expandType(expectedType, baseClass
);
expectedType = TypeUtil.
typeOf(0, expectedType
);
int modifiers = method.
getModifiers();
return Trilean.
valueOf((method.
getName().
startsWith("get") ||
(method.
getName()
.
startsWith("is") && (TypeUtil.
match(method.
getGenericReturnType(),
1.5.0/docs/api/java/lang/Boolean.html">Boolean.
class,
false) ||
boolean.
class.
equals(method.
getReturnType()))))
&& TypeUtil.
match(expectedType, method.
getGenericParameterTypes()[0
],
false)
&& 1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isPublic(modifiers
)
&& !1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isAbstract(modifiers
)
&& !1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isNative(modifiers
));
}
public Trilean isCreator
(Constructor
<?> constructor, Class
<?> baseClass
) {
int modifier = constructor.
getModifiers();
return Trilean.
valueOf(1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isPublic(modifier
)
||
!(1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isPrivate(modifier
) ||
1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isProtected(modifier
)));
}
public Trilean isCreator
(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class
<?> baseClass
) {
if (method.
getAnnotation(JsonCreator.
class) !=
null) {
if (1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isStatic(method.
getModifiers())) return TRUE
;
throw new JsonBindingException
("Method " + method.
toGenericString()
+
" annotated with @Creator must be static!");
}
return FALSE
;
}
public Trilean isMutator
(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class
<?> baseClass
) {
return FALSE
;
}
public Trilean isMutator
(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class
<?> baseClass
) {
1.5.0/docs/api/java/lang/reflect/Type.html">Type expectedType = TypeUtil.
lookupGenericType(BeanView.
class, baseClass
);
expectedType = TypeUtil.
expandType(expectedType, baseClass
);
expectedType = TypeUtil.
typeOf(0, expectedType
);
int modifiers = method.
getModifiers();
return Trilean.
valueOf(method.
getName().
startsWith("set")
&& void.
class.
equals(method.
getReturnType())
&& method.
getGenericParameterTypes().
length == 2
&& TypeUtil.
match(expectedType, method.
getGenericParameterTypes()[1
],
false)
&& 1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isPublic(modifiers
) && !1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isAbstract(modifiers
)
&& !1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.
isNative(modifiers
));
}
}
private static class BeanViewPropertyAccessor
extends MethodAccessor
{
private final BeanView
<?> _view
;
public BeanViewPropertyAccessor
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Method.html">Method getter,
1.5.0/docs/api/java/lang/reflect/Type.html">Type type, BeanView
<?> target,
Class
<?> tClass
) {
super(name, getter, type, tClass
);
this._view = target
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public 5+0%2Fdocs%2Fapi+Object">Object access
(5+0%2Fdocs%2Fapi+Object">Object target
) {
try {
return _getter.
invoke(_view, target
);
} catch (1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException e
) {
throw couldNotAccess
(e
);
} catch (1.5.0/docs/api/java/lang/IllegalAccessException.html">IllegalAccessException e
) {
throw couldNotAccess
(e
);
} catch (1.5.0/docs/api/java/lang/reflect/InvocationTargetException.html">InvocationTargetException e
) {
throw couldNotAccess
(e
);
}
}
}
private static class BeanViewPropertyMutator
extends MethodMutator
{
private final BeanView
<?> _view
;
public BeanViewPropertyMutator
(1.5.0/docs/api/java/lang/String.html">String name,
1.5.0/docs/api/java/lang/reflect/Method.html">Method setter,
1.5.0/docs/api/java/lang/reflect/Type.html">Type type, BeanView
<?> target,
Class
<?> tClass
) {
super(name, setter, type, tClass
);
this._view = target
;
}
@
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
) {
try {
_setter.
invoke(_view, value, target
);
} catch (1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException e
) {
throw couldNotMutate
(e
);
} catch (1.5.0/docs/api/java/lang/IllegalAccessException.html">IllegalAccessException e
) {
throw couldNotMutate
(e
);
} catch (1.5.0/docs/api/java/lang/reflect/InvocationTargetException.html">InvocationTargetException e
) {
throw couldNotMutate
(e
);
}
}
}
}