destinationMap,
fieldName);
}
}
Field field;
ArrayValueMap arrayValueMap = new ArrayValueMap(destination);
boolean isStopped = false;
main: while (true) {
int event = parser.next();
switch (event) {
case XmlPullParser.END_DOCUMENT:
isStopped = true;
break main;
case XmlPullParser.END_TAG:
isStopped = customizeParser != null
&& customizeParser.stopAfterEndTag(parser.getNamespace(), parser.getName());
break main;
case XmlPullParser.TEXT:
// parse text content
if (destination != null) {
field = classInfo == null ? null : classInfo.getField(TEXT_CONTENT);
parseAttributeOrTextContent(parser.getText(),
field,
valueType,
context,
destination,
genericXml,
destinationMap,
TEXT_CONTENT);
}
break;
case XmlPullParser.START_TAG:
if (customizeParser != null
&& customizeParser.stopBeforeStartTag(parser.getNamespace(), parser.getName())) {
isStopped = true;
break main;
}
if (destination == null) {
parseTextContentForElement(parser, context, true, null);
} else {
// element
parseNamespacesForElement(parser, namespaceDictionary);
String namespace = parser.getNamespace();
String alias = namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(namespace);
String fieldName = getFieldName(false, alias, namespace, parser.getName());
field = classInfo == null ? null : classInfo.getField(fieldName);
Type fieldType = field == null ? valueType : field.getGenericType();
fieldType = Data.resolveWildcardTypeOrTypeVariable(context, fieldType);
// field type is now class, parameterized type, or generic array type
// resolve a parameterized type to a class
Class<?> fieldClass = fieldType instanceof Class<?> ? (Class<?>) fieldType : null;
if (fieldType instanceof ParameterizedType) {
fieldClass = Types.getRawClass((ParameterizedType) fieldType);
}
boolean isArray = Types.isArray(fieldType);
// text content
boolean ignore = field == null && destinationMap == null && genericXml == null;
if (ignore || Data.isPrimitive(fieldType)) {
int level = 1;
while (level != 0) {
switch (parser.next()) {
case XmlPullParser.END_DOCUMENT:
isStopped = true;
break main;
case XmlPullParser.START_TAG:
level++;
break;
case XmlPullParser.END_TAG:
level--;
break;
case XmlPullParser.TEXT:
if (!ignore && level == 1) {
parseAttributeOrTextContent(parser.getText(),
field,
valueType,
context,
destination,
genericXml,
destinationMap,
fieldName);
}
break;
}
}
} else if (fieldType == null || fieldClass != null
&& Types.isAssignableToOrFrom(fieldClass, Map.class)) {
// store the element as a map
Map<String, Object> mapValue = Data.newMapInstance(fieldClass);
int contextSize = context.size();
if (fieldType != null) {
context.add(fieldType);
}
Type subValueType = fieldType != null && Map.class.isAssignableFrom(fieldClass)
? Types.getMapValueParameter(fieldType) : null;
subValueType = Data.resolveWildcardTypeOrTypeVariable(context, subValueType);
isStopped = parseElementInternal(parser,
context,
mapValue,
subValueType,
namespaceDictionary,
customizeParser);
if (fieldType != null) {
context.remove(contextSize);
}
if (destinationMap != null) {
// map but not GenericXml: store as ArrayList of elements
@SuppressWarnings("unchecked")
Collection<Object> list = (Collection<Object>) destinationMap.get(fieldName);
if (list == null) {
list = new ArrayList<Object>(1);
destinationMap.put(fieldName, list);
}
list.add(mapValue);
} else if (field != null) {
// not a map: store in field value
FieldInfo fieldInfo = FieldInfo.of(field);
if (fieldClass == Object.class) {
// field is an Object: store as ArrayList of element maps
@SuppressWarnings("unchecked")
Collection<Object> list = (Collection<Object>) fieldInfo.getValue(destination);
if (list == null) {
list = new ArrayList<Object>(1);
fieldInfo.setValue(destination, list);
}
list.add(mapValue);
} else {
// field is a Map: store as a single element map
fieldInfo.setValue(destination, mapValue);
}
} else {
// GenericXml: store as ArrayList of elements
GenericXml atom = (GenericXml) destination;
@SuppressWarnings("unchecked")
Collection<Object> list = (Collection<Object>) atom.get(fieldName);
if (list == null) {
list = new ArrayList<Object>(1);
atom.set(fieldName, list);
}
list.add(mapValue);
}
} else if (isArray || Types.isAssignableToOrFrom(fieldClass, Collection.class)) {
// TODO(yanivi): some duplicate code here; isolate into reusable methods
FieldInfo fieldInfo = FieldInfo.of(field);
Object elementValue = null;
Type subFieldType =
isArray ? Types.getArrayComponentType(fieldType) : Types.getIterableParameter(
fieldType);
Class<?> rawArrayComponentType =
Types.getRawArrayComponentType(context, subFieldType);
subFieldType = Data.resolveWildcardTypeOrTypeVariable(context, subFieldType);
Class<?> subFieldClass =
subFieldType instanceof Class<?> ? (Class<?>) subFieldType : null;
if (subFieldType instanceof ParameterizedType) {
subFieldClass = Types.getRawClass((ParameterizedType) subFieldType);
}
if (Data.isPrimitive(subFieldType)) {
elementValue = parseTextContentForElement(parser, context, false, subFieldType);
} else if (subFieldType == null || subFieldClass != null
&& Types.isAssignableToOrFrom(subFieldClass, Map.class)) {
elementValue = Data.newMapInstance(subFieldClass);
int contextSize = context.size();
if (subFieldType != null) {
context.add(subFieldType);
}
Type subValueType =
subFieldType != null && Map.class.isAssignableFrom(subFieldClass)
? Types.getMapValueParameter(subFieldType) : null;
subValueType = Data.resolveWildcardTypeOrTypeVariable(context, subValueType);
isStopped = parseElementInternal(parser,
context,
elementValue,
subValueType,
namespaceDictionary,
customizeParser);
if (subFieldType != null) {
context.remove(contextSize);
}
} else {
elementValue = Types.newInstance(rawArrayComponentType);
int contextSize = context.size();
context.add(fieldType);
isStopped = parseElementInternal(parser,
context,
elementValue,
null,
namespaceDictionary,
customizeParser);
context.remove(contextSize);
}
if (isArray) {
// array field: add new element to array value map
if (field == null) {
arrayValueMap.put(fieldName, rawArrayComponentType, elementValue);
} else {
arrayValueMap.put(field, rawArrayComponentType, elementValue);
}
} else {
// collection: add new element to collection
@SuppressWarnings("unchecked")
Collection<Object> collectionValue = (Collection<Object>) (field == null
? destinationMap.get(fieldName) : fieldInfo.getValue(destination));
if (collectionValue == null) {
collectionValue = Data.newCollectionInstance(fieldType);
setValue(collectionValue,
field,
destination,
genericXml,
destinationMap,
fieldName);
}
collectionValue.add(elementValue);
}
} else {
// not an array/iterable or a map, but we do have a field
Object value = Types.newInstance(fieldClass);
int contextSize = context.size();
context.add(fieldType);
isStopped = parseElementInternal(parser,
context,
value,
null,
namespaceDictionary,
customizeParser);
context.remove(contextSize);
setValue(value, field, destination, genericXml, destinationMap, fieldName);
}
}
if (isStopped || parser.getEventType() == XmlPullParser.END_DOCUMENT) {
isStopped = true;
break main;
}
break;
}
}
arrayValueMap.setValues();
return isStopped;
}