package com.owlike.genson.reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.owlike.genson.Operations;
/**
* This class provides utilities to work with java Types. Its main goal is to provide tools for working with generic
* types.
*
* @author eugen
*/
/*
* TODO ExpandedType do we need a reference to an original type?=> Not nice to provide 2
* implementations for ParameterizedType...
*/
public final class TypeUtil
{
private final static Map
<Class
<?>, Class
<?>> _wrappedPrimitives =
new HashMap
<Class
<?>, Class
<?>>();
static {
_wrappedPrimitives.
put(int.
class,
1.5.0/docs/api/java/lang/Integer.html">Integer.
class);
_wrappedPrimitives.
put(double.
class,
1.5.0/docs/api/java/lang/Double.html">Double.
class);
_wrappedPrimitives.
put(long.
class,
1.5.0/docs/api/java/lang/Long.html">Long.
class);
_wrappedPrimitives.
put(float.
class,
1.5.0/docs/api/java/lang/Float.html">Float.
class);
_wrappedPrimitives.
put(short.
class,
1.5.0/docs/api/java/lang/Short.html">Short.
class);
_wrappedPrimitives.
put(boolean.
class,
1.5.0/docs/api/java/lang/Boolean.html">Boolean.
class);
_wrappedPrimitives.
put(char.
class,
1.5.0/docs/api/java/lang/Character.html">Character.
class);
_wrappedPrimitives.
put(byte.
class,
1.5.0/docs/api/java/lang/Byte.html">Byte.
class);
_wrappedPrimitives.
put(void.
class,
1.5.0/docs/api/java/lang/Void.html">Void.
class);
}
private final static Map
<TypeAndRootClassKey, Type
> _cache =
new ConcurrentHashMap
<TypeUtil.
TypeAndRootClassKey, Type
>(
32
);
public final static Class
<?> wrap
(Class
<?> clazz
) {
Class
<?> wrappedClass = _wrappedPrimitives.
get(clazz
);
return wrappedClass ==
null ? clazz : wrappedClass
;
}
private final static ThreadLocal
<Map
<Type, Type
>> _circularExpandedType =
new ThreadLocal
<Map
<Type, Type
>>();
/**
* Expands type in the type rootType to Class, ParameterizedType or GenericArrayType. Useful for generic types.
* rootType is used to get the specialization information for expansion.
*/
public final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type expandType
(final 1.5.0/docs/api/java/lang/reflect/Type.html">Type type,
final 1.5.0/docs/api/java/lang/reflect/Type.html">Type rootType
) {
/* TODO in case where it is a class we should maybe still try to expand it using rootType information?
* for example if I want to expand Map in rootType context Map<String, Integer>, actually this does not work.
* However such modification should be done with more care. Impacts on typeOf and lookUpGenericType, probably others too.
*/
if (type
instanceof ExpandedType || type
instanceof 1.5.0/docs/api/java/lang/Class.html">Class)
return type
;
Map
<Type, Type
> circularTypes = _circularExpandedType.
get();
if (circularTypes ==
null) {
circularTypes =
new HashMap
<Type, Type
>();
_circularExpandedType.
set(circularTypes
);
}
// this allows to handle cyclic generic types (types that refer to them self)
if (circularTypes.
containsKey(type
)) {
return circularTypes.
get(type
);
} else {
try {
circularTypes.
put(type, getRawClass
(type
));
TypeAndRootClassKey key =
new TypeAndRootClassKey
(type, rootType
);
1.5.0/docs/api/java/lang/reflect/Type.html">Type expandedType = _cache.
get(key
);
if (expandedType ==
null) {
if (type
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) {
1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType pType =
(1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) type
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] args = pType.
getActualTypeArguments();
int len = args.
length;
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] expandedArgs =
new 1.5.0/docs/api/java/lang/reflect/Type.html">Type[len
];
for (int i =
0; i
< len
; i++
) {
expandedArgs
[i
] = expandType
(args
[i
], rootType
);
}
expandedType =
new ExpandedParameterizedType
(pType, getRawClass
(rootType
), expandedArgs
);
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/TypeVariable.html">TypeVariable) {
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("unchecked")
TypeVariable
<GenericDeclaration
> tvType =
(TypeVariable
<GenericDeclaration
>) type
;
if (rootType
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) {
1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType rootPType =
(1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) rootType
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] typeArgs = rootPType.
getActualTypeArguments();
1.5.0/docs/api/java/lang/String.html">String typeName = tvType.
getName();
int idx =
0;
for (TypeVariable
<?> parameter : genericDeclarationToClass
(tvType.
getGenericDeclaration())
.
getTypeParameters()) {
if (typeName.
equals(parameter.
getName())) {
expandedType = typeArgs
[idx
];
break;
}
idx++
;
}
} else
expandedType = resolveTypeVariable
(tvType, getRawClass
(rootType
));
if (type == expandedType
)
expandedType = expandType
(tvType.
getBounds()[0
], rootType
);
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) {
1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType genArrType =
(1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) type
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type cType = expandType
(genArrType.
getGenericComponentType(), rootType
);
if (genArrType.
getGenericComponentType() == cType
)
cType =
5+0%2Fdocs%2Fapi+Object">Object.
class;
expandedType =
new ExpandedGenericArrayType
(genArrType, cType, getRawClass
(rootType
));
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) {
1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType wType =
(1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) type
;
// let's expand wildcards to their upper bound or object if no upper bound
// defined
// it will simplify things to accept only one upper bound and ignore lower
// bounds
// as it is equivalent to Object.
expandedType = wType.
getUpperBounds().
length > 0
? expandType
(wType.
getUpperBounds()[0
],
rootType
) :
5+0%2Fdocs%2Fapi+Object">Object.
class;
}
if (expandedType ==
null)
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException("Type " + type +
" not supported for expansion!");
_cache.
put(key, expandedType
);
}
return expandedType
;
} finally {
circularTypes.
remove(type
);
}
}
}
/**
* Searches for ofClass in the inherited classes and interfaces of inClass. If ofClass has been found in the super
* classes/interfaces of inClass, then the generic type corresponding to inClass and its TypeVariables is returned,
* otherwise null. For example :
* <p/>
* <pre>
* abstract class MyClass implements Serializer<Number> {
*
* }
*
* // type value will be the parameterized type Serializer<Number>
* Type type = lookupGenericType(Serializer.class, MyClass.class);
* </pre>
*/
public final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type lookupGenericType
(Class
<?> ofClass, Class
<?> inClass
) {
if (ofClass ==
null || inClass ==
null ||
!ofClass.
isAssignableFrom(inClass
))
return null;
if (ofClass.
equals(inClass
))
return inClass
;
if (ofClass.
isInterface()) {
// lets look if the interface is directly implemented by fromClass
Class
<?>[] interfaces = inClass.
getInterfaces();
for (int i =
0; i
< interfaces.
length; i++
) {
// do they match?
if (ofClass.
equals(interfaces
[i
])) {
return inClass.
getGenericInterfaces()[i
];
} else {
1.5.0/docs/api/java/lang/reflect/Type.html">Type superType = lookupGenericType
(ofClass, interfaces
[i
]);
if (superType
!=
null)
return superType
;
}
}
}
// ok it's not one of the directly implemented interfaces, lets try extended class
Class
<?> superClass = inClass.
getSuperclass();
if (ofClass.
equals(superClass
))
return inClass.
getGenericSuperclass();
return lookupGenericType
(ofClass, inClass.
getSuperclass());
}
public final static Class
<?> getRawClass
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type
) {
if (type
instanceof Class
<?>)
return (Class
<?>) type
;
else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) {
1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType pType =
(1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) type
;
return (Class
<?>) pType.
getRawType();
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) {
1.5.0/docs/api/java/lang/reflect/Type.html">Type componentType =
((1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) type
).
getGenericComponentType();
return 5+0%2Fdocs%2Fapi+Array">Array.
newInstance(getRawClass
(componentType
), 0
).
getClass();
} else
return getRawClass
(expand
(type,
null));
}
/**
* Returns the type of this Collection or Array.
*
* @throws IllegalArgumentException if type is not a Collection, not a generic array and not a primitive array.
*/
public final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type getCollectionType
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type
) {
if (type
instanceof 1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) {
return ((1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) type
).
getGenericComponentType();
} else if (type
instanceof Class
<?>) {
Class
<?> clazz =
(Class
<?>) type
;
if (clazz.
isArray())
return clazz.
getComponentType();
else if (1.5.0/docs/api/java/util/Collection.html">Collection.
class.
isAssignableFrom(clazz
)) {
return 5+0%2Fdocs%2Fapi+Object">Object.
class;
}
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType && 1.5.0/docs/api/java/util/Collection.html">Collection.
class.
isAssignableFrom(getRawClass
(type
))) {
return typeOf
(0, type
);
}
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException(
"Could not extract parametrized type, are you sure it is a Collection or an Array?");
}
// protected for testing.
final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type expand
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type, Class
<?> inClass
) {
1.5.0/docs/api/java/lang/reflect/Type.html">Type expandedType =
null;
if (type
instanceof 1.5.0/docs/api/java/lang/reflect/TypeVariable.html">TypeVariable) {
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("unchecked")
// for the moment we assume it is a class, we can later handle ctr and methods
TypeVariable
<GenericDeclaration
> tvType =
(TypeVariable
<GenericDeclaration
>) type
;
if (inClass ==
null)
inClass = genericDeclarationToClass
(tvType.
getGenericDeclaration());
expandedType = resolveTypeVariable
(tvType, inClass
);
if (type.
equals(expandedType
))
expandedType = tvType.
getBounds()[0
];
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) {
1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType wType =
(1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) type
;
expandedType = wType.
getUpperBounds().
length > 0
? expand
(wType.
getUpperBounds()[0
], inClass
)
:
5+0%2Fdocs%2Fapi+Object">Object.
class;
} else
return type
;
return expandedType ==
null || type.
equals(expandedType
) ? 5+0%2Fdocs%2Fapi+Object">Object.
class : expandedType
;
}
/**
* Searches for the typevariable definition in the inClass hierarchy.
*
* @param type
* @param inClass
* @return the resolved type or type if unable to resolve it.
*/
public final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type resolveTypeVariable
(TypeVariable
<? extends GenericDeclaration
> type, Class
<?> inClass
) {
return resolveTypeVariable
(type, genericDeclarationToClass
(type.
getGenericDeclaration()), inClass
);
}
private final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type resolveTypeVariable
(TypeVariable
<? extends GenericDeclaration
> type,
Class
<?> declaringClass, Class
<?> inClass
) {
if (inClass ==
null)
return null;
Class
<?> superClass =
null;
1.5.0/docs/api/java/lang/reflect/Type.html">Type resolvedType =
null;
1.5.0/docs/api/java/lang/reflect/Type.html">Type genericSuperClass =
null;
if (!declaringClass.
equals(inClass
)) {
if (declaringClass.
isInterface()) {
// the declaringClass is an interface
Class
<?>[] interfaces = inClass.
getInterfaces();
for (int i =
0; i
< interfaces.
length && resolvedType ==
null; i++
) {
superClass = interfaces
[i
];
resolvedType = resolveTypeVariable
(type, declaringClass, superClass
);
genericSuperClass = inClass.
getGenericInterfaces()[i
];
}
}
if (resolvedType ==
null) {
superClass = inClass.
getSuperclass();
resolvedType = resolveTypeVariable
(type, declaringClass, superClass
);
genericSuperClass = inClass.
getGenericSuperclass();
}
} else {
resolvedType = type
;
genericSuperClass = superClass = inClass
;
}
if (resolvedType
!=
null) {
// if its another type this means we have finished
if (resolvedType
instanceof TypeVariable
<?>) {
type =
(TypeVariable
<?>) resolvedType
;
TypeVariable
<?>[] parameters = superClass.
getTypeParameters();
int positionInClass =
0;
for (; positionInClass
< parameters.
length && !type.
equals(parameters
[positionInClass
]); positionInClass++
) {
}
// we located the position of the typevariable in the superclass
if (positionInClass
< parameters.
length) {
// let's look if we have type specialization information in the current class
if (genericSuperClass
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) {
1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType pGenericType =
(1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) genericSuperClass
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] args = pGenericType.
getActualTypeArguments();
return positionInClass
< args.
length ? args
[positionInClass
] :
null;
}
}
// we didnt find typevariable specialization in the class, so it's the best we can
// do, lets return the resolvedType...
}
}
return resolvedType
;
}
/**
* Deep comparison between type and oType. If parameter strictMatch is true, then type and oType will be strictly
* compared otherwise this method checks whether oType is assignable from type.
*/
public final static boolean match
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type,
1.5.0/docs/api/java/lang/reflect/Type.html">Type oType,
boolean strictMatch
) {
if (type ==
null || oType ==
null)
return type ==
null && oType ==
null;
Class
<?> clazz = getRawClass
(type
);
Class
<?> oClazz = getRawClass
(oType
);
boolean match = strictMatch
? oClazz.
equals(clazz
) : oClazz.
isAssignableFrom(clazz
);
if (5+0%2Fdocs%2Fapi+Object">Object.
class.
equals(oClazz
) && !strictMatch
)
return match
;
if (clazz.
isArray() && !oClazz.
isArray())
return match
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] types = getTypes
(type
);
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] oTypes = getTypes
(oType
);
match = match
&& (types.
length == oTypes.
length || types.
length == 0
);
for (int i =
0; i
< types.
length && match
; i++
)
match = match
(types
[i
], oTypes
[i
], strictMatch
);
return match
;
}
/**
* Convenient method that returns the type of the parameter at position parameterIdx in the type fromType.
*
* @throws UnsupportedOperationException thrown if fromType is not a Class nor a ParameterizedType.
*/
public final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type typeOf
(int parameterIdx,
1.5.0/docs/api/java/lang/reflect/Type.html">Type fromType
) {
if (fromType
instanceof Class
<?>) {
Class
<?> tClass =
(Class
<?>) fromType
;
TypeVariable
<?>[] tvs = tClass.
getTypeParameters();
if (tvs.
length > parameterIdx
)
return expandType
(tvs
[parameterIdx
], fromType
);
} else if (fromType
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) {
1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType pType =
(1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) fromType
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] ts = pType.
getActualTypeArguments();
if (ts.
length > parameterIdx
)
return ts
[parameterIdx
];
}
throw new 1.5.0/docs/api/java/lang/UnsupportedOperationException.html">UnsupportedOperationException("Couldn't find parameter at " + parameterIdx +
" from type " + fromType
+
" , you should first locate the parameterized type, expand it and then use typeOf.");
}
private static Class
<?> genericDeclarationToClass
(1.5.0/docs/api/java/lang/reflect/GenericDeclaration.html">GenericDeclaration declaration
) {
if (declaration
instanceof 1.5.0/docs/api/java/lang/Class.html">Class)
return (Class
<?>) declaration
;
if (declaration
instanceof 1.5.0/docs/api/java/lang/reflect/Method.html">Method)
return ((1.5.0/docs/api/java/lang/reflect/Method.html">Method) declaration
).
getDeclaringClass();
if (declaration
instanceof 1.5.0/docs/api/java/lang/reflect/Constructor.html">Constructor)
return ((Constructor
<?>) declaration
).
getDeclaringClass();
throw new 1.5.0/docs/api/java/lang/UnsupportedOperationException.html">UnsupportedOperationException();
}
private final static 1.5.0/docs/api/java/lang/reflect/Type.html">Type[] getTypes
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type
) {
if (type
instanceof 1.5.0/docs/api/java/lang/Class.html">Class) {
Class
<?> tClass =
(Class
<?>) type
;
if (tClass.
isArray())
return new 1.5.0/docs/api/java/lang/reflect/Type.html">Type[]{tClass.
getComponentType()};
else {
TypeVariable
<?>[] tvs =
((Class
<?>) type
).
getTypeParameters();
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] types =
new 1.5.0/docs/api/java/lang/reflect/Type.html">Type[tvs.
length];
int i =
0;
for (TypeVariable
<?> tv : tvs
) {
types
[i++
] = tv.
getBounds()[0
];
}
return types
;
}
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) {
return ((1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType) type
).
getActualTypeArguments();
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) {
return new 1.5.0/docs/api/java/lang/reflect/Type.html">Type[]{((1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType) type
).
getGenericComponentType()};
} else if (type
instanceof 1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) {
return Operations.
union(1.5.0/docs/api/java/lang/reflect/Type.html">Type[].
class,
((1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) type
).
getUpperBounds(),
((1.5.0/docs/api/java/lang/reflect/WildcardType.html">WildcardType) type
).
getLowerBounds());
} else if (type
instanceof TypeVariable
<?>) {
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("unchecked")
TypeVariable
<Class
<?>> tvType =
(TypeVariable
<Class
<?>>) type
;
1.5.0/docs/api/java/lang/reflect/Type.html">Type resolvedType = resolveTypeVariable
(tvType, tvType.
getGenericDeclaration());
return tvType.
equals(resolvedType
) ? tvType.
getBounds() :
new 1.5.0/docs/api/java/lang/reflect/Type.html">Type[]{resolvedType
};
} else
return new 1.5.0/docs/api/java/lang/reflect/Type.html">Type[0
];
}
/*
* ExpandedType must implement hashcode and equals using only the original type
* The root class is not significant here as a type expanded in different root classes can yield to the same expanded type.
* Very important, hashcode and equals must also be implemented in subclasses and also use those from ExpandedType.
*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private static abstract class ExpandedType
<T
extends Type
> {
protected final T originalType
;
protected final Class
<?> rootClass
;
private final int _hash
;
private ExpandedType
(T originalType, Class
<?> rootClass
) {
if (originalType ==
null || rootClass ==
null)
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException("Null arg not allowed!");
this.
originalType = originalType
;
this.
rootClass = rootClass
;
final int prime =
31;
int result =
1;
_hash = prime
* result +
((originalType ==
null) ? 0 : originalType.
hashCode());
}
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("unused")
public T getOriginalType
() {
return originalType
;
}
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("unused")
public Class
<?> getRootClass
() {
return rootClass
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int hashCode
() {
return _hash
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public boolean equals
(5+0%2Fdocs%2Fapi+Object">Object obj
) {
if (this == obj
)
return true;
if (obj ==
null)
return false;
if (getClass
() != obj.
getClass())
return false;
@
1.5.0/docs/api/java/lang/SuppressWarnings.html">SuppressWarnings("rawtypes")
ExpandedType other =
(ExpandedType
) obj
;
if (originalType ==
null) {
if (other.
originalType !=
null)
return false;
} else if (!originalType.
equals(other.
originalType))
return false;
return true;
}
}
/*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private final static class ExpandedGenericArrayType
extends ExpandedType
<GenericArrayType
> implements
1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType {
private final 1.5.0/docs/api/java/lang/reflect/Type.html">Type componentType
;
private final int _hash
;
public ExpandedGenericArrayType
(1.5.0/docs/api/java/lang/reflect/GenericArrayType.html">GenericArrayType originalType,
1.5.0/docs/api/java/lang/reflect/Type.html">Type componentType, Class
<?> rootClass
) {
super(originalType, rootClass
);
if (componentType ==
null)
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException("Null arg not allowed!");
this.
componentType = componentType
;
final int prime =
31;
int result =
super.
hashCode();
_hash = prime
* result +
((componentType ==
null) ? 0 : componentType.
hashCode());
}
public 1.5.0/docs/api/java/lang/reflect/Type.html">Type getGenericComponentType
() {
return componentType
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int hashCode
() {
return _hash
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public boolean equals
(5+0%2Fdocs%2Fapi+Object">Object obj
) {
if (this == obj
)
return true;
if (!super.
equals(obj
))
return false;
if (getClass
() != obj.
getClass())
return false;
ExpandedGenericArrayType other =
(ExpandedGenericArrayType
) obj
;
if (componentType ==
null) {
if (other.
componentType !=
null)
return false;
} else if (!componentType.
equals(other.
componentType))
return false;
return true;
}
}
/*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private final static class ExpandedParameterizedType
extends ExpandedType
<ParameterizedType
> implements
1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType {
private final 1.5.0/docs/api/java/lang/reflect/Type.html">Type[] typeArgs
;
private final int _hash
;
public ExpandedParameterizedType
(1.5.0/docs/api/java/lang/reflect/ParameterizedType.html">ParameterizedType originalType, Class
<?> rootClass,
1.5.0/docs/api/java/lang/reflect/Type.html">Type[] typeArgs
) {
super(originalType, rootClass
);
if (typeArgs ==
null)
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException("Null arg not allowed!");
this.
typeArgs = typeArgs
;
final int prime =
31;
int result =
super.
hashCode();
_hash = prime
* result +
1.5.0/docs/api/java/util/Arrays.html">Arrays.
hashCode(typeArgs
);
}
public 1.5.0/docs/api/java/lang/reflect/Type.html">Type[] getActualTypeArguments
() {
return typeArgs
;
}
public 1.5.0/docs/api/java/lang/reflect/Type.html">Type getOwnerType
() {
return originalType.
getOwnerType();
}
public 1.5.0/docs/api/java/lang/reflect/Type.html">Type getRawType
() {
return originalType.
getRawType();
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int hashCode
() {
return _hash
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public boolean equals
(5+0%2Fdocs%2Fapi+Object">Object obj
) {
if (this == obj
)
return true;
if (!super.
equals(obj
))
return false;
if (getClass
() != obj.
getClass())
return false;
ExpandedParameterizedType other =
(ExpandedParameterizedType
) obj
;
if (!1.5.0/docs/api/java/util/Arrays.html">Arrays.
equals(typeArgs, other.
typeArgs))
return false;
return true;
}
}
/*
* No changes here, but it is important to keep using the rootType for computing the hashcode and equals
* as this is used to check if a type needs to be expanded or not. At that moment the type can be in its original form
* so yield to same types when it should be expanded.
*
* An alternative could be to remove the cashing from TypeUtil as anyway it is mainly used only during
* construction of Converters (that are cached). However this might decrease performances on android, where you might
* be more interested in one short ser/deser. Lets keep it like that for the moment.
*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private final static class TypeAndRootClassKey
{
private final 1.5.0/docs/api/java/lang/reflect/Type.html">Type type
;
private final 1.5.0/docs/api/java/lang/reflect/Type.html">Type rootType
;
private int _hash
;
public TypeAndRootClassKey
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type,
1.5.0/docs/api/java/lang/reflect/Type.html">Type rootType
) {
super();
if (type ==
null || rootType ==
null)
throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException("type and rootType must be not null!");
this.
type = type
;
this.
rootType = rootType
;
_hash = 31 + rootType.
hashCode();
_hash = 31 + type.
hashCode();
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public int hashCode
() {
return _hash
;
}
@
1.5.0/docs/api/java/lang/Override.html">Override
public boolean equals
(5+0%2Fdocs%2Fapi+Object">Object obj
) {
if (this == obj
)
return true;
if (obj ==
null)
return false;
if (!(obj
instanceof TypeAndRootClassKey
))
return false;
TypeAndRootClassKey other =
(TypeAndRootClassKey
) obj
;
return rootType.
equals(other.
rootType) && type.
equals(other.
type);
}
}
}