
org.xerial.util.ReflectionUtil Maven / Gradle / Ivy
The newest version!
/*--------------------------------------------------------------------------
* Copyright 2009 Taro L. Saito
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// ReflectionUtil.java
// Since: Feb 9, 2009 5:58:47 PM
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import org.xerial.core.XerialError;
import org.xerial.core.XerialErrorCode;
import org.xerial.core.XerialException;
/**
* Reflection utilities
*
* @author leo
*
*/
public class ReflectionUtil {
/**
* Set the value of the bean using the given setter
*
* @param bean
* @param setter
* @param value
*/
public static void setValue(Object bean, Method setter, Object value) {
try {
try {
setter.invoke(bean, value);
}
catch (IllegalAccessException e) {
setter.setAccessible(true);
try {
setter.invoke(bean, value);
}
catch (IllegalAccessException e2) {
throw new IllegalAccessError(e2.getMessage());
}
}
}
catch (InvocationTargetException e) {
throw new XerialError(XerialErrorCode.WRONG_DATA_TYPE, e);
}
}
/**
* Retrieve the field value
*
* @param bean
* @param field
* @return
*/
public static Object getFieldValue(Object bean, Field field) {
Object value = null;
try {
value = field.get(bean);
}
catch (IllegalAccessException e) {
field.setAccessible(true);
try {
value = field.get(bean);
}
catch (IllegalAccessException e1) {
throw new IllegalAccessError(e1.getMessage());
}
}
return value;
}
public static Object invokeGetter(Object bean, Method getter) {
try {
return getter.invoke(bean);
}
catch (IllegalArgumentException e) {
throw new XerialError(XerialErrorCode.INVALID_STATE,
"not a getter (0-arg public method): " + getter);
}
catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
}
catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (XerialError.class.isInstance(targetException))
throw XerialError.class.cast(targetException);
else
throw new XerialError(XerialErrorCode.WRONG_DATA_TYPE, e.getTargetException());
}
}
public static Object invokeGetter(Object bean, Method getter, Object arg1) {
try {
return getter.invoke(bean, arg1);
}
catch (IllegalArgumentException e) {
throw new XerialError(XerialErrorCode.INVALID_STATE,
"not a getter (0-arg public method): " + getter);
}
catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
}
catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (XerialError.class.isInstance(targetException))
throw XerialError.class.cast(targetException);
else
throw new XerialError(XerialErrorCode.WRONG_DATA_TYPE, e.getTargetException());
}
}
/**
* Get the generic element type of the field that has a collection type. For
* example, for a field f
*
*
* List<String>
*
*
* getGenericCollectionElementType(f) returns String.class.
*
* @param field
* @return the generic element type
*/
public static Type getGenericCollectionElementType(Field field) {
if (!TypeInfo.isCollection(field.getType()))
throw new XerialError(XerialErrorCode.NOT_A_COLLECTION, field.getType().getName());
Type fieldType = field.getGenericType();
if (hasGenericTypes(fieldType)) {
ParameterizedType pt = ParameterizedType.class.cast(fieldType);
return pt.getActualTypeArguments()[0];
}
else
return Object.class;
}
public static boolean hasGenericTypes(Type t) {
return ParameterizedType.class.isInstance(t);
}
public static Type[] getGenericParameterTypes(Type t) {
if (ParameterizedType.class.isInstance(t)) {
ParameterizedType pt = ParameterizedType.class.cast(t);
return pt.getActualTypeArguments();
}
else
return null;
}
public static Class< ? > getGenericArgumentType(Method method, int argIndex) {
Type[] argTypes = method.getGenericParameterTypes();
if (argTypes.length < argIndex)
throw new XerialError(XerialErrorCode.INVALID_INPUT, method.toGenericString());
if (ParameterizedType.class.isInstance(argTypes[argIndex])) {
ParameterizedType pt = ParameterizedType.class.cast(argTypes[argIndex]);
return toClassType(pt.getActualTypeArguments()[0]);
}
else
return Object.class;
}
public static Type getGenericCollectionElementRawType(Field collectionType) {
if (!TypeInfo.isCollection(collectionType.getType()))
throw new XerialError(XerialErrorCode.NOT_A_COLLECTION, collectionType.getType()
.getName());
Type optionFieldType = collectionType.getGenericType();
if (ParameterizedType.class.isInstance(optionFieldType)) {
ParameterizedType pt = ParameterizedType.class.cast(optionFieldType);
return pt.getActualTypeArguments()[0];
}
else
return Object.class;
}
private static Class< ? > toClassType(Type genericType) {
if (Class.class.isInstance(genericType))
return (Class< ? >) genericType;
else
return Object.class;
}
public static Class< ? > getRawClass(Type type) {
if (ParameterizedType.class.isInstance(type)) {
ParameterizedType pt = ParameterizedType.class.cast(type);
return toClassType(pt.getRawType());
}
else
return toClassType(type);
}
public static Pair, Class< ? >> getGenericMapElementClasses(Field field) {
Pair t = getGenericMapElementTypes(field);
return new Pair, Class< ? >>(Class.class.cast(t.getFirst()), Class.class.cast(t
.getSecond()));
}
public static Pair getGenericMapElementTypes(Field field) {
if (!TypeInfo.isMap(field.getType()))
throw new XerialError(XerialErrorCode.INVALID_INPUT, "not a map type: " + field);
Type fieldType = field.getGenericType();
if (ParameterizedType.class.isInstance(fieldType)) {
ParameterizedType pt = ParameterizedType.class.cast(fieldType);
Type[] keyValueType = pt.getActualTypeArguments();
// TODO look up parent classes?
if (keyValueType.length != 2)
throw new XerialError(XerialErrorCode.INVALID_STATE, "not a Map type: "
+ field);
return new Pair(keyValueType[0], keyValueType[1]);
}
return new Pair(Object.class, Object.class);
}
/**
* If the field value is null, initialize the field with a new collection
*
* @param bean
* the target bean containing the field
* @param field
* the field to initialize. This field must have a collection
* type
* @throws XerialException
* when failed to create a new instance of the field type
*/
public static void initializeCollectionField(Object bean, Field field) throws XerialException {
Class< ? > t = field.getType();
if (!TypeInfo.isCollection(t))
return; // not a collection field
Object collection = getFieldValue(bean, field);
if (collection == null) {
collection = TypeInfo.createInstance(t);
ReflectionUtil.setFieldValue_internal(bean, field, collection);
}
}
/**
* Set the field value of the bean using the given value
*
* @param bean
* the target object
* @param field
* the target field
* @param value
* the value to set
* @throws XerialException
*/
public static void setFieldValue(Object bean, Field field, Object value) throws XerialException {
try {
Class< ? > t = field.getType();
if (TypeInfo.isCollection(t)) {
Object collection = getFieldValue(bean, field);
if (collection == null) {
collection = TypeInfo.createInstance(t);
ReflectionUtil.setFieldValue_internal(bean, field, collection);
}
// using the adder of the collection
try {
Method adder = field.getType().getMethod("add", Object.class);
Type elementType = getGenericCollectionElementType(field);
Object convertedValue = TypeConverter.convertType(getRawClass(elementType),
value);
adder.invoke(collection, convertedValue);
}
catch (SecurityException e) {
throw new XerialError(XerialErrorCode.INACCESSIBLE_METHOD, "add() of "
+ t.getName());
}
catch (NoSuchMethodException e) {
throw new XerialError(XerialErrorCode.NOT_A_COLLECTION, t.getName());
}
catch (IllegalAccessException e) {
throw new XerialError(XerialErrorCode.INACCESSIBLE_METHOD, "add() of "
+ t.getName());
}
catch (InvocationTargetException e) {
throw new XerialError(XerialErrorCode.INACCESSIBLE_METHOD, e);
}
}
else {
Object convertedValue = TypeConverter.convertType(t, value);
setFieldValue_internal(bean, field, convertedValue);
}
}
catch (IllegalArgumentException e) {
throw new XerialException(XerialErrorCode.WRONG_DATA_TYPE, e);
}
}
private static void setFieldValue_internal(Object bean, Field field, Object value) {
try {
field.set(bean, value);
}
catch (IllegalAccessException e) {
field.setAccessible(true);
try {
field.set(bean, value);
}
catch (IllegalAccessException e1) {
throw new IllegalAccessError(e1.getMessage());
}
}
}
@SuppressWarnings("unchecked")
public static void setMapEntry(Object bean, Field field, Object key, Object value)
throws XerialException {
ReflectionUtil.initializeCollectionField(bean, field);
Object mapObj = ReflectionUtil.getFieldValue(bean, field);
if (mapObj == null)
throw new XerialException(XerialErrorCode.INVALID_STATE,
"cannot set (key, value) to null Map field: " + bean);
Pair, Class< ? >> mapElementType = ReflectionUtil
.getGenericMapElementClasses(field);
Class< ? > keyType = mapElementType.getFirst();
Class< ? > valueType = mapElementType.getSecond();
Map map = Map.class.cast(mapObj);
map.put(TypeConverter.convertType(keyType, key), TypeConverter
.convertType(valueType, value));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy