Hi Michael,

On Jul 2, 2005, at 11:58 AM, Michael Bouschen wrote:

Hi Craig,

the changes look good!

I would like to propose a few improvements of the method mangleObject you changed. Maybe this should be an extra check in, because they are not related to the fix for JDO-77.
(1) We plan to add configuration running the TCK with a security manager. Then the reflection access of method mangleObject should be enclosed in a doPivileged block.

Done.

(2) The method checks for fields of specific types. Should we add date, BigDecimal, BigInteger, float, double, Float and Double?

Later. None of the identity classes uses these types.

(3) We could use 'else if' when checking the field types.

Done.

Please check the attached.

Thanks,

Craig

Index: test/java/org/apache/jdo/tck/JDO_Test.java
===================================================================
--- test/java/org/apache/jdo/tck/JDO_Test.java  (revision 208860)
+++ test/java/org/apache/jdo/tck/JDO_Test.java  (working copy)
@@ -20,10 +20,18 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Properties;
 import java.util.Vector;
 
@@ -749,54 +757,75 @@
         return NUM_STATES;
     }
 
-    /** This method mangles an object by changing all its public fields
+    /** This method mangles an object by changing all its non-static, 
+     *  non-final fields.
+     *  It returns true if the object was mangled, and false if there
+     *  are no fields to mangle.
      */
-    protected void mangleObject (Object oid) 
+    protected boolean mangleObject (Object oid) 
         throws Exception {
-        Class oidClass = oid.getClass();
-        Field[] fields = oidClass.getFields();
+        Field[] fields = getModifiableFields(oid);
+        if (fields.length == 0) return false;
         for (int i = 0; i < fields.length; ++i) {
             Field field = fields[i];
-            field.setAccessible(true);
-            if (debug) 
-                logger.debug("field" + i + " has name: " + field.getName() +
-                             " type: " + field.getType());
             Class fieldType = field.getType();
             if (fieldType == long.class) {
-                field.setLong(oid, 10000L);
+                field.setLong(oid, 10000L + field.getLong(oid));
+            } else if (fieldType == int.class) {
+                field.setInt(oid, 10000 + field.getInt(oid));
+            } else if (fieldType == short.class) {
+                field.setShort(oid, (short)(10000 + field.getShort(oid)));
+            } else if (fieldType == byte.class) {
+                field.setByte(oid, (byte)(100 + field.getByte(oid)));
+            } else if (fieldType == char.class) {
+                field.setChar(oid, (char)(10 + field.getChar(oid)));
+            } else if (fieldType == String.class) {
+                field.set(oid, "This is certainly a challenge" + 
(String)field.get(oid));
+            } else if (fieldType == Integer.class) {
+                field.set(oid, new Integer(10000 + 
((Integer)field.get(oid)).intValue()));
+            } else if (fieldType == Long.class) {
+                field.set(oid, new Long(10000L + 
((Long)field.get(oid)).longValue()));
+            } else if (fieldType == Short.class) {
+                field.set(oid, new Short((short)(10000 + 
((Short)field.get(oid)).shortValue())));
+            } else if (fieldType == Byte.class) {
+                field.set(oid, new Byte((byte)(100 + 
((Byte)field.get(oid)).byteValue())));
+            } else if (fieldType == Character.class) {
+                field.set(oid, new Character((char)(10 + 
((Character)(field.get(oid))).charValue())));
             }
-            if (fieldType == int.class) {
-                field.setInt(oid, 10000);
-            }
-            if (fieldType == short.class) {
-                field.setShort(oid, (short)10000);
-            }
-            if (fieldType == byte.class) {
-                field.setByte(oid, (byte)100);
-            }
-            if (fieldType == char.class) {
-                field.setChar(oid, '0');
-            }
-            if (fieldType == String.class) {
-                field.set(oid, "This is certainly a challenge");
-            }
-            if (fieldType == Integer.class) {
-                field.set(oid, new Integer(10000));
-            }
-            if (fieldType == Long.class) {
-                field.set(oid, new Long(10000L));
-            }
-            if (fieldType == Short.class) {
-                field.set(oid, new Short((short)10000));
-            }
-            if (fieldType == Byte.class) {
-                field.set(oid, new Byte((byte)100));
-            }
-            if (fieldType == Character.class) {
-                field.set(oid, new Character('0'));
-            }
         }
+        return true;
     }
