Title: [2092] trunk/xstream/src: No converter should throw an exception at initialization, just because it cannot use reflection or it will not find a declared field or method (XSTR-200, XSTR-566).

Diff

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2013 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -44,18 +44,7 @@
  */
 public class PropertiesConverter implements Converter {
 
-    private final static Field defaultsField;
-    static {
-        Field field = null;
-        try {
-            field = Fields.find(Properties.class, "defaults");
-        } catch (SecurityException ex) {
-            // ignore, no access possible with current SecurityManager
-        } catch (RuntimeException ex) {
-            throw new ExceptionInInitializerError("No field 'defaults' in type Properties found");
-        }
-        defaultsField = field;
-    }
+    private final static Field defaultsField = Fields.locate(Properties.class, Properties.class, false);
     private final boolean sort;
 
     public PropertiesConverter() {

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2010, 2011 XStream Committers.
+ * Copyright (C) 2006, 2007, 2010, 2011, 2013 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -15,6 +15,7 @@
 import com.thoughtworks.xstream.converters.MarshallingContext;
 import com.thoughtworks.xstream.converters.UnmarshallingContext;
 import com.thoughtworks.xstream.core.JVM;
+import com.thoughtworks.xstream.core.util.Fields;
 import com.thoughtworks.xstream.core.util.HierarchicalStreams;
 import com.thoughtworks.xstream.core.util.PresortedMap;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
@@ -46,30 +47,8 @@
     }
 
     private final static Comparator NULL_MARKER = new NullComparator();
-    
-    private final static Field comparatorField;
-    static {
-        Field cmpField = null;
-        try {
-            Field[] fields = TreeMap.class.getDeclaredFields();
-            for (int i = 0; i < fields.length; i++ ) {
-                if (fields[i].getType() == Comparator.class) {
-                    // take the fist member of type "Comparator"
-                    cmpField = fields[i];
-                    cmpField.setAccessible(true);
-                    break;
-                }
-            }
-            if (cmpField == null) {
-                throw new ExceptionInInitializerError("Cannot detect comparator field of TreeMap");
-            }
+    private final static Field comparatorField = Fields.locate(TreeMap.class, Comparator.class, false);
 
-        } catch (SecurityException ex) {
-            // ignore, no access possible with current SecurityManager
-        }
-        comparatorField = cmpField;
-    }
-
     public TreeMapConverter(Mapper mapper) {
         super(mapper);
     }

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2010, 2011 XStream Committers.
+ * Copyright (C) 2006, 2007, 2010, 2011, 2013 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -15,6 +15,7 @@
 import com.thoughtworks.xstream.converters.MarshallingContext;
 import com.thoughtworks.xstream.converters.UnmarshallingContext;
 import com.thoughtworks.xstream.core.JVM;
+import com.thoughtworks.xstream.core.util.Fields;
 import com.thoughtworks.xstream.core.util.PresortedSet;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
@@ -40,30 +41,8 @@
  */
 public class TreeSetConverter extends CollectionConverter {
     private transient TreeMapConverter treeMapConverter;  
-    private final static Field sortedMapField;
-    static {
-        Field smField = null;
-        if (!JVM.hasOptimizedTreeSetAddAll()) {
-            try {
-                Field[] fields = TreeSet.class.getDeclaredFields();
-                for (int i = 0; i < fields.length; i++ ) {
-                    if (SortedMap.class.isAssignableFrom(fields[i].getType())) {
-                        // take the fist member assignable to type "SortedMap"
-                        smField = fields[i];
-                        smField.setAccessible(true);
-                        break;
-                    }
-                }
-                if (smField == null) {
-                    throw new ExceptionInInitializerError("Cannot detect field of backing map of TreeSet");
-                }
-    
-            } catch (SecurityException ex) {
-                // ignore, no access possible with current SecurityManager
-            }
-        }
-        sortedMapField = smField;
-    }
+    private final static Field sortedMapField = 
+       JVM.hasOptimizedTreeSetAddAll() ? Fields.locate(TreeSet.class, SortedMap.class, false) : null;
 
     public TreeSetConverter(Mapper mapper) {
         super(mapper);

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2013 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -37,30 +37,8 @@
  */
 public class EnumMapConverter extends MapConverter {
 
-    private final static Field typeField;
-    static {
-        // field name is "keyType" in Sun JDK, but different in IKVM
-        Field assumedTypeField = null;
-        try {
-            Field[] fields = EnumMap.class.getDeclaredFields();
-            for (int i = 0; i < fields.length; i++ ) {
-                if (fields[i].getType() == Class.class) {
-                    // take the fist member of type "Class"
-                    assumedTypeField = fields[i];
-                    assumedTypeField.setAccessible(true);
-                    break;
-                }
-            }
-            if (assumedTypeField == null) {
-                throw new ExceptionInInitializerError("Cannot detect key type of EnumMap");
-            }
+    private final static Field typeField = Fields.locate(EnumMap.class, Class.class, false);
 
-        } catch (SecurityException ex) {
-            // ignore, no access possible with current SecurityManager
-        }
-        typeField = assumedTypeField;
-    }
-
     public EnumMapConverter(Mapper mapper) {
         super(mapper);
     }

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -39,29 +39,7 @@
  */
 public class EnumSetConverter implements Converter {
 
-    private final static Field typeField;
-    static {
-        // field name is "elementType" in Sun JDK, but different in Harmony
-        Field assumedTypeField = null;
-        try {
-            Field[] fields = EnumSet.class.getDeclaredFields();
-            for (int i = 0; i < fields.length; i++ ) {
-                if (fields[i].getType() == Class.class) {
-                    // take the fist member of type "Class"
-                    assumedTypeField = fields[i];
-                    assumedTypeField.setAccessible(true);
-                    break;
-                }
-            }
-            if (assumedTypeField == null) {
-                throw new ExceptionInInitializerError("Cannot detect element type of EnumSet");
-            }
-        } catch (SecurityException ex) {
-            // ignore, no access possible with current SecurityManager
-        }
-        typeField = assumedTypeField;
-    }
-    
+    private final static Field typeField = Fields.locate(EnumSet.class, Class.class, false);
     private final Mapper mapper;
 
     public EnumSetConverter(Mapper mapper) {

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -39,23 +39,12 @@
 
     private ClassLoaderReference classLoaderReference;
     private Mapper mapper;
-    private static final Field HANDLER;
+    private static final Field HANDLER = Fields.locate(Proxy.class, InvocationHandler.class, false);
     private static final InvocationHandler DUMMY = new InvocationHandler() {
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             return null;
         }
     };
-    
-    static {
-        Field field = null; 
-        try {
-            field = Proxy.class.getDeclaredField("h");
-            field.setAccessible(true);
-        } catch (NoSuchFieldException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-        HANDLER = field;
-    }
 
     /**
      * @deprecated As of upcoming use {@link #DynamicProxyConverter(Mapper, ClassLoaderReference)}
@@ -131,10 +120,17 @@
         }
         Class[] interfacesAsArray = new Class[interfaces.size()];
         interfaces.toArray(interfacesAsArray);
-        Object proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, DUMMY);
+        Object proxy = null;
+        if (HANDLER != null) { // we will not be able to resolve references to the proxy
+            proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, DUMMY);
+        }
         handler = (InvocationHandler) context.convertAnother(proxy, handlerType);
         reader.moveUp();
-        Fields.write(HANDLER, proxy, handler);
+        if (HANDLER != null) {
+            Fields.write(HANDLER, proxy, handler);
+        } else {
+            proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, handler);
+        }
         return proxy;
     }
 }

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -10,7 +10,9 @@
  */
 package com.thoughtworks.xstream.converters.reflection;
 
+import com.thoughtworks.xstream.converters.ConversionException;
 import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
+import com.thoughtworks.xstream.core.util.Fields;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -32,22 +34,33 @@
 public class AbstractAttributedCharacterIteratorAttributeConverter extends
     AbstractSingleValueConverter {
 
+    private static final Map instanceMaps = new HashMap();
     private static final Method getName;
     static {
+        Method method = null;
         try {
-            getName = AttributedCharacterIterator.Attribute.class.getDeclaredMethod(
+            method = AttributedCharacterIterator.Attribute.class.getDeclaredMethod(
                 "getName", (Class[])null);
+            if (!method.isAccessible()) {
+                method.setAccessible(true);
+            }
+        } catch (SecurityException e) {
+            // ignore for now
         } catch (NoSuchMethodException e) {
-            throw new ExceptionInInitializerError("Missing AttributedCharacterIterator.Attribute.getName()");
+            // ignore for now
         }
+        getName = method;
     }
 
     private final Class type;
     private transient Map attributeMap;
-    private transient FieldDictionary fieldDictionary;
 
     public AbstractAttributedCharacterIteratorAttributeConverter(final Class type) {
         super();
+        if (!AttributedCharacterIterator.Attribute.class.isAssignableFrom(type)) {
+            throw new IllegalArgumentException(type.getName()
+                + " is not a " + AttributedCharacterIterator.Attribute.class.getName());
+        }
         this.type = type;
         readResolve();
     }
@@ -57,40 +70,72 @@
     }
 
     public String toString(final Object source) {
-        AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute)source;
-        try {
-            if (!getName.isAccessible()) {
-                getName.setAccessible(true);
+        return getName((AttributedCharacterIterator.Attribute)source);
+    }
+
+    private String getName(AttributedCharacterIterator.Attribute attribute) {
+        Exception ex = null;
+        if (getName != null) {
+            try {
+                return (String)getName.invoke(attribute, (Object[])null);
+            } catch (IllegalAccessException e) {
+                ex = e;
+            } catch (InvocationTargetException e) {
+                ex = e;
             }
-            return (String)getName.invoke(attribute, (Object[])null);
-        } catch (IllegalAccessException e) {
-            throw new ObjectAccessException(
-                "Cannot get name of AttributedCharacterIterator.Attribute", e);
-        } catch (InvocationTargetException e) {
-            throw new ObjectAccessException(
-                "Cannot get name of AttributedCharacterIterator.Attribute", e
-                    .getTargetException());
         }
+        String s = attribute.toString();
+        String className = attribute.getClass().getName();
+        if (s.startsWith(className)) {
+            return s.substring(className.length()+1, s.length()-1);
+        }
+        throw new ConversionException("Cannot find name of attribute of type " + className, ex);
     }
 
     public Object fromString(final String str) {
-        return attributeMap.get(str);
+        if (attributeMap.containsKey(str)) {
+            return attributeMap.get(str);
+        }
+        throw new ConversionException("Cannot find attribute of type " + type.getName() + " with name " + str);
     }
 
     private Object readResolve() {
-        fieldDictionary = new FieldDictionary();
-        attributeMap = new HashMap();
-        for (final Iterator iterator = fieldDictionary.fieldsFor(type); iterator
-            .hasNext();) {
-            final Field field = (Field)iterator.next();
-            if (field.getType() == type && Modifier.isStatic(field.getModifiers())) {
+        attributeMap = (Map)instanceMaps.get(type.getName());
+        if (attributeMap == null) {
+            attributeMap = new HashMap();
+            Field instanceMap = Fields.locate(type, Map.class, true);
+            if (instanceMap != null) {
                 try {
-                    final Object attribute = field.get(null);
-                    attributeMap.put(toString(attribute), attribute);
-                } catch (IllegalAccessException e) {
-                    throw new ObjectAccessException("Cannot get object of " + field, e);
+                    Map map = (Map)Fields.read(instanceMap, null);
+                    if (map != null) {
+                        boolean valid = true;
+                        for (Iterator iter = map.entrySet().iterator(); valid && iter.hasNext(); ) {
+                            Map.Entry entry = (Map.Entry)iter.next(); 
+                            valid = entry.getKey().getClass() == String.class && entry.getValue().getClass() == type;
+                        }
+                        if (valid) {
+                            attributeMap.putAll(map);
+                        }
+                    }
+                } catch (ObjectAccessException e) {
                 }
             }
+            if (attributeMap.isEmpty()) {
+                try {
+                    Field[] fields = type.getDeclaredFields();
+                    for(int i = 0; i < fields.length; ++i) {
+                        if(fields[i].getType() == type == Modifier.isStatic(fields[i].getModifiers())) {
+                            AttributedCharacterIterator.Attribute attribute =
+                                    (AttributedCharacterIterator.Attribute)Fields.read(fields[i], null);
+                            attributeMap.put(toString(attribute), attribute);
+                        }
+                    }
+                } catch (SecurityException e) {
+                    attributeMap.clear();
+                } catch (ObjectAccessException e) {
+                    attributeMap.clear();
+                }
+            }
         }
         return this;
     }

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java (2091 => 2092)


--- trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009, 2011 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -12,6 +12,7 @@
 package com.thoughtworks.xstream.core.util;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 
 import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
 
@@ -20,8 +21,29 @@
  * wraps exception in XStreamExceptions.
  *
  * @author Joe Walnes
+ * @author J&ouml;rg Schaible
  */
 public class Fields {
+    public static Field locate(Class definedIn, Class fieldType, boolean isStatic) {
+        Field field = null;
+        try {
+            Field[] fields = definedIn.getDeclaredFields();
+            for(int i = 0; i < fields.length; ++i) {
+                if (Modifier.isStatic(fields[i].getModifiers()) == isStatic) {
+                    if (fieldType.isAssignableFrom(fields[i].getType())) {
+                        field = fields[i];
+                    }
+                }
+            }
+            if (field != null) {
+                field.setAccessible(true);
+            }
+        } catch (SecurityException e) {
+            // active SecurityManager
+        }
+        return field;
+    }
+
     public static Field find(Class type, String name) {
         try {
             Field result = type.getDeclaredField(name);
@@ -30,12 +52,7 @@
             }
             return result;
         } catch (NoSuchFieldException e) {
-            throw new IllegalArgumentException("Could not access "
-                + type.getName()
-                + "."
-                + name
-                + " field: "
-                + e.getMessage());
+            throw new IllegalArgumentException("Could not access " + type.getName() + "." + name + " field: " + e.getMessage());
         }
     }
 

Modified: trunk/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java (2091 => 2092)


--- trunk/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java	2013-07-04 22:18:43 UTC (rev 2091)
+++ trunk/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java	2013-07-04 23:12:27 UTC (rev 2092)
@@ -40,6 +40,7 @@
 
     protected void setUp() throws Exception {
         super.setUp();
+        // fonts should be serializable also with pure Java
         xstream = new XStream(new PureJavaReflectionProvider());
         in = new Font("Arial", Font.BOLD, 20);
     }

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to