10000 XML Parsing: Enum as element type (#475) by geri-m · Pull Request #476 · googleapis/google-http-java-client · GitHub
[go: up one dir, main page]

Skip to content

XML Parsing: Enum as element type (#475) #476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ private static boolean parseElementInternal(XmlPullParser parser,
@SuppressWarnings("unchecked")
Map<String, Object> destinationMap =
genericXml == null && destination instanceof Map<?, ?> ? Map.class.cast(destination) : null;

// if there is a class, we want to put the data into, create the class Info for this
ClassInfo classInfo =
destinationMap != null || destination == null ? null : ClassInfo.of(destination.getClass());
if (parser.getEventType() == XmlPullParser.START_DOCUMENT) {
Expand Down Expand Up @@ -313,7 +315,11 @@ private static boolean parseElementInternal(XmlPullParser parser,
parseNamespacesForElement(parser, namespaceDictionary);
String namespace = parser.getNamespace();
String alias = namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(namespace);

// get the "real" field name of the
String fieldName = getFieldName(false, alias, namespace, parser.getName());

// fetch the field from the classInfo
field = classInfo == null ? null : classInfo.getField(fieldName);
Type fieldType = field == null ? valueType : field.getGenericType();
fieldType = Data.resolveWildcardTypeOrTypeVariable(context, fieldType);
Expand All @@ -326,7 +332,9 @@ private static boolean parseElementInternal(XmlPullParser parser,
boolean isArray = Types.isArray(fieldType);
// text content
boolean ignore = field == null && destinationMap == null && genericXml == null;
if (ignore || Data.isPrimitive(fieldType)) {
// is the field an Enum
boolean isEnum = fieldClass != null && fieldClass.isEnum();
if (ignore || Data.isPrimitive(fieldType) || isEnum) {
int level = 1;
while (level != 0) {
switch (parser.next()) {
Expand Down Expand Up @@ -425,7 +433,8 @@ private static boolean parseElementInternal(XmlPullParser parser,
if (subFieldType instanceof ParameterizedType) {
subFieldClass = Types.getRawClass((ParameterizedType) subFieldType);
}
if (Data.isPrimitive(subFieldType)) {
boolean isSubEnum = subFieldClass != null && subFieldClass.isEnum();
if (Data.isPrimitive(subFieldType) || isSubEnum) {
elementValue = parseTextContentForElement(parser, context, false, subFieldType);
} else if (subFieldType == null || subFieldClass != null
&& Types.isAssignableToOrFrom(subFieldClass, Map.class)) {
Expand Down Expand Up @@ -501,9 +510,9 @@ private static boolean parseElementInternal(XmlPullParser parser,
isStopped = true;
break main;
}
break;
}
}
break; // break Switch;
} // end -- switch (event)
} // end -- main: while (true)
arrayValueMap.setValues();
return isStopped;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ private void computeAliases(Object element, SortedSet<String> aliases) {
aliases.add(alias);
}
Class<?> valueClass = value.getClass();
if (!isAttribute && !Data.isPrimitive(valueClass)) {
if (!isAttribute && !Data.isPrimitive(valueClass) && !valueClass.isEnum() ) {
if (value instanceof Iterable<?> || valueClass.isArray()) {
for (Object subValue : Types.iterableOf(value)) {
computeAliases(subValue, aliases);
Expand Down Expand Up @@ -328,6 +328,8 @@ class ElementSerializer {
Class<?> valueClass = elementValue.getClass();
if (Data.isPrimitive(valueClass) && !Data.isNull(elementValue)) {
textValue = elementValue;
} else if (valueClass.isEnum() && !Data.isNull(elementValue)){
textValue = elementValue;
} else {
for (Map.Entry<String, Object> entry : Data.mapOf(elementValue).entrySet()) {
Object fieldValue = entry.getValue();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.google.api.client.xml;

import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import com.google.api.client.util.Key;
import com.google.api.client.util.Value;
import junit.framework.TestCase;

public class XmlEnumTest extends TestCase {

public enum AnyEnum {
@Value ENUM_1,
@Value ENUM_2
}

public static class AnyType {
@Key("@attr")
public Object attr;
@Key
public Object elem;
@Key
public Object rep;
@Key("@anyEnum")
public XmlEnumTest.AnyEnum anyEnum;
@Key
public XmlEnumTest.AnyEnum anotherEnum;
@Key
public ValueType value;
}

public static class AnyTypeEnumElementOnly {
@Key
public XmlEnumTest.AnyEnum elementEnum;
}

public static class AnyTypeEnumAttributeOnly {
@Key("@attributeEnum")
public XmlEnumTest.AnyEnum attributeEnum;
}

public static class ValueType {
@Key("text()")
public XmlEnumTest.AnyEnum content;
}

private static final String XML =
"<?xml version=\"1.0\"?><any anyEnum=\"ENUM_1\" attr=\"value\" xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<anotherEnum>ENUM_2</anotherEnum><elem>content</elem><rep>rep1</rep><rep>rep2</rep><value>ENUM_1</value></any>";

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>";

private static final String XML_ENUM_ATTRIBUTE_ONLY = "<?xml version=\"1.0\"?><any attributeEnum=\"ENUM_1\" xmlns=\"http://www.w3.org/2005/Atom\" />";

private static final String XML_ENUM_INCORRECT = "<?xml version=\"1.0\"?><any xmlns=\"http://www.w3.org/2005/Atom\"><elementEnum>ENUM_3</elementEnum></any>";


@SuppressWarnings("cast")
public void testParse_anyType() throws Exception {
AnyType xml = new AnyType();
XmlPullParser parser = Xml.createParser();
parser.setInput(new StringReader(XML));
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
Xml.parseElement(parser, xml, namespaceDictionary, null);
assertTrue(xml.attr instanceof String);
assertTrue(xml.elem.toString(), xml.elem instanceof ArrayList<?>);
assertTrue(xml.rep.toString(), xml.rep instanceof ArrayList<?>);
assertTrue(xml.value instanceof ValueType);
assertTrue(xml.value.content instanceof XmlEnumTest.AnyEnum);
assertTrue(xml.anyEnum instanceof XmlEnumTest.AnyEnum);
assertTrue(xml.anotherEnum instanceof XmlEnumTest.AnyEnum);
assertTrue(xml.anyEnum.equals(AnyEnum.ENUM_1));
assertTrue(xml.anotherEnum.equals(AnyEnum.ENUM_2));
assertTrue(xml.value.content.equals(AnyEnum.ENUM_1));
// serialize
XmlSerializer serializer = Xml.createSerializer();
ByteArrayOutputStream out = new ByteArrayOutputStream();
serializer.setOutput(out, "UTF-8");
namespaceDictionary.serialize(serializer, "any", xml);
assertEquals(XML, out.toString());
}

public void testParse_enumElementType() throws Exception {
XmlEnumTest.AnyTypeEnumElementOnly xml = new XmlEnumTest.AnyTypeEnumElementOnly();
XmlPullParser parser = Xml.createParser();
parser.setInput(new StringReader(XML_ENUM_ELEMENT_ONLY));
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
Xml.parseElement(parser, xml, namespaceDictionary, null);
assertTrue(xml.elementEnum instanceof XmlEnumTest.AnyEnum);
assertTrue(xml.elementEnum.equals(AnyEnum.ENUM_2));
// serialize
XmlSerializer serializer = Xml.createSerializer();
ByteArrayOutputStream out = new ByteArrayOutputStream();
serializer.setOutput(out, "UTF-8");
namespaceDictionary.serialize(serializer, "any", xml);
assertEquals(XML_ENUM_ELEMENT_ONLY, out.toString());
}

public void testParse_enumAttributeType() throws Exception {
XmlEnumTest.AnyTypeEnumAttributeOnly xml = new XmlEnumTest.AnyTypeEnumAttributeOnly();
XmlPullParser parser = Xml.createParser();
parser.setInput(new StringReader(XML_ENUM_ATTRIBUTE_ONLY));
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
Xml.parseElement(parser, xml, namespaceDictionary, null);
assertTrue(xml.attributeEnum instanceof XmlEnumTest.AnyEnum);
assertTrue(xml.attributeEnum.equals(AnyEnum.ENUM_1));
// serialize
XmlSerializer serializer = Xml.createSerializer();
ByteArrayOutputStream out = new ByteArrayOutputStream();
serializer.setOutput(out, "UTF-8");
namespaceDictionary.serialize(serializer, "any", xml);
assertEquals(XML_ENUM_ATTRIBUTE_ONLY, out.toString());
}

public void testParse_enumElementTypeIncorrect() throws Exception {
XmlEnumTest.AnyTypeEnumElementOnly xml = new XmlEnumTest.AnyTypeEnumElementOnly();
XmlPullParser parser = Xml.createParser();
parser.setInput(new StringReader(XML_ENUM_INCORRECT));
XmlNamespaceDictionary namespaceDictionary = new XmlNamespaceDictionary();
try{
Xml.parseElement(parser, xml, namespaceDictionary, null);
// fail test, if there is no exception
fail();
} catch (final IllegalArgumentException e){
assertEquals("given enum name ENUM_3 not part of enumeration", e.getMessage());
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ public static Object parsePrimitiveValue(Type type, String stringValue) {
return new BigDecimal(stringValue);
}
if (primitiveClass.isEnum()) {
if (!ClassInfo.of(primitiveClass).names.contains(stringValue)) {
throw new IllegalArgumentException(String.format("given enum name %s not part of " +
"enumeration", stringValue));
}
@SuppressWarnings({"unchecked", "rawtypes"})
Enum result = ClassInfo.of(primitiveClass).getFieldInfo(stringValue).<Enum>enumValue();
return result;
Expand Down
0