Title: [2097] trunk: Implement support for aliasing JavaClassConverter, JavaFieldConverter and JavaMethodConverter (XSTR-578).

Diff

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java (2096 => 2097)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java	2013-07-08 22:36:06 UTC (rev 2096)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java	2013-07-12 16:45:09 UTC (rev 2097)
@@ -36,7 +36,7 @@
      * @since upcoming
      */
     public JavaClassConverter(ClassLoaderReference classLoaderReference) {
-        mapper = new DefaultMapper(classLoaderReference);
+        this(new DefaultMapper(classLoaderReference));
     }
 
     /**
@@ -46,12 +46,22 @@
         this(new ClassLoaderReference(classLoader));
     }
 
+    /**
+     * Construct a JavaClassConverter that uses a provided mapper. Depending on the mapper
+     * chain it will not only be used to load classes, but also to support type aliases.
+     * @param mapper to use
+     * @since upcoming
+     */
+    protected JavaClassConverter(Mapper mapper) {
+        this.mapper = mapper;
+    }
+
     public boolean canConvert(Class clazz) {
         return Class.class.equals(clazz); // :)
     }
 
     public String toString(Object obj) {
-        return ((Class) obj).getName();
+        return mapper.serializedClass(((Class) obj));
     }
 
     public Object fromString(String str) {

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java (2096 => 2097)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java	2013-07-08 22:36:06 UTC (rev 2096)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java	2013-07-12 16:45:09 UTC (rev 2097)
@@ -18,6 +18,8 @@
 import com.thoughtworks.xstream.core.ClassLoaderReference;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.mapper.DefaultMapper;
+import com.thoughtworks.xstream.mapper.Mapper;
 
 import java.lang.reflect.Field;
 
@@ -29,6 +31,7 @@
 public class JavaFieldConverter implements Converter {
 
     private final SingleValueConverter javaClassConverter;
+    private final Mapper mapper;
 
     /**
      * Construct a JavaFieldConverter.
@@ -36,7 +39,7 @@
      * @since upcoming
      */
     public JavaFieldConverter(ClassLoaderReference classLoaderReference) {
-        this.javaClassConverter = new JavaClassConverter(classLoaderReference);
+        this(new JavaClassConverter(classLoaderReference), new DefaultMapper(classLoaderReference));
     }
 
     /**
@@ -46,19 +49,31 @@
         this(new ClassLoaderReference(classLoader));
     }
 
+    /**
+     * Construct a JavaFieldConverter. Depending on the mapper chain the converter will also respect aliases.
+     * @param javaClassConverter the converter to use 
+     * @param mapper to use
+     * @since upcoming
+     */
+    protected JavaFieldConverter(SingleValueConverter javaClassConverter, Mapper mapper) {
+        this.javaClassConverter = javaClassConverter;
+        this.mapper = mapper;
+    }
+
     public boolean canConvert(Class type) {
         return type.equals(Field.class);
     }
 
     public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
         Field field = (Field) source;
+        Class type = field.getDeclaringClass();
 
         writer.startNode("name");
-        writer.setValue(field.getName());
+        writer.setValue(mapper.serializedMember(type, field.getName()));
         writer.endNode();
 
         writer.startNode("clazz");
-        writer.setValue(javaClassConverter.toString(field.getDeclaringClass()));
+        writer.setValue(javaClassConverter.toString(type));
         writer.endNode();
     }
 
@@ -79,7 +94,7 @@
         
         Class declaringClass = (Class)javaClassConverter.fromString(declaringClassName);
         try {
-            return declaringClass.getDeclaredField(methodName);
+            return declaringClass.getDeclaredField(mapper.realMember(declaringClass, methodName));
         } catch (NoSuchFieldException e) {
             throw new ConversionException(e);
         }

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java (2096 => 2097)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java	2013-07-08 22:36:06 UTC (rev 2096)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java	2013-07-12 16:45:09 UTC (rev 2097)
@@ -41,7 +41,7 @@
      * @since upcoming
      */
     public JavaMethodConverter(ClassLoaderReference classLoaderReference) {
-        this.javaClassConverter = new JavaClassConverter(classLoaderReference);
+        this(new JavaClassConverter(classLoaderReference));
     }
 
     /**
@@ -51,6 +51,15 @@
         this(new ClassLoaderReference(classLoader));
     }
 
+    /**
+     * Construct a JavaMethodConverter.
+     * @param javaClassConverter the converter to use 
+     * @since upcoming
+     */
+    protected JavaMethodConverter(SingleValueConverter javaClassConverter) {
+        this.javaClassConverter = javaClassConverter;
+    }
+
     public boolean canConvert(Class type) {
         return type.equals(Method.class) || type.equals(Constructor.class);
     }

Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java (2096 => 2097)


--- trunk/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java	2013-07-08 22:36:06 UTC (rev 2096)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java	2013-07-12 16:45:09 UTC (rev 2097)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005, 2006 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
@@ -12,13 +12,22 @@
 package com.thoughtworks.acceptance;
 
 import com.thoughtworks.acceptance.objects.Category;
+import com.thoughtworks.acceptance.objects.Product;
 import com.thoughtworks.acceptance.objects.Software;
 import com.thoughtworks.acceptance.someobjects.WithList;
 import com.thoughtworks.acceptance.someobjects.X;
 import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.converters.SingleValueConverter;
+import com.thoughtworks.xstream.converters.extended.JavaClassConverter;
+import com.thoughtworks.xstream.converters.extended.JavaFieldConverter;
+import com.thoughtworks.xstream.converters.extended.JavaMethodConverter;
+import com.thoughtworks.xstream.core.util.Primitives;
 import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
 import com.thoughtworks.xstream.io.xml.XppDriver;
+import com.thoughtworks.xstream.mapper.ArrayMapper;
 import com.thoughtworks.xstream.mapper.CannotResolveClassException;
+import com.thoughtworks.xstream.mapper.Mapper;
+import com.thoughtworks.xstream.mapper.MapperWrapper;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -369,4 +378,62 @@
 
         assertBothWays(withList, xml);
     }
