in xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java [279:483]
public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader,
final UnmarshallingContext context) {
final Class<?> resultType = result.getClass();
@SuppressWarnings("serial")
final Set<FastField> seenFields = new HashSet<FastField>() {
@Override
public boolean add(final FastField e) {
if (!super.add(e)) {
throw new DuplicateFieldException(e.getName());
}
return true;
}
};
// process attributes before recursing into child elements.
final Iterator<String> it = reader.getAttributeNames();
while (it.hasNext()) {
final String attrAlias = it.next();
// TODO: realMember should return FastField
final String attrName = mapper.realMember(resultType, mapper.attributeForAlias(attrAlias));
final Field field = reflectionProvider.getFieldOrNull(resultType, attrName);
if (field != null && shouldUnmarshalField(field)) {
final Class<?> classDefiningField = field.getDeclaringClass();
if (!mapper.shouldSerializeMember(classDefiningField, attrName)) {
continue;
}
// we need a converter that produces a string representation only
Class<?> type = field.getType();
final SingleValueConverter converter = mapper.getConverterFromAttribute(classDefiningField, attrName,
type);
if (converter != null) {
final Object value = converter.fromString(reader.getAttribute(attrAlias));
if (type.isPrimitive()) {
type = Primitives.box(type);
}
if (value != null && !type.isAssignableFrom(value.getClass())) {
final ConversionException exception = new ConversionException("Cannot convert type");
exception.add("source-type", value.getClass().getName());
exception.add("target-type", type.getName());
throw exception;
}
seenFields.add(new FastField(classDefiningField, attrName));
reflectionProvider.writeField(result, attrName, value, classDefiningField);
}
}
}
Map<FieldLocation, Collection<? super Object>> implicitCollectionsForCurrentObject = null;
while (reader.hasMoreChildren()) {
reader.moveDown();
final String originalNodeName = reader.getNodeName();
final Class<?> explicitDeclaringClass = readDeclaringClass(reader);
final Class<?> fieldDeclaringClass = explicitDeclaringClass == null ? resultType : explicitDeclaringClass;
final String fieldName = mapper.realMember(fieldDeclaringClass, originalNodeName);
final Mapper.ImplicitCollectionMapping implicitCollectionMapping = mapper
.getImplicitCollectionDefForFieldName(fieldDeclaringClass, fieldName);
final Object value;
String implicitFieldName = null;
Field field = null;
Class<?> type = null;
if (implicitCollectionMapping == null) {
// no item of an implicit collection for this name ... do we have a field?
field = reflectionProvider.getFieldOrNull(fieldDeclaringClass, fieldName);
if (field == null) {
// it is not a field ... do we have a field alias?
final Class<?> itemType = mapper.getItemTypeForItemFieldName(fieldDeclaringClass, fieldName);
if (itemType != null) {
final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
if (classAttribute != null) {
type = mapper.realClass(classAttribute);
} else {
type = itemType;
}
} else {
// it is not an alias ... do we have an element of an implicit
// collection based on type only?
try {
type = mapper.realClass(originalNodeName);
implicitFieldName = mapper.getFieldNameForItemTypeAndName(fieldDeclaringClass, type,
originalNodeName);
} catch (final 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, fieldDeclaringClass,
originalNodeName);
// element is unknown in declaring class, ignore it now
type = null;
}
}
if (type == null) {
// no type, no value
value = null;
} else {
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;
// we have a field, but do we have to address a hidden one?
if (explicitDeclaringClass == null) {
while (field != null
&& !(fieldAlreadyChecked = shouldUnmarshalField(field)
&& mapper.shouldSerializeMember(field.getDeclaringClass(), fieldName))) {
field = reflectionProvider.getFieldOrNull(field.getDeclaringClass().getSuperclass(),
fieldName);
}
}
if (field != null
&& (fieldAlreadyChecked
|| shouldUnmarshalField(field)
&& mapper.shouldSerializeMember(field.getDeclaringClass(), fieldName))) {
final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
if (classAttribute != null) {
type = mapper.realClass(classAttribute);
} else {
type = mapper.defaultImplementationOf(field.getType());
}
// TODO the reflection provider should already return the proper field
value = unmarshallField(context, result, type, field);
final Class<?> definedType = field.getType();
if (!definedType.isPrimitive()) {
type = definedType;
}
} else {
value = null;
}
}
} else {
// we have an implicit collection with defined names
implicitFieldName = implicitCollectionMapping.getFieldName();
type = implicitCollectionMapping.getItemType();
if (type == null) {
final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
type = mapper.realClass(classAttribute != null ? classAttribute : originalNodeName);
}
value = context.convertAnother(result, type);
}
if (value != null && !type.isAssignableFrom(value.getClass())) {
throw new ConversionException("Cannot convert type "
+ value.getClass().getName()
+ " to type "
+ type.getName());
}
if (field != null) {
reflectionProvider.writeField(result, fieldName, value, field.getDeclaringClass());
seenFields.add(new FastField(field.getDeclaringClass(), fieldName));
} else if (type != null) {
if (implicitFieldName == null) {
// look for implicit field
implicitFieldName = mapper.getFieldNameForItemTypeAndName(fieldDeclaringClass, value != null
? value.getClass()
: Mapper.Null.class, originalNodeName);
}
if (implicitCollectionsForCurrentObject == null) {
implicitCollectionsForCurrentObject = new HashMap<>();
}
writeValueToImplicitCollection(value, implicitCollectionsForCurrentObject, result, new FieldLocation(
implicitFieldName, fieldDeclaringClass));
}
reader.moveUp();
}
if (implicitCollectionsForCurrentObject != null) {
for (final Map.Entry<FieldLocation, Collection<? super Object>> entry : implicitCollectionsForCurrentObject
.entrySet()) {
final Object value = entry.getValue();
if (value instanceof ArraysList) {
final Object array = ((ArraysList)value).toPhysicalArray();
final FieldLocation fieldLocation = entry.getKey();
final Field field = reflectionProvider.getFieldOrNull(fieldLocation.definedIn,
fieldLocation.fieldName);
reflectionProvider.writeField(result, fieldLocation.fieldName, array, field != null
? field.getDeclaringClass()
: null);
}
}
}
return result;
}