public Object unmarshal()

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