+    
+    private void takingDoubles(Double d1, double d2) {}
+    
+    public void testCanCreateAliasingJavaTypeConverter() throws NoSuchFieldException, NoSuchMethodException {
+        Mapper mapper = new MapperWrapper(xstream.getMapper().lookupMapperOfType(ArrayMapper.class)) {
+            public Class realClass(String elementName) {
+                Class primitiveType = Primitives.primitiveType(elementName);
+                return primitiveType != null ? primitiveType : super.realClass(elementName);
+            }
+        };
+        SingleValueConverter javaClassConverter = new JavaClassConverter(mapper) {};
+        xstream.registerConverter(javaClassConverter);
+        xstream.registerConverter(new JavaMethodConverter(javaClassConverter){});
+        xstream.registerConverter(new JavaFieldConverter(javaClassConverter, mapper){});
+        xstream.alias("A", TypeA.class);
+        xstream.alias("Prod", Product.class);
+        xstream.aliasField("a", TypeA.class, "attrA");
+        xstream.alias("Test", getClass());
+        
+        List list = new ArrayList();
+        list.add(TypeA.class);
+        list.add(int[][][].class);
+        list.add(Integer[][][].class);
+        list.add(TypeA.class.getDeclaredField("attrA"));
+        list.add(Product.class.getConstructor(new Class[]{String.class, String.class, double.class}));
+        list.add(getClass().getDeclaredMethod("takingDoubles", new Class[]{Double.class, double.class}));
+        list.add(ArrayList.class);
+        
+        String xml = "" //
+            + "<list>\n"
+            + "  <java-class>A</java-class>\n"
+            + "  <java-class>int-array-array-array</java-class>\n"
+            + "  <java-class>java.lang.Integer-array-array-array</java-class>\n"
+            + "  <field>\n"
+            + "    <name>a</name>\n"
+            + "    <clazz>A</clazz>\n"
+            + "  </field>\n"
+            + "  <constructor>\n"
+            + "    <class>Prod</class>\n"
+            + "    <parameter-types>\n"
+            + "      <class>string</class>\n"
+            + "      <class>string</class>\n"
+            + "      <class>double</class>\n"
+            + "    </parameter-types>\n"
+            + "  </constructor>\n"
+            + "  <method>\n"
+            + "    <class>Test</class>\n"
+            + "    <name>takingDoubles</name>\n"
+            + "    <parameter-types>\n"
+            + "      <class>java.lang.Double</class>\n"
+            + "      <class>double</class>\n"
+            + "    </parameter-types>\n"
+            + "  </method>\n"
+            + "  <java-class>java.util.ArrayList</java-class>\n"
+            + "</list>";
+
+        assertBothWays(list, xml);
+    }
 }