+    
+    /** Returns modifiable Fields of the class of the parameter. 
+     * Fields are considered modifiable if they are not static or final.
+     * This method requires several permissions in order to run with
+     * a SecurityManager, hence the doPrivileged block:
+     * <ul>
+     * <li>ReflectPermission("suppressAccessChecks")</li>
+     * <li>RuntimePermission("accessDeclaredMembers")</li>
+     * </ul>
+     */
+    protected Field[] getModifiableFields(final Object obj) {
+        return (Field[])AccessController.doPrivileged(
+            new PrivilegedAction () {
+                public Object run () {
+                    Class cls = obj.getClass();
+                    List result = new ArrayList();
+                    Field[] fields = cls.getFields();
+                    for (int i = 0; i < fields.length; ++i) {
+                        Field field = fields[i];
+                        int modifiers = field.getModifiers();
+                        if (Modifier.isFinal(modifiers) ||
+                                Modifier.isStatic(modifiers))
+                            continue;
+                        field.setAccessible(true);
+                        result.add(field);
+                    }
+                    return result.toArray(new Field[result.size()]);
+                }
+            }
+        );
+    }
 
     /**
      * Returns <code>true</code> if the current test runs with application
Index: 
test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java
===================================================================
--- 
test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java
 (revision 208860)
+++ 
test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java
 (working copy)
@@ -16,7 +16,9 @@
  
 package org.apache.jdo.tck.lifecycle;
 
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 import javax.jdo.Extent;
 import javax.jdo.Transaction;
@@ -76,16 +78,45 @@
                                 "Extent for StateTransitionObj should not be 
empty");
                }
                extent.close(iter);
-    
-               for (int i=0; i<NUM_OBJECTS; i++)
-               {
-                       Object objId=pm.getObjectId(obj[i]);
-                       mangleObject(objId);
-                       Object objId2 = pm.getObjectId(obj[i]); // get another 
ObjectId copy
-                       if (objId.equals(objId2))
-                               fail(ASSERTION_FAILED,
-                                        "object Id has been changed");
+            int failures = 0;
+            StringBuffer report = new StringBuffer("Failures comparing 
oids.\n");
+               for (int i=0; i<NUM_OBJECTS; i++) {
+                       Object objId1=pm.getObjectId(obj[i]);
+                String before=objId1.toString();
+                int objId1HashCode = objId1.hashCode();
+                Object objId2=pm.getObjectId(obj[i]);
+                       if (!mangleObject(objId2)) {
+                    /* The object id class is immutable, so the test succeeds. 
*/
+                    break;
+                }
+                int objId2HashCode = objId2.hashCode();
+                       Object objId3 = pm.getObjectId(obj[i]); // get another 
ObjectId copy
+                       if (!(objId1.equals(objId3) && objId1HashCode != 
objId2HashCode)) {
+                    /* The object id obtained after mangling the second object 
id
+                     * must equal the original object id, and the mangling must
+                     * have changed the mangled id.
+                     */
+                    report.append("Index= ");
+                    report.append(i);
+                    report.append("\n");
+                    report.append(" before= ");
+                    report.append(before);
+                    report.append("\n");
+                    report.append("mangled= ");
+                    report.append(objId2.toString());
+                    report.append("\n");
+                    report.append("  after= ");
+                    report.append(objId3.toString());
+                    report.append("\n");
+                    ++failures;
+                }
                }
