private static Object parseValue(Type valueType, List<Type> context, String value) { valueType = Data.resolveWildcardTypeOrTypeVariable(context, valueType); if (valueType == Double.class || valueType == double.class) { if (value.equals("INF")) { return new Double(Double.POSITIVE_INFINITY); } if (value.equals("-INF")) { return new Double(Double.NEGATIVE_INFINITY); } } if (valueType == Float.class || valueType == float.class) { if (value.equals("INF")) { return Float.POSITIVE_INFINITY; } if (value.equals("-INF")) { return Float.NEGATIVE_INFINITY; } } return Data.parsePrimitiveValue(valueType, value); }
/** * Returns whether the customize parser has requested to stop or reached end of document. * Otherwise, identical to {@link #parseElement(XmlPullParser, Object, XmlNamespaceDictionary, * CustomizeParser)} . */ private static boolean parseElementInternal( XmlPullParser parser, ArrayList<Type> context, Object destination, Type valueType, XmlNamespaceDictionary namespaceDictionary, CustomizeParser customizeParser) throws IOException, XmlPullParserException { // TODO(yanivi): method is too long; needs to be broken down into smaller methods and comment // better GenericXml genericXml = destination instanceof GenericXml ? (GenericXml) destination : null; @SuppressWarnings("unchecked") Map<String, Object> destinationMap = genericXml == null && destination instanceof Map<?, ?> ? Map.class.cast(destination) : null; ClassInfo classInfo = destinationMap != null || destination == null ? null : ClassInfo.of(destination.getClass()); if (parser.getEventType() == XmlPullParser.START_DOCUMENT) { parser.next(); } parseNamespacesForElement(parser, namespaceDictionary); // generic XML if (genericXml != null) { genericXml.namespaceDictionary = namespaceDictionary; String name = parser.getName(); String namespace = parser.getNamespace(); String alias = namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(namespace); genericXml.name = alias.length() == 0 ? name : alias + ":" + name; } // attributes if (destination != null) { int attributeCount = parser.getAttributeCount(); for (int i = 0; i < attributeCount; i++) { // TODO(yanivi): can have repeating attribute values, e.g. "@a=value1 @a=value2"? String attributeName = parser.getAttributeName(i); String attributeNamespace = parser.getAttributeNamespace(i); String attributeAlias = attributeNamespace.length() == 0 ? "" : namespaceDictionary.getNamespaceAliasForUriErrorOnUnknown(attributeNamespace); String fieldName = getFieldName(true, attributeAlias, attributeNamespace, attributeName); Field field = classInfo == null ? null : classInfo.getField(fieldName); parseAttributeOrTextContent( parser.getAttributeValue(i), field, valueType, context, destination, genericXml, destinationMap, fieldName); } } Field field; ArrayValueMap arrayValueMap = new ArrayValueMap(destination); boolean isStopped = false; // TODO(yanivi): support Void type as "ignore" element/attribute 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; default: 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; }