Skip to content

Commit 4d6a42d

Browse files
geri-mchingor13
authored andcommitted
XML Parsing: Enum as element type (#475) (#476)
* Allows enums as element types (#475) * Remove Blank lines (#475)
1 parent 1f067da commit 4d6a42d

File tree

4 files changed

+153
-6
lines changed

4 files changed

+153
-6
lines changed

google-http-client-xml/src/main/java/com/google/api/client/xml/Xml.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ private static boolean parseElementInternal(XmlPullParser parser,
237237
@SuppressWarnings("unchecked")
238238
Map<String, Object> destinationMap =
239239
genericXml == null && destination instanceof Map<?, ?> ? Map.class.cast(destination) : null;
240+
241+
// if there is a class, we want to put the data into, create the class Info for this
240242
ClassInfo classInfo =
241243
destinationMap != null || destination == null ? null : ClassInfo.of(destination.getClass());
242244
if (parser.getEventType() == XmlPullParser.START_DOCUMENT) {
@@ -313,7 +315,11 @@ private static boolean parseElementInternal(XmlPullParser parser,
313315
parseNamespacesForElement(parser, namespaceDictionary);
314316
String namespace = parser.getNamespace();
315317
String alias = namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(namespace);
318+
319+
// get the "real" field name of the
316320
String fieldName = getFieldName(false, alias, namespace, parser.getName());
321+
322+
// fetch the field from the classInfo
317323
field = classInfo == null ? null : classInfo.getField(fieldName);
318324
Type fieldType = field == null ? valueType : field.getGenericType();
319325
fieldType = Data.resolveWildcardTypeOrTypeVariable(context, fieldType);
@@ -326,7 +332,9 @@ private static boolean parseElementInternal(XmlPullParser parser,
326332
boolean isArray = Types.isArray(fieldType);
327333
// text content
328334
boolean ignore = field == null && destinationMap == null && genericXml == null;
329-
if (ignore || Data.isPrimitive(fieldType)) {
335+
// is the field an Enum
336+
boolean isEnum = fieldClass != null && fieldClass.isEnum();
337+
if (ignore || Data.isPrimitive(fieldType) || isEnum) {
330338
int level = 1;
331339
while (level != 0) {
332340
switch (parser.next()) {
@@ -425,7 +433,8 @@ private static boolean parseElementInternal(XmlPullParser parser,
425433
if (subFieldType instanceof ParameterizedType) {
426434
subFieldClass = Types.getRawClass((ParameterizedType) subFieldType);
427435
}
428-
if (Data.isPrimitive(subFieldType)) {
436+
boolean isSubEnum = subFieldClass != null && subFieldClass.isEnum();
437+
if (Data.isPrimitive(subFieldType) || isSubEnum) {
429438
elementValue = parseTextContentForElement(parser, context, false, subFieldType);
430439
} else if (subFieldType == null || subFieldClass != null
431440
&& Types.isAssignableToOrFrom(subFieldClass, Map.class)) {
@@ -501,9 +510,9 @@ private static boolean parseElementInternal(XmlPullParser parser,
501510
isStopped = true;
502511
break main;
503512
}
504-
break;
505-
}
506-
}
513+
break; // break Switch;
514+
} // end -- switch (event)
515+
} // end -- main: while (true)
507516
arrayValueMap.setValues();
508517
return isStopped;
509518
}

google-http-client-xml/src/main/java/com/google/api/client/xml/XmlNamespaceDictionary.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ private void computeAliases(Object element, SortedSet<String> aliases) {
257257
aliases.add(alias);
258258
}
259259
Class<?> valueClass = value.getClass();
260-
if (!isAttribute && !Data.isPrimitive(valueClass)) {
260+
if (!isAttribute && !Data.isPrimitive(valueClass) && !valueClass.isEnum() ) {
261261
if (value instanceof Iterable<?> || valueClass.isArray()) {
262262
for (Object subValue : Types.iterableOf(value)) {
263263
computeAliases(subValue, aliases);
@@ -328,6 +328,8 @@ class ElementSerializer {
328328
Class<?> valueClass = elementValue.getClass();
329329
if (Data.isPrimitive(valueClass) && !Data.isNull(elementValue)) {
330330
textValue = elementValue;
331+
} else if (valueClass.isEnum() && !Data.isNull(elementValue)){
332+
textValue = elementValue;
331333
} else {
332334
for (Map.Entry<String, Object> entry : Data.mapOf(elementValue).entrySet()) {
333335
Object fieldValue = entry.getValue();
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.google.api.client.xml;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.StringReader;
5+
import java.util.ArrayList;
6+
import org.xmlpull.v1.XmlPullParser;
7+
import org.xmlpull.v1.XmlSerializer;
8+
import com.google.api.client.util.Key;
9+
import com.google.api.client.util.Value;
10+
import junit.framework.TestCase;
11+
12+
public class XmlEnumTest extends TestCase {
13+
14+
public enum AnyEnum {
15+
@Value ENUM_1,
16+
@Value ENUM_2
17+
}
18+
19+
public static class AnyType {
20+
@Key("@attr")
21+
public Object attr;
22+
@Key
23+
public Object elem;
24+
@Key
25+
public Object rep;
26+
@Key("@anyEnum")
27+
public XmlEnumTest.AnyEnum anyEnum;
28+
@Key
29+
public XmlEnumTest.AnyEnum anotherEnum;
30+
@Key
31+
public ValueType value;
32+
}
33+
34+
public static class AnyTypeEnumElementOnly {
35+
@Key
36+
public XmlEnumTest.AnyEnum elementEnum;
37+
}
38+
39+
public static class AnyTypeEnumAttributeOnly {
40+
@Key("@attributeEnum")
41+
public XmlEnumTest.AnyEnum attributeEnum;
42+
}
43+
44+
public static class ValueType {
45+
@Key("text()")
46+
public XmlEnumTest.AnyEnum content;
47+
}
48+
49+
private static final String XML =
50+
"<?xml version=\"1.0\"?><any anyEnum=\"ENUM_1\" attr=\"value\" xmlns=\"http://www.w3.org/2005/Atom\">"
51+
+ "<anotherEnum>ENUM_2</anotherEnum><elem>content</elem><rep>rep1</rep><rep>rep2</rep><value>ENUM_1</value></any>";
52+
53+
private static final String XML_ENUM_ELEMENT_ONLY = "<?xml version=\"1.0\"?><any xmlns=\"http://www.w3.org/2005/Atom\"><elementEnum>ENUM_2</elementEnum></any>";
54+
55+
private static final String XML_ENUM_ATTRIBUTE_ONLY = "<?xml version=\"1.0\"?><any attributeEnum=\"ENUM_1\" xmlns=\"http://www.w3.org/2005/Atom\" />";
56+
57+
private static final String XML_ENUM_INCORRECT = "<?xml version=\"1.0\"?><any xmlns=\"http://www.w3.org/2005/Atom\"><elementEnum>ENUM_3</elementEnum></any>";
58+
59+
60+
@SuppressWarnings("cast")
61+
public void testParse_anyType() throws Exception {
62+
AnyType xml = new AnyType();
63+
XmlPullParser parser = Xml.createParser();
64+
parser.setInput(new StringReader(XML));
65+
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
66+
Xml.parseElement(parser, xml, namespaceDictionary, null);
67+
assertTrue(xml.attr instanceof String);
68+
assertTrue(xml.elem.toString(), xml.elem instanceof ArrayList<?>);
69+
assertTrue(xml.rep.toString(), xml.rep instanceof ArrayList<?>);
70+
assertTrue(xml.value instanceof ValueType);
71+
assertTrue(xml.value.content instanceof XmlEnumTest.AnyEnum);
72+
assertTrue(xml.anyEnum instanceof XmlEnumTest.AnyEnum);
73+
assertTrue(xml.anotherEnum instanceof XmlEnumTest.AnyEnum);
74+
assertTrue(xml.anyEnum.equals(AnyEnum.ENUM_1));
75+
assertTrue(xml.anotherEnum.equals(AnyEnum.ENUM_2));
76+
assertTrue(xml.value.content.equals(AnyEnum.ENUM_1));
77+
// serialize
78+
XmlSerializer serializer = Xml.createSerializer();
79+
ByteArrayOutputStream out = new ByteArrayOutputStream();
80+
serializer.setOutput(out, "UTF-8");
81+
namespaceDictionary.serialize(serializer, "any", xml);
82+
assertEquals(XML, out.toString());
83+
}
84+
85+
public void testParse_enumElementType() throws Exception {
86+
XmlEnumTest.AnyTypeEnumElementOnly xml = new XmlEnumTest.AnyTypeEnumElementOnly();
87+
XmlPullParser parser = Xml.createParser();
88+
parser.setInput(new StringReader(XML_ENUM_ELEMENT_ONLY));
89+
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
90+
Xml.parseElement(parser, xml, namespaceDictionary, null);
91+
assertTrue(xml.elementEnum instanceof XmlEnumTest.AnyEnum);
92+
assertTrue(xml.elementEnum.equals(AnyEnum.ENUM_2));
93+
// serialize
94+
XmlSerializer serializer = Xml.createSerializer();
95+
ByteArrayOutputStream out = new ByteArrayOutputStream();
96+
serializer.setOutput(out, "UTF-8");
97+
namespaceDictionary.serialize(serializer, "any", xml);
98+
assertEquals(XML_ENUM_ELEMENT_ONLY, out.toString());
99+
}
100+
101+
public void testParse_enumAttributeType() throws Exception {
102+
XmlEnumTest.AnyTypeEnumAttributeOnly xml = new XmlEnumTest.AnyTypeEnumAttributeOnly();
103+
XmlPullParser parser = Xml.createParser();
104+
parser.setInput(new StringReader(XML_ENUM_ATTRIBUTE_ONLY));
105+
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
106+
Xml.parseElement(parser, xml, namespaceDictionary, null);
107+
assertTrue(xml.attributeEnum instanceof XmlEnumTest.AnyEnum);
108+
assertTrue(xml.attributeEnum.equals(AnyEnum.ENUM_1));
109+
// serialize
110+
XmlSerializer serializer = Xml.createSerializer();
111+
ByteArrayOutputStream out = new ByteArrayOutputStream();
112+
serializer.setOutput(out, "UTF-8");
113+
namespaceDictionary.serialize(serializer, "any", xml);
114+
assertEquals(XML_ENUM_ATTRIBUTE_ONLY, out.toString());
115+
}
116+
117+
public void testParse_enumElementTypeIncorrect() throws Exception {
118+
XmlEnumTest.AnyTypeEnumElementOnly xml = new XmlEnumTest.AnyTypeEnumElementOnly();
119+
XmlPullParser parser = Xml.createParser();
120+
parser.setInput(new StringReader(XML_ENUM_INCORRECT));
121+
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
122+
try{
123+
Xml.parseElement(parser, xml, namespaceDictionary, null);
124+
// fail test, if there is no exception
125+
fail();
126+
} catch (final IllegalArgumentException e){
127+
assertEquals("given enum name ENUM_3 not part of enumeration", e.getMessage());
128+
}
129+
130+
}
131+
132+
}

google-http-client/src/main/java/com/google/api/client/util/Data.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@ public static Object parsePrimitiveValue(Type type, String stringValue) {
445445
return new BigDecimal(stringValue);
446446
}
447447
if (primitiveClass.isEnum()) {
448+
if (!ClassInfo.of(primitiveClass).names.contains(stringValue)) {
449+
throw new IllegalArgumentException(String.format("given enum name %s not part of " +
450+
"enumeration", stringValue));
451+
}
448452
@SuppressWarnings({"unchecked", "rawtypes"})
449453
Enum result = ClassInfo.of(primitiveClass).getFieldInfo(stringValue).<Enum>enumValue();
450454
return result;

0 commit comments

Comments
 (0)