Author: mbenson
Date: Mon May  5 15:12:48 2008
New Revision: 653618

URL: http://svn.apache.org/viewvc?rev=653618&view=rev
Log:
add FieldUtils and tests

Added:
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/FieldUtilsTest.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/ReflectTestSuite.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/Ambig.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/Bar.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/Foo.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/Parent.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/PrivatelyShadowedChild.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/PublicChild.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/PubliclyShadowedChild.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/StaticContainer.java
   (with props)
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/reflect/testbed/StaticContainerChild.java
   (with props)
Modified:
    
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/FieldUtils.java
    
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/MemberUtils.java
    
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/AllLangTestSuite.java

Modified: 
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/FieldUtils.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/FieldUtils.java?rev=653618&r1=653617&r2=653618&view=diff
==============================================================================
--- 
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/FieldUtils.java
 (original)
+++ 
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/FieldUtils.java
 Mon May  5 15:12:48 2008
@@ -1,41 +1,39 @@
 /*
- * Copyright 2003,2004 The Apache Software Foundation.
- * 
- * 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
- * 
+ * 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.commons.reflect;
+package org.apache.commons.lang.reflect;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 
 /**
- * Utilities for working with fields by reflection.
+ * Utilities for working with fields by reflection. Adapted and refactored
+ * from the dormant [reflect] Commons sandbox component.
  * <p>
  * The ability is provided to break the scoping restrictions coded by the
  * programmer. This can allow fields to be changed that shouldn't be. This
  * facility should be used with care.
  *
  * @author Stephen Colebourne
+ * @author Matt Benson
+ * @since 2.5
  * @version $Id$
- * @since Commons Reflect 1.0
  */
 public class FieldUtils {
-    
-    /**
-     * An empty field array.
-     */
-    public static final Field[] EMPTY_FIELD_ARRAY = new Field[0];
-    
+
     /**
      * FieldUtils instances should NOT be constructed in standard programming.
      * <p>
@@ -46,7 +44,6 @@
         super();
     }
 
-    //-----------------------------------------------------------------------
     /**
      * Gets an accessible <code>Field</code> by name repecting scope.
      * Superclasses/interfaces will be considered.
@@ -55,26 +52,26 @@
      * @param fieldName  the field name to obtain
      * @return the Field object
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
      */
     public static Field getField(Class cls, String fieldName) {
-        return getField(cls, fieldName, false);
+        Field field = getField(cls, fieldName, false);
+        MemberUtils.setAccessibleWorkaround(field);
+        return field;
     }
-    
+
     /**
      * Gets an accessible <code>Field</code> by name breaking scope
      * if requested. Superclasses/interfaces will be considered.
      *
      * @param cls  the class to reflect, must not be null
      * @param fieldName  the field name to obtain
-     * @param breakScope  whether to break scope restrictions using the
+     * @param forceAccess  whether to break scope restrictions using the
      *  <code>setAccessible</code> method. <code>False</code> will only
      *  match public fields.
      * @return the Field object
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
      */
-    public static Field getField(Class cls, String fieldName, boolean 
breakScope) {
+    public static Field getField(final Class cls, String fieldName, boolean 
forceAccess) {
         if (cls == null) {
             throw new IllegalArgumentException("The class must not be null");
         }
@@ -83,7 +80,7 @@
         }
         // Sun Java 1.3 has a bugged implementation of getField hence we write 
the
         // code ourselves
-        
+
         // getField() will return the Field object with the declaring class
         // set correctly to the class that declares the field. Thus requesting 
the
         // field on a subclass will return the field from the superclass.
@@ -93,66 +90,55 @@
         // superclass protected/package/public
         //  private/different package blocks access to further superclasses
         // implementedinterface public
-        try {
-            // check up the superclass hierarchy
-            Class acls = cls;
-            Field match = null;
-            while (acls != null && acls != Object.class) {
+
+        // check up the superclass hierarchy
+        for (Class acls = cls; acls != null; acls = acls.getSuperclass()) {
+            try {
+                Field field = acls.getDeclaredField(fieldName);
                 // getDeclaredField checks for non-public scopes as well
                 // and it returns accurate results
-                try {
-                    Field field = acls.getDeclaredField(fieldName);
-                    if (Modifier.isPublic(field.getModifiers()) == false) {
-                        field.setAccessible(breakScope);
-                        return field;
-                    }
-                    if (breakScope == false) {
-                        // only public acceptable if not breaking scope
-                        throw new IllegalAccessException("The field '" + 
fieldName + 
-                            "' was found, but it's scope prevents direct 
access by reflection");
+                if (!Modifier.isPublic(field.getModifiers())) {
+                    if (forceAccess) {
+                        field.setAccessible(true);
+                    } else {
+                        continue;
                     }
-                    field.setAccessible(true);
-                    match = field;
-                    break;
-                    
-                } catch (NoSuchFieldException ex) {
-                    // ignore
                 }
-                // next superclass
-                acls = acls.getSuperclass();
+                return field;
+            } catch (NoSuchFieldException ex) {
+                // ignore
             }
-            // check the public interface case. This must be manually searched 
for
-            // incase there is a public supersuperclass field hidden by a 
private/package
-            // superclass field.
-            // check up the superclass hierarchy
-            Class[] ints = cls.getInterfaces();
+        }
+        // check the public interface case. This must be manually searched for
+        // incase there is a public supersuperclass field hidden by a 
private/package
+        // superclass field.
+        Field match = null;
+        for (Class acls = cls; acls != null; acls = acls.getSuperclass()) {
+            Class[] ints = acls.getInterfaces();
             for (int i = 0; i < ints.length; i++) {
                 // getField is fine here, because everything is public, and 
thus it works
                 try {
-                    Field field = ints[i].getField(fieldName);
-                    return field;
-                    
+                    Field test = ints[i].getField(fieldName);
+                    if (match != null) {
+                        if 
(match.getDeclaringClass().equals(test.getDeclaringClass())) {
+                            continue;
+                        }
+                        throw new IllegalArgumentException(
+                                "Reference to field "
+                                        + fieldName
+                                        + " is ambiguous relative to "
+                                        + cls
+                                        + "; a matching field exists on two or 
more parent interfaces.");
+                    }
+                    match = test;
                 } catch (NoSuchFieldException ex) {
                     // ignore
                 }
             }
-            if (match != null) {
-                return match;
-            }
-            throw new NoSuchFieldException("The field '" + fieldName + "' 
could not be found");
-    
-        } catch (ReflectionException ex) {
-            throw ex;
-        } catch (LinkageError ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field", cls.getName(), null, fieldName), ex);
-        } catch (Exception ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field", cls.getName(), null, fieldName), ex);
         }
+        return match;
     }
-    
-    //-----------------------------------------------------------------------
+
     /**
      * Gets an accessible <code>Field</code> by name respecting scope.
      * Only the specified class will be considered.
@@ -161,25 +147,23 @@
      * @param fieldName  the field name to obtain
      * @return the Field object
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
      */
-    public static Field getFieldExact(Class cls, String fieldName) {
-        return getFieldExact(cls, fieldName, false);
+    public static Field getDeclaredField(Class cls, String fieldName) {
+        return getDeclaredField(cls, fieldName, false);
     }
-    
+
     /**
      * Gets an accessible <code>Field</code> by name breaking scope
      * if requested. Only the specified class will be considered.
      *
      * @param cls  the class to reflect, must not be null
      * @param fieldName  the field name to obtain
-     * @param breakScope  whether to break scope restrictions using the
+     * @param forceAccess  whether to break scope restrictions using the
      *  <code>setAccessible</code> method. False will only match public fields.
      * @return the Field object
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
      */
-    public static Field getFieldExact(Class cls, String fieldName, boolean 
breakScope) {
+    public static Field getDeclaredField(Class cls, String fieldName, boolean 
forceAccess) {
         if (cls == null) {
             throw new IllegalArgumentException("The class must not be null");
         }
@@ -189,160 +173,81 @@
         try {
             // only consider the specified class by using getDeclaredField()
             Field field = cls.getDeclaredField(fieldName);
-            if (Modifier.isPublic(field.getModifiers()) == false) {
-                if (breakScope) {
+            if (!MemberUtils.isAccessible(field)) {
+                if (forceAccess) {
                     field.setAccessible(true);
                 } else {
-                    throw new IllegalAccessException("The field '" + fieldName 
+ "' was found, but it's scope prevents direct access by reflection");
+                    return null;
                 }
             }
             return field;
-    
-        } catch (ReflectionException ex) {
-            throw ex;
-        } catch (LinkageError ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field", cls.getName(), null, fieldName), ex);
-        } catch (Exception ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field", cls.getName(), null, fieldName), ex);
+        } catch (NoSuchFieldException e) {
         }
+        return null;
     }
-    
-    //-----------------------------------------------------------------------
+
     /**
-     * Gets a static Field value from a <code>Field</code> object.
-     * 
-     * @param field  the field to use
+     * Read an accessible static Field.
+     * @param field to read
      * @return the field value
      * @throws IllegalArgumentException if the field is null or not static
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the field is not accessible
      */
-    public static Object getStaticFieldValue(Field field) {
-        if (field == null) {
-            throw new IllegalArgumentException("The field must not be null");
-        }
-        if (Modifier.isStatic(field.getModifiers()) == false) {
-            throw new IllegalArgumentException("The field '" + field.getName() 
+ "' is not static");
-        }
-        return getFieldValue(field, (Object) null, false);
+    public static Object readStaticField(Field field) throws 
IllegalAccessException {
+        return readStaticField(field, false);
     }
-    
+
     /**
-     * Gets a static Field value from a <code>Field</code> object.
-     * 
-     * @param field  the field to use
-     * @param breakScope  whether to break scope restrictions using the
-     *  <code>setAccessible</code> method. <code>False</code> will only
-     *  match public methods.
+     * Read a static Field.
+     * @param field to read
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method.
      * @return the field value
      * @throws IllegalArgumentException if the field is null or not static
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the field is not made accessible
      */
-    public static Object getStaticFieldValue(Field field, boolean breakScope) {
+    public static Object readStaticField(Field field, boolean forceAccess) 
throws IllegalAccessException {
         if (field == null) {
             throw new IllegalArgumentException("The field must not be null");
         }
-        if (Modifier.isStatic(field.getModifiers()) == false) {
+        if (!Modifier.isStatic(field.getModifiers())) {
             throw new IllegalArgumentException("The field '" + field.getName() 
+ "' is not static");
         }
-        return getFieldValue(field, (Object) null, breakScope);
-    }
-    
-    /**
-     * Gets a Field value from a <code>Field</code> object.
-     * 
-     * @param field  the field to use
-     * @param object  the object to call on, may be null for static fields
-     * @return the field value
-     * @throws IllegalArgumentException if the field is null
-     * @throws ReflectionException if an error occurs during reflection
-     */
-    public static Object getFieldValue(Field field, Object object) {
-        return getFieldValue(field, object, false);
+        return readField(field, (Object) null, forceAccess);
     }
-    
-    /**
-     * Gets a Field value from a Field object.
-     * 
-     * @param field  the field to use
-     * @param object  the object to call on, may be null for static fields
-     * @param breakScope  whether to break scope restrictions using the
-     *  <code>setAccessible</code> method. <code>False</code> will only
-     *  match public methods.
-     * @return the field value
-     * @throws IllegalArgumentException if the field is null
-     * @throws ReflectionException if an error occurs during reflection
-     */
-    public static Object getFieldValue(Field field, Object object, boolean 
breakScope) {
-        if (field == null) {
-            throw new IllegalArgumentException("The field must not be null");
-        }
-        try {
-            if (breakScope && Modifier.isPublic(field.getModifiers()) == 
false) {
-                field.setAccessible(true);
-            }
-            return field.get(object);
-    
-        } catch (ReflectionException ex) {
-            throw ex;
-        } catch (LinkageError ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field value", 
field.getDeclaringClass().getName(), null, field.getName()), ex);
-        } catch (Exception ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field value", 
field.getDeclaringClass().getName(), null, field.getName()), ex);
-        }
-    }
-    
-    //-----------------------------------------------------------------------
+
     /**
-     * Gets a static Field value by name. The field must be public.
-     * Superclasses will be considered.
-     *
+     * Read the named public static field. Superclasses will be considered.
      * @param cls  the class to reflect, must not be null
      * @param fieldName  the field name to obtain
      * @return the value of the field
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the field is not accessible
      */
-    public static Object getStaticFieldValue(Class cls, String fieldName) {
-        return getStaticFieldValue(cls, fieldName, false);
+    public static Object readStaticField(Class cls, String fieldName) throws 
IllegalAccessException {
+        return readStaticField(cls, fieldName, false);
     }
-    
+
     /**
-     * Gets a static Field value by name. Only the specified class
-     * will be considered.
-     *
+     * Read the named static field. Superclasses will be considered.
      * @param cls  the class to reflect, must not be null
      * @param fieldName  the field name to obtain
-     * @param breakScope  whether to break scope restrictions using the
+     * @param forceAccess  whether to break scope restrictions using the
      *  <code>setAccessible</code> method. <code>False</code> will only
      *  match public fields.
      * @return the Field object
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the field is not made accessible
      */
-    public static Object getStaticFieldValue(Class cls, String fieldName, 
boolean breakScope) {
-        try {
-            Field field = getField(cls, fieldName, breakScope);
-            if (Modifier.isStatic(field.getModifiers()) == false) {
-                throw new NoSuchMethodException("The field '" + fieldName + "' 
is not static");
-            }
-            return getStaticFieldValue(field, breakScope);
-            
-        } catch (ReflectionException ex) {
-            throw ex;
-        } catch (LinkageError ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field value", cls.getName(), null, fieldName), 
ex);
-        } catch (Exception ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field value", cls.getName(), null, fieldName), 
ex);
+    public static Object readStaticField(Class cls, String fieldName, boolean 
forceAccess) throws IllegalAccessException {
+        Field field = getField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate field " + 
fieldName + " on " + cls);
         }
+        //already forced access above, don't repeat it here:
+        return readStaticField(field, false);
     }
-    
-    //-----------------------------------------------------------------------
+
     /**
      * Gets a static Field value by name. The field must be public.
      * Only the specified class will be considered.
@@ -351,108 +256,350 @@
      * @param fieldName  the field name to obtain
      * @return the value of the field
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the field is not accessible
      */
-    public static Object getStaticFieldValueExact(Class cls, String fieldName) 
{
-        return getStaticFieldValueExact(cls, fieldName, false);
+    public static Object readDeclaredStaticField(Class cls, String fieldName) 
throws IllegalAccessException {
+        return readDeclaredStaticField(cls, fieldName, false);
     }
-    
+
     /**
      * Gets a static Field value by name. Only the specified class will
      * be considered.
      *
      * @param cls  the class to reflect, must not be null
      * @param fieldName  the field name to obtain
-     * @param breakScope  whether to break scope restrictions using the
+     * @param forceAccess  whether to break scope restrictions using the
      *  <code>setAccessible</code> method. <code>False</code> will only
      *  match public fields.
      * @return the Field object
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the field is not made accessible
      */
-    public static Object getStaticFieldValueExact(Class cls, String fieldName, 
boolean breakScope) {
-        try {
-            Field field = getFieldExact(cls, fieldName, breakScope);
-            if (Modifier.isStatic(field.getModifiers()) == false) {
-                throw new NoSuchMethodException("The field '" + fieldName + "' 
is not static");
-            }
-            return getStaticFieldValue(field, breakScope);
-            
-        } catch (ReflectionException ex) {
-            throw ex;
-        } catch (LinkageError ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field value", cls.getName(), null, fieldName), 
ex);
-        } catch (Exception ex) {
-            throw new ReflectionException(ReflectionUtils.getThrowableText(
-                ex, "getting field value", cls.getName(), null, fieldName), 
ex);
+    public static Object readDeclaredStaticField(Class cls, String fieldName, 
boolean forceAccess)
+            throws IllegalAccessException {
+        Field field = getDeclaredField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate declared field " 
+ cls.getName() + "." + fieldName);
         }
+        //already forced access above, don't repeat it here:
+        return readStaticField(field, false);
     }
-    
-    //-----------------------------------------------------------------------
+
     /**
-     * Gets a Field value by name. The field must be public. Superclasses
-     * will be considered.
-     *
-     * @param object  the object to reflect, must not be null
+     * Read an accessible Field.
+     * @param field  the field to use
+     * @param target  the object to call on, may be null for static fields
+     * @return the field value
+     * @throws IllegalArgumentException if the field is null
+     * @throws IllegalAccessException if the field is not accessible
+     */
+    public static Object readField(Field field, Object target) throws 
IllegalAccessException {
+        return readField(field, target, false);
+    }
+
+    /**
+     * Read a Field.
+     * @param field  the field to use
+     * @param target  the object to call on, may be null for static fields
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method.
+     * @return the field value
+     * @throws IllegalArgumentException if the field is null
+     * @throws IllegalAccessException if the field is not made accessible
+     */
+    public static Object readField(Field field, Object target, boolean 
forceAccess) throws IllegalAccessException {
+        if (field == null) {
+            throw new IllegalArgumentException("The field must not be null");
+        }
+        if (forceAccess && !field.isAccessible()) {
+            field.setAccessible(true);
+        } else {
+            MemberUtils.setAccessibleWorkaround(field);
+        }
+        return field.get(target);
+    }
+
+    /**
+     * Read the named public field. Superclasses will be considered.
+     * @param target  the object to reflect, must not be null
      * @param fieldName  the field name to obtain
      * @return the value of the field
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the named field is not public
      */
-    public static Object getFieldValue(Object object, String fieldName) {
-        return getFieldValue(object, fieldName, false);
+    public static Object readField(Object target, String fieldName) throws 
IllegalAccessException {
+        return readField(target, fieldName, false);
     }
-    
+
     /**
-     * Gets a Field value by name. Only the specified class will be
-     * considered.
-     *
-     * @param object  the object to reflect, must not be null
+     * Read the named field. Superclasses will be considered.
+     * @param target  the object to reflect, must not be null
      * @param fieldName  the field name to obtain
-     * @param breakScope  whether to break scope restrictions using the
+     * @param forceAccess  whether to break scope restrictions using the
      *  <code>setAccessible</code> method. <code>False</code> will only
      *  match public fields.
-     * @return the Field object
+     * @return the field value
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the named field is not made accessible
      */
-    public static Object getFieldValue(Object object, String fieldName, 
boolean breakScope) {
-        Field field = getField(object.getClass(), fieldName, breakScope);
-        return getFieldValue(field, object, breakScope);
+    public static Object readField(Object target, String fieldName, boolean 
forceAccess) throws IllegalAccessException {
+        if (target == null) {
+            throw new IllegalArgumentException("target object must not be 
null");
+        }
+        Class cls = target.getClass();
+        Field field = getField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate field " + 
fieldName + " on " + cls);
+        }
+        //already forced access above, don't repeat it here:
+        return readField(field, target);
     }
-    
-    //-----------------------------------------------------------------------
+
     /**
-     * Gets a Field value by name. The field must be public.
-     * Only the class of the specified object will be considered.
-     *
-     * @param object  the object to reflect, must not be null
+     * Read the named public field. Only the class of the specified object 
will be considered.
+     * @param target  the object to reflect, must not be null
      * @param fieldName  the field name to obtain
      * @return the value of the field
      * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalAccessException if the named field is not public
      */
-    public static Object getFieldValueExact(Object object, String fieldName) {
-        return getFieldValueExact(object, fieldName, false);
+    public static Object readDeclaredField(Object target, String fieldName) 
throws IllegalAccessException {
+        return readDeclaredField(target, fieldName, false);
     }
-    
+
     /**
      * <p<>Gets a Field value by name. Only the class of the specified
      * object will be considered.
      *
-     * @param object  the object to reflect, must not be null
+     * @param target  the object to reflect, must not be null
      * @param fieldName  the field name to obtain
-     * @param breakScope  whether to break scope restrictions using the
+     * @param forceAccess  whether to break scope restrictions using the
      *  <code>setAccessible</code> method. <code>False</code> will only
      *  match public fields.
      * @return the Field object
-     * @throws IllegalArgumentException if the class or field name is null
-     * @throws ReflectionException if an error occurs during reflection
+     * @throws IllegalArgumentException if <code>target</code> or 
<code>fieldName</code> is null
+     * @throws IllegalAccessException if the field is not made accessible
+     */
+    public static Object readDeclaredField(Object target, String fieldName, 
boolean forceAccess) throws IllegalAccessException {
+        if (target == null) {
+            throw new IllegalArgumentException("target object must not be 
null");
+        }
+        Class cls = target.getClass();
+        Field field = getDeclaredField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate declared field " 
+ cls.getName() + "." + fieldName);
+        }
+        //already forced access above, don't repeat it here:
+        return readField(field, target);
+    }
+
+    /**
+     * Write a public static Field.
+     * @param field to write
+     * @param value to set
+     * @throws IllegalArgumentException if the field is null or not static
+     * @throws IllegalAccessException if the field is not public or is final
+     */
+    public static void writeStaticField(Field field, Object value) throws 
IllegalAccessException {
+        writeStaticField(field, value, false);
+    }
+
+    /**
+     * Write a static Field.
+     * @param field to write
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if the field is null or not static
+     * @throws IllegalAccessException if the field is not made accessible or 
is final
+     */
+    public static void writeStaticField(Field field, Object value, boolean 
forceAccess) throws IllegalAccessException {
+        if (field == null) {
+            throw new IllegalArgumentException("The field must not be null");
+        }
+        if (!Modifier.isStatic(field.getModifiers())) {
+            throw new IllegalArgumentException("The field '" + field.getName() 
+ "' is not static");
+        }
+        writeField(field, (Object) null, value, forceAccess);
+    }
+
+    /**
+     * Write a named public static Field. Superclasses will be considered.
+     * @param cls Class on which the Field is to be found
+     * @param fieldName to write
+     * @param value to set
+     * @throws IllegalArgumentException if the field cannot be located or is 
not static
+     * @throws IllegalAccessException if the field is not public or is final
+     */
+    public static void writeStaticField(Class cls, String fieldName, Object 
value) throws IllegalAccessException {
+        writeStaticField(cls, fieldName, value, false);
+    }
+
+    /**
+     * Write a named static Field. Superclasses will be considered.
+     * @param cls Class on which the Field is to be found
+     * @param fieldName to write
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if the field cannot be located or is 
not static
+     * @throws IllegalAccessException if the field is not made accessible or 
is final
      */
-    public static Object getFieldValueExact(Object object, String fieldName, 
boolean breakScope) {
-        Field field = getFieldExact(object.getClass(), fieldName, breakScope);
-        return getFieldValue(field, object, breakScope);
+    public static void writeStaticField(Class cls, String fieldName, Object 
value, boolean forceAccess)
+            throws IllegalAccessException {
+        Field field = getField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate field " + 
fieldName + " on " + cls);
+        }
+        //already forced access above, don't repeat it here:
+        writeStaticField(field, value);
+    }
+
+    /**
+     * Write a named public static Field. Only the specified class will be 
considered.
+     * @param cls Class on which the Field is to be found
+     * @param fieldName to write
+     * @param value to set
+     * @throws IllegalArgumentException if the field cannot be located or is 
not static
+     * @throws IllegalAccessException if the field is not public or is final
+     */
+    public static void writeDeclaredStaticField(Class cls, String fieldName, 
Object value)
+            throws IllegalAccessException {
+        writeDeclaredStaticField(cls, fieldName, value, false);
+    }
+
+    /**
+     * Write a named static Field. Only the specified class will be considered.
+     * @param cls Class on which the Field is to be found
+     * @param fieldName to write
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if the field cannot be located or is 
not static
+     * @throws IllegalAccessException if the field is not made accessible or 
is final
+      */
+    public static void writeDeclaredStaticField(Class cls, String fieldName, 
Object value, boolean forceAccess)
+            throws IllegalAccessException {
+        Field field = getDeclaredField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate declared field " 
+ cls.getName() + "." + fieldName);
+        }
+        //already forced access above, don't repeat it here:
+        writeField(field, (Object) null, value);
+    }
+
+    /**
+     * Write an accessible field.
+     * @param field to write
+     * @param target  the object to call on, may be null for static fields
+     * @param value to set
+     * @throws IllegalArgumentException if the field is null
+     * @throws IllegalAccessException if the field is not accessible or is 
final
+     */
+    public static void writeField(Field field, Object target, Object value) 
throws IllegalAccessException {
+        writeField(field, target, value, false);
+    }
+
+    /**
+     * Write a field.
+     * @param field to write
+     * @param target  the object to call on, may be null for static fields
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if the field is null
+     * @throws IllegalAccessException if the field is not made accessible or 
is final
+     */
+    public static void writeField(Field field, Object target, Object value, 
boolean forceAccess) throws IllegalAccessException {
+        if (field == null) {
+            throw new IllegalArgumentException("The field must not be null");
+        }
+        if (forceAccess && !field.isAccessible()) {
+            field.setAccessible(true);
+        } else {
+            MemberUtils.setAccessibleWorkaround(field);
+        }
+        field.set(target, value);
+    }
+
+    /**
+     * Write a public field. Superclasses will be considered.
+     * @param target  the object to reflect, must not be null
+     * @param fieldName  the field name to obtain
+     * @param value to set
+     * @throws IllegalArgumentException if <code>target</code> or 
<code>fieldName</code> is null
+     * @throws IllegalAccessException if the field is not accessible
+     */
+    public static void writeField(Object target, String fieldName, Object 
value) throws IllegalAccessException {
+        writeField(target, fieldName, value, false);
+    }
+
+    /**
+     * Write a field. Superclasses will be considered.
+     * @param target  the object to reflect, must not be null
+     * @param fieldName  the field name to obtain
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if <code>target</code> or 
<code>fieldName</code> is null
+     * @throws IllegalAccessException if the field is not made accessible
+     */
+    public static void writeField(Object target, String fieldName, Object 
value, boolean forceAccess)
+            throws IllegalAccessException {
+        if (target == null) {
+            throw new IllegalArgumentException("target object must not be 
null");
+        }
+        Class cls = target.getClass();
+        Field field = getField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate declared field " 
+ cls.getName() + "." + fieldName);
+        }
+        //already forced access above, don't repeat it here:
+        writeField(field, target, value);
+    }
+
+    /**
+     * Write a public field. Only the specified class will be considered.
+     * @param target  the object to reflect, must not be null
+     * @param fieldName  the field name to obtain
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if <code>target</code> or 
<code>fieldName</code> is null
+     * @throws IllegalAccessException if the field is not made accessible
+     */
+    public static void writeDeclaredField(Object target, String fieldName, 
Object value) throws IllegalAccessException {
+        writeDeclaredField(target, fieldName, value, false);
+    }
+
+    /**
+     * Write a public field. Only the specified class will be considered.
+     * @param target  the object to reflect, must not be null
+     * @param fieldName  the field name to obtain
+     * @param value to set
+     * @param forceAccess  whether to break scope restrictions using the
+     *  <code>setAccessible</code> method. <code>False</code> will only
+     *  match public fields.
+     * @throws IllegalArgumentException if <code>target</code> or 
<code>fieldName</code> is null
+     * @throws IllegalAccessException if the field is not made accessible
+     */
+    public static void writeDeclaredField(Object target, String fieldName, 
Object value, boolean forceAccess)
+            throws IllegalAccessException {
+        if (target == null) {
+            throw new IllegalArgumentException("target object must not be 
null");
+        }
+        Class cls = target.getClass();
+        Field field = getDeclaredField(cls, fieldName, forceAccess);
+        if (field == null) {
+            throw new IllegalArgumentException("Cannot locate declared field " 
+ cls.getName() + "." + fieldName);
+        }
+        //already forced access above, don't repeat it here:
+        writeField(field, target, value);
     }
-    
 }

Modified: 
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/MemberUtils.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/MemberUtils.java?rev=653618&r1=653617&r2=653618&view=diff
==============================================================================
--- 
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/MemberUtils.java
 (original)
+++ 
commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/reflect/MemberUtils.java
 Mon May  5 15:12:48 2008
@@ -37,6 +37,8 @@
 abstract class MemberUtils {
     // TODO extract an interface to implement compareParameterSets(...)?
 
+    private static final int ACCESS_TEST = Modifier.PUBLIC | 
Modifier.PROTECTED | Modifier.PRIVATE;
+
     private static final Method IS_SYNTHETIC;
     static {
         Method isSynthetic = null;
@@ -60,8 +62,8 @@
      * XXX Default access superclass workaround
      *
      * When a public class has a default access superclass with public
-     * methods/constructors, these members are accessible. Calling them from
-     * compiled code works fine. Unfortunately, using reflection to invoke 
these
+     * 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) to prevent access even when the
      * modifer is public. Calling setAccessible(true) solves the problem
      * but will only work from sufficiently privileged code. Better
@@ -69,7 +71,11 @@
      * @param o the AccessibleObject to set as accessible
      */
     static void setAccessibleWorkaround(AccessibleObject o) {
-        if (!o.isAccessible() && SystemUtils.isJavaVersionAtLeast(1.4f)) {
+        if (o == null || o.isAccessible()) {
+            return;
+        }
+        Member m = (Member) o;
+        if (Modifier.isPublic(m.getModifiers()) && 
isPackageAccess(m.getDeclaringClass().getModifiers())) {
             try {
                 o.setAccessible(true);
             } catch (SecurityException e) {
@@ -79,6 +85,15 @@
     }
 
     /**
+     * Learn whether a given set of modifiers implies package access.
+     * @param modifiers to test
+     * @return true unless package/protected/private modifier detected
+     */
+    static boolean isPackageAccess(int modifiers) {
+        return (modifiers & ACCESS_TEST) == 0;
+    }
+
+    /**
      * Check a Member for basic accessibility.
      * @param m Member to check
      * @return true if <code>m</code> is accessible

Modified: 
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/AllLangTestSuite.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/AllLangTestSuite.java?rev=653618&r1=653617&r2=653618&view=diff
==============================================================================
--- 
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/AllLangTestSuite.java
 (original)
+++ 
commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/AllLangTestSuite.java
 Mon May  5 15:12:48 2008
@@ -26,6 +26,7 @@
 import org.apache.commons.lang.exception.ExceptionTestSuite;
 import org.apache.commons.lang.math.MathTestSuite;
 import org.apache.commons.lang.mutable.MutableTestSuite;
+import org.apache.commons.lang.reflect.ReflectTestSuite;
 import org.apache.commons.lang.text.TextTestSuite;
 import org.apache.commons.lang.time.TimeTestSuite;
 
@@ -64,6 +65,7 @@
         suite.addTest(ExceptionTestSuite.suite());
         suite.addTest(MathTestSuite.suite());
         suite.addTest(MutableTestSuite.suite());
+        suite.addTest(ReflectTestSuite.suite());
         suite.addTest(TextTestSuite.suite());
         suite.addTest(TimeTestSuite.suite());
         return suite;


Reply via email to