in xstream/src/java/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java [221:325]
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
final Object result = reflectionProvider.newInstance(context.getRequiredType());
final Class<?> resultType = result.getClass();
final Set<FastField> seenFields = new HashSet<>();
final Iterator<String> it = reader.getAttributeNames();
final Set<String> systemAttributes = new HashSet<>();
systemAttributes.add(mapper.aliasForSystemAttribute("class"));
// Process attributes before recursing into child elements.
while (it.hasNext()) {
final String attrName = it.next();
if (systemAttributes.contains(attrName)) {
continue;
}
final String fieldName = mapper.realMember(resultType, attrName);
final Field field = reflectionProvider.getFieldOrNull(resultType, fieldName);
if (field != null) {
if (Modifier.isTransient(field.getModifiers())) {
continue;
}
Class<?> type = field.getType();
final Class<?> declaringClass = field.getDeclaringClass();
ConverterMatcher converter = Enum.class.isAssignableFrom(type) ? (ConverterMatcher)enumMapper
.getConverterFromItemType(null, type, null) : (ConverterMatcher)mapper.getLocalConverter(
declaringClass, fieldName);
if (converter == null) {
converter = lookup.lookupConverterForType(type);
}
if (!(converter instanceof SingleValueConverter)) {
final ConversionException exception = new ConversionException(
"Cannot read field as a single value for object");
exception.add("field", fieldName);
exception.add("type", resultType.getName());
throw exception;
}
if (converter != null) {
final Object value = ((SingleValueConverter)converter).fromString(reader.getAttribute(attrName));
if (type.isPrimitive()) {
type = Primitives.box(type);
}
if (value != null && !type.isAssignableFrom(value.getClass())) {
final ConversionException exception = new ConversionException("Cannot assign object to type");
exception.add("object type", value.getClass().getName());
exception.add("target type", type.getName());
throw exception;
}
reflectionProvider.writeField(result, fieldName, value, declaringClass);
if (!seenFields.add(new FastField(declaringClass, fieldName))) {
throw new DuplicateFieldException(fieldName + " [" + declaringClass.getName() + "]");
}
}
}
}
if (valueField != null) {
final Class<?> classDefiningField = valueField.getDeclaringClass();
final String fieldName = valueField.getName();
final Field field = fieldName == null ? null : reflectionProvider.getField(classDefiningField, fieldName);
if (fieldName == null || field == null) {
final ConversionException exception = new ConversionException("Cannot assign value to field of type");
exception.add("element", reader.getNodeName());
exception.add("field", fieldName);
exception.add("target type", context.getRequiredType().getName());
throw exception;
}
Class<?> type;
final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
if (classAttribute != null) {
type = mapper.realClass(classAttribute);
} else {
type = mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName,
classDefiningField));
}
final Object value = context.convertAnother(result, type, mapper.getLocalConverter(field
.getDeclaringClass(), field.getName()));
final Class<?> definedType = reflectionProvider.getFieldType(result, fieldName, classDefiningField);
if (!definedType.isPrimitive()) {
type = definedType;
}
if (value != null && !type.isAssignableFrom(value.getClass())) {
final ConversionException exception = new ConversionException("Cannot assign object to type");
exception.add("object type", value.getClass().getName());
exception.add("target type", type.getName());
throw exception;
}
reflectionProvider.writeField(result, fieldName, value, classDefiningField);
if (!seenFields.add(new FastField(classDefiningField, fieldName))) {
throw new DuplicateFieldException(fieldName + " [" + classDefiningField.getName() + "]");
}
}
return result;
}