| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.openjpa.enhance; |
| |
| import java.lang.reflect.AccessibleObject; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.security.AccessController; |
| import java.util.Collections; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import org.apache.openjpa.lib.util.J2DoPrivHelper; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.lib.util.Localizer.Message; |
| import org.apache.openjpa.lib.util.Reflectable; |
| import org.apache.openjpa.lib.util.StringUtil; |
| import org.apache.openjpa.lib.util.collections.AbstractReferenceMap.ReferenceStrength; |
| import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; |
| import org.apache.openjpa.util.GeneralException; |
| import org.apache.openjpa.util.UserException; |
| |
| /** |
| * Reflection utilities used to support and augment enhancement. Used both |
| * at enhancement time and at runtime. |
| * |
| * @author Abe White |
| */ |
| public class Reflection { |
| |
| private static final Localizer _loc = Localizer.forPackage |
| (Reflection.class); |
| |
| // Weak HashMap caches of getter/setter/beanProperty methods |
| private static Map<Class<?>, Map<String, Method>> getterMethodCache = |
| new ConcurrentReferenceHashMap(ReferenceStrength.WEAK, ReferenceStrength.HARD); |
| private static Map<Class<?>, Map<String, Method>> setterMethodCache = |
| new ConcurrentReferenceHashMap(ReferenceStrength.WEAK, ReferenceStrength.HARD); |
| private static Map<Class<?>, Set<String>> beanPropertiesNameCache = |
| new ConcurrentReferenceHashMap(ReferenceStrength.WEAK, ReferenceStrength.HARD); |
| |
| private static Method getGetterMethod(Class<?> cls, String prop) { |
| Method rtnMethod = null; |
| Map<String, Method> clsMap = getterMethodCache.get(cls); |
| if (clsMap != null) { |
| rtnMethod = clsMap.get(prop); |
| } |
| return rtnMethod; |
| } |
| |
| private static void setGetterMethod(Class<?> cls, String prop, |
| Method method) { |
| Map<String, Method> clsMap = getterMethodCache.get(cls); |
| if (clsMap == null) { |
| clsMap = new ConcurrentReferenceHashMap(ReferenceStrength.HARD, |
| ReferenceStrength.WEAK); |
| getterMethodCache.put(cls, clsMap); |
| } |
| clsMap.put(prop, method); |
| } |
| |
| private static Method getSetterMethod(Class<?> cls, String prop) { |
| Method rtnMethod = null; |
| Map<String, Method> clsMap = setterMethodCache.get(cls); |
| if (clsMap != null) { |
| rtnMethod = clsMap.get(prop); |
| } |
| return rtnMethod; |
| } |
| |
| private static void setSetterMethod(Class<?> cls, String prop, |
| Method method) { |
| Map<String, Method> clsMap = setterMethodCache.get(cls); |
| if (clsMap == null) { |
| clsMap = new ConcurrentReferenceHashMap(ReferenceStrength.HARD, |
| ReferenceStrength.WEAK); |
| setterMethodCache.put(cls, clsMap); |
| } |
| clsMap.put(prop, method); |
| } |
| |
| /** |
| * Return the getter method matching the given property name, optionally |
| * throwing an exception if none. |
| */ |
| public static Method findGetter(Class cls, String prop, boolean mustExist) { |
| Method m = getGetterMethod(cls, prop); |
| if (m != null) { |
| return m; |
| } |
| String capProp = StringUtil.capitalize(prop); |
| try { |
| // this algorithm searches for a get<prop> or is<prop> method in |
| // a breadth-first manner. |
| for (Class c = cls; c != null && c != Object.class; |
| c = c.getSuperclass()) { |
| m = getDeclaredMethod(c, "get" + capProp, null); |
| if (m != null) { |
| setGetterMethod(cls, prop, m); |
| return m; |
| } else { |
| m = getDeclaredMethod(c, "is" + capProp, null); |
| if (m != null && (m.getReturnType() == boolean.class |
| || m.getReturnType() == Boolean.class)) { |
| setGetterMethod(cls, prop, m); |
| return m; |
| } else { |
| m = getDeclaredMethod(c, "get" + prop, null); |
| if (m != null) { |
| setGetterMethod(cls, prop, m); |
| return m; |
| } else { |
| m = getDeclaredMethod(c, "is" + prop, null); |
| if (m != null |
| && (m.getReturnType() == boolean.class || m.getReturnType() == Boolean.class)) { |
| setGetterMethod(cls, prop, m); |
| return m; |
| } |
| } |
| } |
| } |
| } |
| } catch (Exception e) { |
| throw new GeneralException(e); |
| } |
| |
| if (mustExist) |
| throw new UserException(_loc.get("bad-getter", cls, prop)); |
| return null; |
| } |
| |
| /** |
| * Return the setter method matching the given property name, optionally |
| * throwing an exception if none. The property must also have a getter. |
| */ |
| public static Method findSetter(Class cls, String prop, boolean mustExist) { |
| Method getter = findGetter(cls, prop, mustExist); |
| return (getter == null) ? null |
| : findSetter(cls, prop, getter.getReturnType(), mustExist); |
| } |
| |
| /** |
| * Return the setter method matching the given property name, optionally |
| * throwing an exception if none. |
| */ |
| public static Method findSetter(Class cls, String prop, Class param, |
| boolean mustExist) { |
| Method m = getSetterMethod(cls, prop); |
| if (m != null) { |
| return m; |
| } |
| String name = "set" + StringUtil.capitalize(prop); |
| try { |
| for (Class c = cls; c != null && c != Object.class; |
| c = c.getSuperclass()) { |
| m = getDeclaredMethod(c, name, param); |
| if (m != null) { |
| setSetterMethod(cls, prop, m); |
| return m; |
| } |
| } |
| } catch (Exception e) { |
| throw new GeneralException(e); |
| } |
| |
| if (mustExist) |
| throw new UserException(_loc.get("bad-setter", cls, prop)); |
| return null; |
| } |
| |
| /** |
| * Invokes <code>cls.getDeclaredMethods()</code>, and returns the method |
| * that matches the <code>name</code> and <code>param</code> arguments. |
| * Avoids the exception thrown by <code>Class.getDeclaredMethod()</code> |
| * for performance reasons. <code>param</code> may be null. Additionally, |
| * if there are multiple methods with different return types, this will |
| * return the method defined in the least-derived class. |
| * |
| * @since 0.9.8 |
| */ |
| static Method getDeclaredMethod(Class cls, String name, |
| Class param) { |
| Method[] methods = (Method[]) AccessController.doPrivileged( |
| J2DoPrivHelper.getDeclaredMethodsAction(cls)); |
| Method candidate = null; |
| for (Method method : methods) { |
| if (name.equals(method.getName())) { |
| Class[] methodParams = method.getParameterTypes(); |
| if (param == null && methodParams.length == 0) |
| candidate = mostDerived(method, candidate); |
| else if (param != null && methodParams.length == 1 |
| && param.equals(methodParams[0])) |
| candidate = mostDerived(method, candidate); |
| } |
| } |
| return candidate; |
| } |
| |
| static Method mostDerived(Method meth1, Method meth2) { |
| if (meth1 == null) |
| return meth2; |
| if (meth2 == null) |
| return meth1; |
| |
| Class cls2 = meth2.getDeclaringClass(); |
| Class cls1 = meth1.getDeclaringClass(); |
| |
| if (cls1.equals(cls2)) { |
| Class ret1 = meth1.getReturnType(); |
| Class ret2 = meth2.getReturnType(); |
| if (ret1.isAssignableFrom(ret2)) |
| return meth2; |
| else if (ret2.isAssignableFrom(ret1)) |
| return meth1; |
| else |
| throw new IllegalArgumentException( |
| _loc.get("most-derived-unrelated-same-type", meth1, meth2) |
| .getMessage()); |
| } else { |
| if (cls1.isAssignableFrom(cls2)) |
| return meth2; |
| else if (cls2.isAssignableFrom(cls1)) |
| return meth1; |
| else |
| throw new IllegalArgumentException( |
| _loc.get("most-derived-unrelated", meth1, meth2) |
| .getMessage()); |
| } |
| } |
| |
| /** |
| * Return the field with the given name, optionally throwing an exception |
| * if none. |
| */ |
| public static Field findField(Class cls, String name, boolean mustExist) { |
| try { |
| Field f; |
| for (Class c = cls; c != null && c != Object.class; |
| c = c.getSuperclass()) { |
| f = getDeclaredField(c, name); |
| if (f != null) |
| return f; |
| } |
| } catch (Exception e) { |
| throw new GeneralException(e); |
| } |
| |
| if (mustExist) |
| throw new UserException(_loc.get("bad-field", cls, name)); |
| return null; |
| } |
| |
| /** |
| * Invokes <code>cls.getDeclaredFields()</code>, and returns the field |
| * that matches the <code>name</code> argument. Avoids the exception |
| * thrown by <code>Class.getDeclaredField()</code> for performance reasons. |
| * |
| * @since 0.9.8 |
| */ |
| private static Field getDeclaredField(Class cls, String name) { |
| Field[] fields = AccessController.doPrivileged( |
| J2DoPrivHelper.getDeclaredFieldsAction(cls)); |
| for (Field field : fields) { |
| if (name.equals(field.getName())) |
| return field; |
| } |
| return null; |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static Object get(Object target, Field field) { |
| if (target == null || field == null) |
| return null; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.get(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Get the value of the given named field or a corresponding getter method. |
| * |
| * @return null if the field does not exist and mustExist is set to false or |
| * the given target is null. |
| * |
| * @exception UserException if mustExist is true and the field or getter |
| * method is non-existent |
| */ |
| public static Object getValue(Object obj, String prop, boolean mustExist) { |
| if (obj == null) |
| return null; |
| Class cls = obj.getClass(); |
| Field field = findField(cls, prop, false); |
| if (field != null) |
| return get(obj, field); |
| Method getter = findGetter(cls, prop, false); |
| if (getter != null) |
| return get(obj, getter); |
| if (mustExist) |
| throw new UserException(_loc.get("bad-field", cls, prop)); |
| return null; // should not reach |
| } |
| |
| /** |
| * Make the given member accessible if it isn't already. |
| */ |
| private static void makeAccessible(AccessibleObject ao, int mods) { |
| try { |
| if (!Modifier.isPublic(mods) && !ao.isAccessible()) |
| AccessController.doPrivileged(J2DoPrivHelper |
| .setAccessibleAction(ao, true)); |
| } catch (SecurityException se) { |
| throw new UserException(_loc.get("reflect-security", ao)). |
| setFatal(true); |
| } |
| } |
| |
| /** |
| * Wrap the given reflection exception as a runtime exception. |
| */ |
| private static RuntimeException wrapReflectionException(Throwable t, Message message) { |
| if (t instanceof InvocationTargetException) |
| t = ((InvocationTargetException) t).getTargetException(); |
| t.initCause(new IllegalArgumentException(message.getMessage())); |
| if (t instanceof RuntimeException) |
| return (RuntimeException) t; |
| return new GeneralException(t); |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static boolean getBoolean(Object target, Field field) { |
| if (target == null || field == null) |
| return false; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getBoolean(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static byte getByte(Object target, Field field) { |
| if (target == null || field == null) |
| return (byte) 0; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getByte(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static char getChar(Object target, Field field) { |
| if (target == null || field == null) |
| return (char) 0; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getChar(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static double getDouble(Object target, Field field) { |
| if (target == null || field == null) |
| return 0D; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getDouble(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static float getFloat(Object target, Field field) { |
| if (target == null || field == null) |
| return 0F; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getFloat(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static int getInt(Object target, Field field) { |
| if (target == null || field == null) |
| return 0; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getInt(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static long getLong(Object target, Field field) { |
| if (target == null || field == null) |
| return 0L; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getLong(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the value of the given field in the given object. |
| */ |
| public static short getShort(Object target, Field field) { |
| if (target == null || field == null) |
| return (short) 0; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| return field.getShort(target); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-field", target, field)); |
| } |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static Object get(Object target, Method getter) { |
| if (target == null || getter == null) |
| return null; |
| makeAccessible(getter, getter.getModifiers()); |
| try { |
| return getter.invoke(target, (Object[]) null); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("get-method", target, getter)); |
| } |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static boolean getBoolean(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? false : (Boolean) o; |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static byte getByte(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? (byte) 0 : ((Number) o).byteValue(); |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static char getChar(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? (char) 0 : (Character) o; |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static double getDouble(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? 0D : ((Number) o).doubleValue(); |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static float getFloat(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? 0F : ((Number) o).floatValue(); |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static int getInt(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? 0 : ((Number) o).intValue(); |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static long getLong(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? 0L : ((Number) o).longValue(); |
| } |
| |
| /** |
| * Return the return value of the given getter in the given object. |
| */ |
| public static short getShort(Object target, Method getter) { |
| Object o = get(target, getter); |
| return (o == null) ? (short) 0 : ((Number) o).shortValue(); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, Object value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.set(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, |
| value == null ? "" : value.getClass()})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, boolean value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setBoolean(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "boolean"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, byte value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setByte(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "byte"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, char value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setChar(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "char"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, double value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setDouble(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "double"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, float value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setFloat(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "float"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, int value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setInt(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "int"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, long value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setLong(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "long"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| */ |
| public static void set(Object target, Field field, short value) { |
| if (target == null || field == null) |
| return; |
| makeAccessible(field, field.getModifiers()); |
| try { |
| field.setShort(target, value); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-field", new Object[]{target, field, value, "short"})); |
| } |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, Object value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, boolean value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, byte value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, char value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, double value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, float value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, int value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, long value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Set the value of the given field in the given object. |
| * Same behavior as above methods, but parameter ordering is rearranged |
| * to simplify usage from generated bytecodes. |
| * |
| * @since 1.0.0 |
| */ |
| public static void set(Object target, short value, Field field) { |
| set(target, field, value); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, Object value) { |
| if (target == null || setter == null) |
| return; |
| makeAccessible(setter, setter.getModifiers()); |
| try { |
| setter.invoke(target, new Object[] { value }); |
| } catch (Throwable t) { |
| throw wrapReflectionException(t, _loc.get("set-method", new Object[]{target, setter, value, |
| value == null ? "" : value.getClass()})); |
| } |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, boolean value) { |
| set(target, setter, (value) ? Boolean.TRUE : Boolean.FALSE); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, byte value) { |
| set(target, setter, Byte.valueOf(value)); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, char value) { |
| set(target, setter, Character.valueOf(value)); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, double value) { |
| set(target, setter, new Double(value)); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, float value) { |
| set(target, setter, new Float(value)); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, int value) { |
| set(target, setter, Integer.valueOf(value)); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, long value) { |
| set(target, setter, Long.valueOf(value)); |
| } |
| |
| /** |
| * Invoke the given setter on the given object. |
| */ |
| public static void set(Object target, Method setter, short value) { |
| set(target, setter, Short.valueOf(value)); |
| } |
| |
| /** |
| * Gets all bean-style property names of the given Class or its superclass. |
| * A bean-style property 'abc' exists in Class C iff C has declared |
| * following pair of methods: |
| * public void setAbc(Y y) or public C setAbc(Y y) |
| * public Y getAbc(); |
| * |
| * If a getter property is annotated with {@link Reflectable}, then |
| * it is ignored. |
| * |
| */ |
| public static Set<String> getBeanStylePropertyNames(Class<?> c) { |
| if (c == null) |
| return Collections.emptySet(); |
| Set<String> result = beanPropertiesNameCache.get(c); |
| if (result != null) { |
| return result; |
| } |
| Method[] methods = c.getMethods(); |
| if (methods == null || methods.length < 2) |
| return Collections.emptySet(); |
| result = new TreeSet<>(); |
| for (Method m : methods) { |
| if (m.getName().startsWith("get")) { |
| if (!canReflect(m)) |
| continue; |
| String prop = StringUtil.capitalize(m.getName() |
| .substring("get".length())); |
| Class<?> rtype = m.getReturnType(); |
| try { |
| Method setter = c.getMethod("set"+prop, new Class<?>[]{rtype}); |
| if (setter.getReturnType() == void.class || |
| setter.getReturnType().isAssignableFrom(c)) |
| result.add(prop); |
| } catch (NoSuchMethodException e) { |
| |
| } |
| } |
| } |
| beanPropertiesNameCache.put(c, result); |
| return result; |
| } |
| |
| /** |
| * Gets all public field names of the given Class. |
| * |
| */ |
| public static Set<String> getPublicFieldNames(Class c) { |
| if (c == null) |
| return Collections.EMPTY_SET; |
| Field[] fields = c.getFields(); |
| if (fields == null || fields.length == 0) |
| return Collections.EMPTY_SET; |
| Set<String> result = new TreeSet<>(); |
| for (Field f : fields) { |
| if (canReflect(f)) |
| result.add(f.getName()); |
| } |
| return result; |
| } |
| |
| /** |
| * Gets values of all field f the given class such that f exactly |
| * match the given modifiers and are of given type (Object implies any type) |
| * unless f is annotated as {@link Reflectable}. |
| * |
| */ |
| public static <T> Set<T> getFieldValues(Class c, int mods, Class<T> t){ |
| if (c == null) |
| return Collections.EMPTY_SET; |
| Field[] fields = c.getFields(); |
| if (fields == null || fields.length == 0) |
| return Collections.EMPTY_SET; |
| Set<T> result = new TreeSet<>(); |
| for (Field f : fields) { |
| if (mods == f.getModifiers() |
| && (t == Object.class || t.isAssignableFrom(f.getType())) |
| && canReflect(f)) { |
| try { |
| result.add((T)f.get(null)); |
| } catch (IllegalArgumentException | IllegalAccessException e) { |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Affirms if the given member is selected for reflection. The decision is |
| * based on the following truth table on both the class-level and |
| * member-level annotation (null annotation represents MAYBE) |
| * |
| * Class member |
| * MAYBE MAYBE YES |
| * MAYBE YES YES |
| * MAYBE NO NO |
| * |
| * YES MAYBE YES |
| * YES YES YES |
| * YES NO NO |
| * |
| * NO YES YES |
| * NO MAYBE NO |
| * NO NO NO |
| * |
| */ |
| static boolean canReflect(Reflectable cls, Reflectable member) { |
| if (cls == null || cls.value()) { |
| return member == null || member.value(); |
| } else { |
| return member != null && member.value(); |
| } |
| } |
| |
| /** |
| * Affirms if the original declaration the given field is annotated |
| * for reflection. |
| */ |
| static boolean canReflect(Field field) { |
| Class cls = field.getDeclaringClass(); |
| return canReflect((Reflectable)cls.getAnnotation(Reflectable.class), |
| field.getAnnotation(Reflectable.class)); |
| } |
| |
| /** |
| * Affirms if the original declaration the given method is annotated |
| * for reflection. |
| */ |
| static boolean canReflect(Method method) { |
| Class cls = getDeclaringClass(method); |
| if (cls != method.getDeclaringClass()) |
| method = getDeclaringMethod(cls, method); |
| return canReflect((Reflectable)cls.getAnnotation(Reflectable.class), |
| method.getAnnotation(Reflectable.class)); |
| } |
| |
| /** |
| * Gets the declaring class of the given method signature but also checks |
| * if the method is declared in an interface. If yes, then returns the |
| * interface. |
| */ |
| public static Class getDeclaringClass(Method m) { |
| if (m == null) |
| return null; |
| Class cls = m.getDeclaringClass(); |
| Class[] intfs = cls.getInterfaces(); |
| for (Class intf : intfs) { |
| if (getDeclaringMethod(intf, m) != null) |
| cls = intf; |
| } |
| return cls; |
| } |
| |
| /** |
| * Gets the method in the given class that has the same signature of the |
| * given method, if exists. Otherwise, null. |
| */ |
| public static Method getDeclaringMethod(Class c, Method m) { |
| try { |
| Method m0 = c.getMethod(m.getName(), m.getParameterTypes()); |
| return m0; |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| } |