Author: mbenson
Date: Fri Dec 5 22:16:50 2014
New Revision: 1643452
URL: http://svn.apache.org/r1643452
Log:
clean up when we alter accessibility of members
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/ConstructorAccess.java
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/AccessStrategy.java
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/FieldAccess.java
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/MethodAccess.java
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/ConstructorAccess.java
URL:
http://svn.apache.org/viewvc/bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/ConstructorAccess.java?rev=1643452&r1=1643451&r2=1643452&view=diff
==============================================================================
---
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/ConstructorAccess.java
(original)
+++
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/ConstructorAccess.java
Fri Dec 5 22:16:50 2014
@@ -28,7 +28,6 @@ public class ConstructorAccess extends A
public ConstructorAccess(final Constructor<?> constructor) {
this.constructor = constructor;
- setAccessible(constructor);
}
@Override
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/AccessStrategy.java
URL:
http://svn.apache.org/viewvc/bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/AccessStrategy.java?rev=1643452&r1=1643451&r2=1643452&view=diff
==============================================================================
---
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/AccessStrategy.java
(original)
+++
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/AccessStrategy.java
Fri Dec 5 22:16:50 2014
@@ -17,11 +17,8 @@
package org.apache.bval.util;
import java.lang.annotation.ElementType;
-import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Type;
-import org.apache.commons.weaver.privilizer.Privileged;
-
/**
* Description: abstract class to encapsulate different strategies
* to get the value of a Property. This class is designed such that
@@ -59,20 +56,4 @@ public abstract class AccessStrategy {
*/
public abstract String getPropertyName();
- /**
- * Set {@code accessibleObject} as being accessible
- * @param accessibleObject
- */
- protected boolean setAccessible(AccessibleObject accessibleObject) {
- if (accessibleObject.isAccessible()) {
- return false;
- }
- doSetAccessible(accessibleObject);
- return true;
- }
-
- @Privileged
- private void doSetAccessible(AccessibleObject accessibleObject) {
- accessibleObject.setAccessible(true);
- }
}
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/FieldAccess.java
URL:
http://svn.apache.org/viewvc/bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/FieldAccess.java?rev=1643452&r1=1643451&r2=1643452&view=diff
==============================================================================
---
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/FieldAccess.java
(original)
+++
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/FieldAccess.java
Fri Dec 5 22:16:50 2014
@@ -20,9 +20,14 @@ import java.lang.annotation.ElementType;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
/**
* Description: direct field access strategy.<br/>
*/
+@Privilizing(@CallTo(Reflection.class))
public class FieldAccess extends AccessStrategy {
private final Field field;
@@ -33,17 +38,21 @@ public class FieldAccess extends AccessS
*/
public FieldAccess(final Field field) {
this.field = field;
- setAccessible(field);
}
/**
* {@inheritDoc}
*/
public Object get(final Object instance) {
+ final boolean mustUnset = Reflection.setAccessible(field, true);
try {
return field.get(instance);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(field, false);
+ }
}
}
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/MethodAccess.java
URL:
http://svn.apache.org/viewvc/bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/MethodAccess.java?rev=1643452&r1=1643451&r2=1643452&view=diff
==============================================================================
---
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/MethodAccess.java
(original)
+++
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/MethodAccess.java
Fri Dec 5 22:16:50 2014
@@ -22,9 +22,14 @@ import java.lang.reflect.InvocationTarge
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
/**
* Description: invoke a zero-argument method (getter)<br/>
*/
+@Privilizing(@CallTo(Reflection.class))
public class MethodAccess extends AccessStrategy {
private final Method method;
private final String propertyName;
@@ -45,7 +50,6 @@ public class MethodAccess extends Access
public MethodAccess(String propertyName, final Method method) {
this.method = method;
this.propertyName = propertyName;
- setAccessible(method);
}
/**
@@ -80,12 +84,17 @@ public class MethodAccess extends Access
* {@inheritDoc}
*/
public Object get(final Object instance) {
+ final boolean mustUnset = Reflection.setAccessible(method, true);
try {
return method.invoke(instance);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(method, false);
+ }
}
}
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java
URL:
http://svn.apache.org/viewvc/bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java?rev=1643452&r1=1643451&r2=1643452&view=diff
==============================================================================
---
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java
(original)
+++
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java
Fri Dec 5 22:16:50 2014
@@ -16,6 +16,7 @@
*/
package org.apache.bval.util;
+import org.apache.bval.util.reflection.Reflection;
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;
@@ -149,6 +150,17 @@ public class PropertyAccess extends Acce
return null;
}
+ private static Object readField(Field field, Object bean) throws
IllegalAccessException {
+ final boolean mustUnset = Reflection.setAccessible(field, true);
+ try {
+ return field.get(bean);
+ } finally {
+ if (mustUnset) {
+ Reflection.setAccessible(field, false);
+ }
+ }
+ }
+
/**
* {@inheritDoc}
*/
@@ -162,7 +174,7 @@ public class PropertyAccess extends Acce
public Object get(Object bean) {
try {
if (rememberField != null) { // cache field of previous access
- return rememberField.get(bean);
+ return readField(rememberField, bean);
}
try { // try public method
return getPublicProperty(bean, propertyName);
@@ -180,15 +192,12 @@ public class PropertyAccess extends Acce
Field field = getField(propertyName, beanClass);
if (field != null) {
cacheField(field);
- return rememberField.get(bean);
+ return readField(rememberField, bean);
}
throw new IllegalArgumentException("cannot access field " +
propertyName);
}
private void cacheField(Field field) {
- if (!field.isAccessible()) {
- field.setAccessible(true);
- }
this.rememberField = field;
}
Modified:
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
URL:
http://svn.apache.org/viewvc/bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java?rev=1643452&r1=1643451&r2=1643452&view=diff
==============================================================================
---
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
(original)
+++
bval/branches/bval-11/bval-core/src/main/java/org/apache/bval/util/reflection/Reflection.java
Fri Dec 5 22:16:50 2014
@@ -17,89 +17,112 @@
package org.apache.bval.util.reflection;
import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.weaver.privilizer.Privilizing;
/**
- * Security-agnostic "blueprint" class for reflection-related operations.
+ * Security-agnostic "blueprint" class for reflection-related operations.
Intended for use by Apache BVal code.
*
* @version $Rev$ $Date$
*/
public class Reflection {
- private static void setAccessibility(final Field field) {
- // FIXME 2011-03-27 jw:
- // - Why not simply call field.setAccessible(true)?
- // - Fields can not be abstract.
- if (!Modifier.isPublic(field.getModifiers())
- || (Modifier.isPublic(field.getModifiers()) &&
Modifier.isAbstract(field.getModifiers()))) {
- field.setAccessible(true);
- }
- }
-
+ /**
+ * Get the named {@link Class} from the specified {@link ClassLoader}.
+ * @param classLoader
+ * @param className
+ * @return Class
+ * @throws Exception
+ */
public static Class<?> getClass(final ClassLoader classLoader, final
String className) throws Exception {
return ClassUtils.getClass(classLoader, className, true);
}
+ /**
+ * Get the named value from the specified {@link Annotation}.
+ * @param annotation
+ * @param name
+ * @return Object value
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
public static Object getAnnotationValue(final Annotation annotation, final
String name)
throws IllegalAccessException, InvocationTargetException {
- Method valueMethod;
+ final Method valueMethod;
try {
valueMethod = annotation.annotationType().getDeclaredMethod(name);
} catch (final NoSuchMethodException ex) {
// do nothing
- valueMethod = null;
+ return null;
}
- if (null != valueMethod) {
- if (!valueMethod.isAccessible()) {
- valueMethod.setAccessible(true);
- }
+ final boolean mustUnset = setAccessible(valueMethod, true);
+ try {
return valueMethod.invoke(annotation);
+ } finally {
+ if (mustUnset) {
+ setAccessible(valueMethod, false);
+ }
}
- return null;
}
+ /**
+ * Get a usable {@link ClassLoader}: that of {@code clazz} if {@link
Thread#getContextClassLoader()} returns {@code null}.
+ * @param clazz
+ * @return {@link ClassLoader}
+ */
public static ClassLoader getClassLoader(final Class<?> clazz) {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
- if (cl != null) {
- return cl;
- }
- return clazz.getClassLoader();
+ return cl == null ? clazz.getClassLoader() : cl;
}
+ /**
+ * Convenient point for {@link Privilizing} {@link
System#getProperty(String)}.
+ * @param name
+ * @return String
+ */
public static String getProperty(final String name) {
return System.getProperty(name);
}
+ /**
+ * Get the declared field from {@code clazz}.
+ * @param clazz
+ * @param fieldName
+ * @return {@link Field} or {@code null}
+ */
public static Field getDeclaredField(final Class<?> clazz, final String
fieldName) {
- final Field f;
try {
- f = clazz.getDeclaredField(fieldName);
+ return clazz.getDeclaredField(fieldName);
} catch (final NoSuchFieldException e) {
return null;
}
- setAccessibility(f);
- return f;
}
+ /**
+ * Convenient point for {@link Privilizing} {@link
Class#getDeclaredFields()}.
+ * @param clazz
+ * @return {@link Field} array
+ */
public static Field[] getDeclaredFields(final Class<?> clazz) {
- final Field[] fields = clazz.getDeclaredFields();
- if (fields.length > 0) {
- for (final Field f : fields) {
- if (!f.isAccessible()) {
- f.setAccessible(true);
- }
- }
- }
- return fields;
+ return clazz.getDeclaredFields();
}
- public static Constructor<?> getDeclaredConstructor(final Class<?> clazz,
final Class<?>... parameters) {
+ /**
+ * Get the declared constructor from {@code clazz}.
+ * @param T generic type
+ * @param clazz
+ * @param parameters
+ * @return {@link Constructor} or {@code null}
+ */
+ public static <T> Constructor<T> getDeclaredConstructor(final Class<T>
clazz, final Class<?>... parameters) {
try {
return clazz.getDeclaredConstructor(parameters);
} catch (final NoSuchMethodException e) {
@@ -107,6 +130,13 @@ public class Reflection {
}
}
+ /**
+ * Get the declared method from {@code clazz}.
+ * @param clazz
+ * @param name
+ * @param parameters
+ * @return {@link Method} or {@code null}
+ */
public static Method getDeclaredMethod(final Class<?> clazz, final String
name, final Class<?>... parameters) {
try {
return clazz.getDeclaredMethod(name, parameters);
@@ -115,22 +145,43 @@ public class Reflection {
}
}
+ /**
+ * Convenient point for {@link Privilizing} {@link
Class#getDeclaredMethods()}.
+ * @param clazz
+ * @return {@link Method} array
+ */
public static Method[] getDeclaredMethods(final Class<?> clazz) {
return clazz.getDeclaredMethods();
}
+ /**
+ * Convenient point for {@link Privilizing} {@link
Class#getDeclaredConstructors()}.
+ * @param clazz
+ * @return {@link Constructor} array
+ */
public static Constructor<?>[] getDeclaredConstructors(final Class<?>
clazz) {
return clazz.getDeclaredConstructors();
}
- public static Method getPublicMethod(final Class<?> clazz, final String
methodName) {
+ /**
+ * Get the specified {@code public} {@link Method} from {@code clazz}.
+ * @param clazz
+ * @param methodName
+ * @return {@link Method} or {@code null}
+ */
+ public static Method getPublicMethod(final Class<?> clazz, final String
methodName, Class<?>... parameterTypes) {
try {
- return clazz.getMethod(methodName);
+ return clazz.getMethod(methodName, parameterTypes);
} catch (final NoSuchMethodException e) {
return null;
}
}
+ /**
+ * Construct a new instance of {@code cls} using its default constructor.
+ * @param cls
+ * @return T
+ */
public static <T> T newInstance(final Class<T> cls) {
try {
return cls.newInstance();
@@ -139,4 +190,39 @@ public class Reflection {
}
}
+ /**
+ * Set the accessibility of {@code o} to {@code accessible}.
+ * @param o
+ * @param accessible
+ * @return whether a change was made.
+ */
+ public static boolean setAccessible(final AccessibleObject o, boolean
accessible) {
+ if (o == null || o.isAccessible() == accessible) {
+ return false;
+ }
+ final Member m = (Member) o;
+ if (Modifier.isPublic(m.getModifiers())) {
+ /*
+ * For objects with public accessibility, we do nothing and return
with one exception.
+ *
+ * Following explanation copied from Apache Commons [lang]
MemberUtils:
+ * When a {@code public} class has a default access superclass
with {@code public} members,
+ * these members are accessible. Calling them from compiled code
works fine.
+ * Unfortunately, on some JVMs, using reflection to invoke these
members
+ * seems to (wrongly) prevent access even when the modifier is
{@code public}.
+ * Calling {@code setAccessible(true)} solves the problem but will
only work from
+ * sufficiently privileged code.
+ */
+ if (!isPackageAccess(m.getDeclaringClass().getModifiers())) {
+ return false;
+ }
+ }
+ o.setAccessible(accessible);
+ return true;
+ }
+
+ private static boolean isPackageAccess(final int modifiers) {
+ return (modifiers & (Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.PUBLIC)) == 0;
+ }
+
}