Modified: trunk/xstream-distribution/src/content/changes.html (2096 => 2097)


--- trunk/xstream-distribution/src/content/changes.html	2013-07-08 22:36:06 UTC (rev 2096)
+++ trunk/xstream-distribution/src/content/changes.html	2013-07-12 16:45:09 UTC (rev 2097)
@@ -75,6 +75,9 @@
     	map with the nearest matching element type.</li>
     	<li>JIRA:XSTR-740: ISO8601GregorianCalendarConverter creates Calendar instance with wrong Locale in Java 7 if
     	the Locale for the LocaleCategory.FORMAT is different to the global default Locale.</li>
+    	<li>JIRA:XSTR-578: Implement support for aliasing in JavaClasConverter, JavaFieldConverter and
+    	JavaMethodConverter. While it is not possible to enable this in general, new constructors have been added to
+    	these converters and an example in the acceptance tests (AliasTest).</li>
     </ul>
 
     <h2>API changes</h2>

Modified: trunk/xstream-distribution/src/content/faq.html (2096 => 2097)


--- trunk/xstream-distribution/src/content/faq.html	2013-07-08 22:36:06 UTC (rev 2096)
+++ trunk/xstream-distribution/src/content/faq.html	2013-07-12 16:45:09 UTC (rev 2097)
@@ -1,7 +1,7 @@
 <html>
 <!--
  Copyright (C) 2005, 2006 Joe Walnes.
- Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 XStream committers.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 XStream committers.
  All rights reserved.
  
  The software in this package is published under the terms of the BSD
@@ -228,6 +228,26 @@
 	<p>Note, that it is possible to configure XStream to omit the container element <i>toys</i> using implicit collections.</p>
 
     <!-- ...................................................... -->
+    <h2 id="Serialization_reflection_types">Why do serialized types, fields or methods do not use aliasing for the names?</h2>
+
+	<p>XStream normally has no to separate between a primitive and its boxed type. The complete reflection API works
+	always with the boxed types and converts to primitives types on the fly. However, for method and field type
+	signatures the difference is essential. Nevertheless it is possible to register derived versions of the converters
+	that are able to respect the aliasing with some minor effort. Following lines are taken from the AliasTest in the
+	acceptence tests:</p>
+<div class="Source Java"><pre>XStream xstream = new XStream();
+Mapper mapper = new MapperWrapper(xstream.getMapper().lookupMapperOfType(ArrayMapper.class)) {
+  public Class realClass(String elementName) {
+    Class primitiveType = Primitives.primitiveType(elementName);
+    return primitiveType != null ? primitiveType : super.realClass(elementName);
+  }
+};
+SingleValueConverter javaClassConverter = new JavaClassConverter(mapper) {};
+xstream.registerConverter(javaClassConverter);
+xstream.registerConverter(new JavaMethodConverter(javaClassConverter){});
+xstream.registerConverter(new JavaFieldConverter(javaClassConverter, mapper){});</pre></div>
+
+    <!-- ...................................................... -->
     <h2 id="Serialization_implicit_null">My implicit collection is suddenly null after deserialization instead of empty!</h2>
 
 	<p>By declaring a collection as implicit, the result will have no direct representation of the collection container

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to