+            if (failures != 0) {
+                if (debug) {
+                    logger.debug(report.toString());
+                }
+                fail(ASSERTION_FAILED, "Failed to compare " + failures + " 
object ids.");
+            }
             pm.currentTransaction().commit();
         } finally {
             if (pm!=null && pm.currentTransaction().isActive()) {


Regards Michael


Hi,

Please review this patch. It fixes an illegal access exception when mangleObject tries to change a final field. The final field was added to the PCPoint$Oid class.

The fix checks for final and static modifiers on the field before it changes it.

I also changed the method to actually change each field, instead of simply changing its value to a constant.

Thanks,

Craig

------------------------------------------------------------------------

Index: test/java/org/apache/jdo/tck/JDO_Test.java
===================================================================
--- test/java/org/apache/jdo/tck/JDO_Test.java    (revision 208860)
+++ test/java/org/apache/jdo/tck/JDO_Test.java    (working copy)
@@ -757,43 +757,47 @@
        Field[] fields = oidClass.getFields();
        for (int i = 0; i < fields.length; ++i) {
            Field field = fields[i];
+            int modifiers = field.getModifiers();
+            if (java.lang.reflect.Modifier.isFinal(modifiers) ||
+                    java.lang.reflect.Modifier.isStatic(modifiers))
+                break;
            field.setAccessible(true);
            if (debug)                 logger.debug("field" + i + " has name: " + field.getName() +
                             " type: " + field.getType());
            Class fieldType = field.getType();
            if (fieldType == long.class) {
-                field.setLong(oid, 10000L);
+                field.setLong(oid, 10000L + field.getLong(oid));
            }
            if (fieldType == int.class) {
-                field.setInt(oid, 10000);
+                field.setInt(oid, 10000 + field.getInt(oid));
            }
            if (fieldType == short.class) {
-                field.setShort(oid, (short)10000);
+                field.setShort(oid, (short)(10000 + field.getShort(oid)));
            }
            if (fieldType == byte.class) {
-                field.setByte(oid, (byte)100);
+                field.setByte(oid, (byte)(100 + field.getByte(oid)));
            }
            if (fieldType == char.class) {
-                field.setChar(oid, '0');
+                field.setChar(oid, (char)(10 + field.getChar(oid)));
            }
            if (fieldType == String.class) {
-                field.set(oid, "This is certainly a challenge");
+                field.set(oid, "This is certainly a challenge" + (String)field.get(oid));
            }
            if (fieldType == Integer.class) {
-                field.set(oid, new Integer(10000));
+                field.set(oid, new Integer(10000 + ((Integer)field.get(oid)).intValue()));
            }
            if (fieldType == Long.class) {
-                field.set(oid, new Long(10000L));
+                field.set(oid, new Long(10000L + ((Long)field.get(oid)).longValue()));
            }
            if (fieldType == Short.class) {
-                field.set(oid, new Short((short)10000));
+                field.set(oid, new Short((short)(10000 + ((Short)field.get(oid)).shortValue())));
            }
            if (fieldType == Byte.class) {
-                field.set(oid, new Byte((byte)100));
+                field.set(oid, new Byte((byte)(100 + ((Byte)field.get(oid)).byteValue())));
            }
            if (fieldType == Character.class) {
-                field.set(oid, new Character('0'));
+                field.set(oid, new Character((char)(10 + ((Character)(field.get(oid))).charValue())));
            }
        }
    }

 


------------------------------------------------------------------------


Craig Russell

Architect, Sun Java Enterprise System http://java.sun.com/products/jdo


P.S. A good JDO? O, Gasp!





-- 
Michael Bouschen        [EMAIL PROTECTED] Engineering GmbH
mailto:[EMAIL PROTECTED]    http://www.tech.spree.de/
Tel.:++49/30/235 520-33        Buelowstr. 66            
Fax.:++49/30/2175 2012        D-10783 Berlin            



Craig Russell

Architect, Sun Java Enterprise System http://java.sun.com/products/jdo

408 276-5638 mailto:[EMAIL PROTECTED]

P.S. A good JDO? O, Gasp!


Attachment: smime.p7s
Description: S/MIME cryptographic signature



Reply via email to