Title: [2068] trunk/xstream/src: Do not unmarshal unknown elements if the tag matches a type alias (XSTR-737).
Revision
2068
Author
joehni
Date
2013-06-04 18:56:37 -0500 (Tue, 04 Jun 2013)

Log Message

Do not unmarshal unknown elements if the tag matches a type alias (XSTR-737).

Modified Paths

Diff

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (2067 => 2068)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java	2013-06-01 12:38:45 UTC (rev 2067)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java	2013-06-04 23:56:37 UTC (rev 2068)
@@ -308,6 +308,7 @@
             Mapper.ImplicitCollectionMapping implicitCollectionMapping = mapper
                 .getImplicitCollectionDefForFieldName(fieldDeclaringClass, fieldName);
             final Object value;
+            String implicitFieldName = null;
             Field field = null;
             Class type = null;
             if (implicitCollectionMapping == null) {
@@ -329,26 +330,42 @@
                         // collection based on type only?
                         try {
                             type = mapper.realClass(originalNodeName);
+                            implicitFieldName = mapper.getFieldNameForItemTypeAndName(
+                                context.getRequiredType(), type, originalNodeName);
                         } catch (CannotResolveClassException e) {
+                            // type stays null ...
+                        }
+                        if (type == null || (type != null && implicitFieldName == null)) {
+                            // either not a type or element is a type alias, but does not
+                            // belong to an implicit field
                             handleUnknownField(
                                 explicitDeclaringClass, fieldName, resultType, originalNodeName);
+                            
+                            // element is unknown in declaring class, ignore it now
+                            type = null;
                         }
                     }
-                    if (Map.Entry.class.equals(type)) {
-                        // it is an element of an implicit map with two elements now for key
-                        // and value 
-                        reader.moveDown();
-                        final Object key = context.convertAnother(
-                            result, HierarchicalStreams.readClassType(reader, mapper));
-                        reader.moveUp();
-                        reader.moveDown();
-                        final Object v = context.convertAnother(
-                            result, HierarchicalStreams.readClassType(reader, mapper));
-                        reader.moveUp();
-                        value = Collections.singletonMap(key, v).entrySet().iterator().next();
+                    if (type == null) {
+                        // no type, no value
+                        value = null;
                     } else {
-                        // if we have a type, recurse info hierarchy
-                        value = type != null ? context.convertAnother(result, type) : null;
+                        if (Map.Entry.class.equals(type)) {
+                            // it is an element of an implicit map with two elements now for
+                            // key and value 
+                            reader.moveDown();
+                            final Object key = context.convertAnother(
+                                result, HierarchicalStreams.readClassType(reader, mapper));
+                            reader.moveUp();
+                            reader.moveDown();
+                            final Object v = context.convertAnother(
+                                result, HierarchicalStreams.readClassType(reader, mapper));
+                            reader.moveUp();
+                            value = Collections.singletonMap(key, v)
+                                .entrySet().iterator().next();
+                        } else {
+                            // recurse info hierarchy
+                            value = context.convertAnother(result, type);
+                        }
                     }
                 } else {
                     boolean fieldAlreadyChecked = false;
@@ -386,7 +403,8 @@
                     }
                 }
             } else {
-                // we have an implicit collection with defined names 
+                // we have an implicit collection with defined names
+               // implicitFieldName = implicitCollectionMapping.getItemFieldName();
                 type = implicitCollectionMapping.getItemType();
                 if (type == null) {
                     String classAttribute = HierarchicalStreams.readClassAttribute(
@@ -409,9 +427,15 @@
                 reflectionProvider.writeField(result, fieldName, value, field.getDeclaringClass());
                 seenFields.add(new FastField(field.getDeclaringClass(), fieldName));
             } else if (type != null) {
-                implicitCollectionsForCurrentObject = writeValueToImplicitCollection(
-                    context, value, implicitCollectionsForCurrentObject, result,
-                    originalNodeName);
+                if (implicitFieldName == null) {
+                    // look for implicit field
+                    implicitFieldName = mapper.getFieldNameForItemTypeAndName(
+                        context.getRequiredType(), 
+                        value != null ? value.getClass() : Mapper.Null.class,
+                        originalNodeName);
+                }
+                implicitCollectionsForCurrentObject = writeValueToImplicitCollection(value,
+                    implicitCollectionsForCurrentObject, result, implicitFieldName);
             }
 
             reader.moveUp();
@@ -458,58 +482,45 @@
         throw new UnknownFieldException(resultType.getName(), fieldName);
     }
 
-    private Map writeValueToImplicitCollection(UnmarshallingContext context, Object value,
-        Map implicitCollections, Object result, String itemFieldName) {
-        String fieldName = mapper.getFieldNameForItemTypeAndName(
-            context.getRequiredType(), value != null ? value.getClass() : Mapper.Null.class,
-            itemFieldName);
-        if (fieldName != null) {
-            if (implicitCollections == null) {
-                implicitCollections = new HashMap(); // lazy instantiation
-            }
-            Collection collection = (Collection)implicitCollections.get(fieldName);
-            if (collection == null) {
-                Class physicalFieldType = reflectionProvider.getFieldType(
-                    result, fieldName, null);
-                if (physicalFieldType.isArray()) {
-                    collection = new ArraysList(physicalFieldType);
+    private Map writeValueToImplicitCollection(Object value, Map implicitCollections, Object result, String implicitFieldName) {
+        if (implicitCollections == null) {
+            implicitCollections = new HashMap(); // lazy instantiation
+        }
+        Collection collection = (Collection)implicitCollections.get(implicitFieldName);
+        if (collection == null) {
+            Class physicalFieldType = reflectionProvider.getFieldType(
+                result, implicitFieldName, null);
+            if (physicalFieldType.isArray()) {
+                collection = new ArraysList(physicalFieldType);
+            } else {
+                Class fieldType = mapper.defaultImplementationOf(physicalFieldType);
+                if (!(Collection.class.isAssignableFrom(fieldType) || Map.class
+                    .isAssignableFrom(fieldType))) {
+                    throw new ObjectAccessException(
+                        "Field "
+                            + implicitFieldName
+                            + " of "
+                            + result.getClass().getName()
+                            + " is configured for an implicit Collection or Map, but field is of type "
+                            + fieldType.getName());
+                }
+                if (pureJavaReflectionProvider == null) {
+                    pureJavaReflectionProvider = new PureJavaReflectionProvider();
+                }
+                Object instance = pureJavaReflectionProvider.newInstance(fieldType);
+                if (instance instanceof Collection) {
+                    collection = (Collection)instance;
                 } else {
-                    Class fieldType = mapper.defaultImplementationOf(physicalFieldType);
-                    if (!(Collection.class.isAssignableFrom(fieldType) || Map.class
-                        .isAssignableFrom(fieldType))) {
-                        throw new ObjectAccessException(
-                            "Field "
-                                + fieldName
-                                + " of "
-                                + result.getClass().getName()
-                                + " is configured for an implicit Collection or Map, but field is of type "
-                                + fieldType.getName());
-                    }
-                    if (pureJavaReflectionProvider == null) {
-                        pureJavaReflectionProvider = new PureJavaReflectionProvider();
-                    }
-                    Object instance = pureJavaReflectionProvider.newInstance(fieldType);
-                    if (instance instanceof Collection) {
-                        collection = (Collection)instance;
-                    } else {
-                        Mapper.ImplicitCollectionMapping implicitCollectionMapping = mapper
-                            .getImplicitCollectionDefForFieldName(result.getClass(), fieldName);
-                        collection = new MappingList(
-                            (Map)instance, implicitCollectionMapping.getKeyFieldName());
-                    }
-                    reflectionProvider.writeField(result, fieldName, instance, null);
+                    Mapper.ImplicitCollectionMapping implicitCollectionMapping = mapper
+                        .getImplicitCollectionDefForFieldName(result.getClass(), implicitFieldName);
+                    collection = new MappingList(
+                        (Map)instance, implicitCollectionMapping.getKeyFieldName());
                 }
-                implicitCollections.put(fieldName, collection);
+                reflectionProvider.writeField(result, implicitFieldName, instance, null);
             }
-            collection.add(value);
-        } else {
-            throw new ConversionException("Element "
-                + itemFieldName
-                + " of type "
-                + value.getClass().getName()
-                + " is not defined as field in type "
-                + result.getClass().getName());
+            implicitCollections.put(implicitFieldName, collection);
         }
+        collection.add(value);
         return implicitCollections;
     }
 

Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java (2067 => 2068)


--- trunk/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java	2013-06-01 12:38:45 UTC (rev 2067)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java	2013-06-04 23:56:37 UTC (rev 2068)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2009, 2011 XStream Committers.
+ * Copyright (C) 2006, 2007, 2009, 2011, 2013 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -75,7 +75,6 @@
             assertEquals("3",
                     e.get("line number"));
         }
-
     }
     
     public void testNonExistingMember() {
@@ -94,6 +93,20 @@
             assertEquals("3",
                     e.get("line number"));
         }
-        
     }
+    
+    public void testNonExistingMemberMatchingAlias() {
+        try {
+            xstream.fromXML("" 
+                + "<thing>\n" 
+                + "  <string>string 1</string>\n" 
+                + "</thing>");
+            fail("Error expected");
+        } catch (ConversionException e) {
+            assertEquals("/thing/string",
+                    e.get("path"));
+            assertEquals("2",
+                    e.get("line number"));
+        }
+    }
 }

Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java (2067 => 2068)


--- trunk/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java	2013-06-01 12:38:45 UTC (rev 2067)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java	2013-06-04 23:56:37 UTC (rev 2068)
@@ -338,6 +338,30 @@
                     DerivedThing.class.getName() + ".unknown"));
         }
     }
+    
+    public void testIgnoreNonExistingElementsMatchingTypeAlias() {
+        xstream.alias("thing", Thing.class);
+        xstream.ignoreUnknownElements("string");
+        Thing thing = new Thing();
+        String provided = "" 
+            + "<thing>\n" 
+            + "  <string>string 1</string>\n" 
+            + "</thing>";
+        String expected = "<thing/>";
+        assertWithAsymmetricalXml(thing, provided, expected);
+    }
+    
+    public void testIgnoredElementIsNotInstantiated() {
+        xstream.alias("thing", Thing.class);
+        xstream.ignoreUnknownElements("int");
+        Thing thing = new Thing();
+        String provided = "" 
+            + "<thing>\n" 
+            + "  <int>invalid</int>\n" 
+            + "</thing>";
+        String expected = "<thing/>";
+        assertWithAsymmetricalXml(thing, provided, expected);
+    }
 
     static class ThingAgain extends Thing {
         String sometimesIgnore;

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to