public Object doUnmarshal()

in xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java [322:484]


    public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader,
            final UnmarshallingContext context) {
        // this is an array as it's a non final value that's accessed from an anonymous inner class.
        final Class<?>[] currentType = new Class<?>[1];

        final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_SERIALIZATION);
        if (attributeName != null && !ATTRIBUTE_VALUE_CUSTOM.equals(reader.getAttribute(attributeName))) {
            throw new ConversionException("Cannot deserialize object with new readObject()/writeObject() methods");
        }

        final CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() {
            @Override
            public Object readFromStream() {
                reader.moveDown();
                final Class<?> type = HierarchicalStreams.readClassType(reader, mapper);
                final Object value = context.convertAnother(result, type);
                reader.moveUp();
                return value;
            }

            @Override
            public Map<String, Object> readFieldsFromStream() {
                final Map<String, Object> fields = new HashMap<>();
                reader.moveDown();
                if (reader.getNodeName().equals(ELEMENT_FIELDS)) {
                    // Maintain compatibility with XStream 1.1.0
                    while (reader.hasMoreChildren()) {
                        reader.moveDown();
                        if (!reader.getNodeName().equals(ELEMENT_FIELD)) {
                            throw new ConversionException("Expected <"
                                + ELEMENT_FIELD
                                + "/> element inside <"
                                + ELEMENT_FIELD
                                + "/>");
                        }
                        final String name = reader.getAttribute(ATTRIBUTE_NAME);
                        final Class<?> type = mapper.realClass(reader.getAttribute(ATTRIBUTE_CLASS));
                        final Object value = context.convertAnother(result, type);
                        fields.put(name, value);
                        reader.moveUp();
                    }
                } else if (reader.getNodeName().equals(ELEMENT_DEFAULT)) {
                    // New format introduced in XStream 1.1.1
                    final ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]);
                    while (reader.hasMoreChildren()) {
                        reader.moveDown();
                        final String name = mapper.realMember(currentType[0], reader.getNodeName());
                        if (mapper.shouldSerializeMember(currentType[0], name)) {
                            final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
                            Class<?> type;
                            if (classAttribute != null) {
                                type = mapper.realClass(classAttribute);
                            } else {
                                final ObjectStreamField field = objectStreamClass.getField(name);
                                if (field == null) {
                                    throw new MissingFieldException(currentType[0].getName(), name);
                                }
                                type = field.getType();
                            }
                            final Object value = context.convertAnother(result, type);
                            fields.put(name, value);
                        }
                        reader.moveUp();
                    }
                } else {
                    throw new ConversionException("Expected <"
                        + ELEMENT_FIELDS
                        + "/> or <"
                        + ELEMENT_DEFAULT
                        + "/> element when calling ObjectInputStream.readFields()");
                }
                reader.moveUp();
                return fields;
            }

            @Override
            public void defaultReadObject() {
                if (serializationMembers.getSerializablePersistentFields(currentType[0]) != null) {
                    readFieldsFromStream();
                    return;
                }
                if (!reader.hasMoreChildren()) {
                    return;
                }
                reader.moveDown();
                if (!reader.getNodeName().equals(ELEMENT_DEFAULT)) {
                    throw new ConversionException("Expected <" + ELEMENT_DEFAULT + "/> element in readObject() stream");
                }
                while (reader.hasMoreChildren()) {
                    reader.moveDown();

                    final String fieldName = mapper.realMember(currentType[0], reader.getNodeName());
                    if (mapper.shouldSerializeMember(currentType[0], fieldName)) {
                        final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
                        final Class<?> type;
                        if (classAttribute != null) {
                            type = mapper.realClass(classAttribute);
                        } else {
                            type = mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName,
                                currentType[0]));
                        }

                        final Object value = context.convertAnother(result, type);
                        reflectionProvider.writeField(result, fieldName, value, currentType[0]);
                    }

                    reader.moveUp();
                }
                reader.moveUp();
            }

            @Override
            public void registerValidation(final ObjectInputValidation validation, final int priority) {
                context.addCompletionCallback(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            validation.validateObject();
                        } catch (final InvalidObjectException e) {
                            throw new ObjectAccessException("Cannot validate object", e);
                        }
                    }
                }, priority);
            }

            @Override
            public void close() {
                throw new UnsupportedOperationException(
                    "Objects are not allowed to call ObjectInputStream.close() from readObject()");
            }
        };

        while (reader.hasMoreChildren()) {
            reader.moveDown();
            final String nodeName = reader.getNodeName();
            if (nodeName.equals(ELEMENT_UNSERIALIZABLE_PARENTS)) {
                super.doUnmarshal(result, reader, context);
            } else {
                final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper);
                if (classAttribute == null) {
                    currentType[0] = mapper.defaultImplementationOf(mapper.realClass(nodeName));
                } else {
                    currentType[0] = mapper.realClass(classAttribute);
                }
                if (serializationMembers.supportsReadObject(currentType[0], false)) {
                    @SuppressWarnings("resource")
                    final CustomObjectInputStream objectInputStream = CustomObjectInputStream.getInstance(context,
                        callback, classLoaderReference);
                    serializationMembers.callReadObject(currentType[0], result, objectInputStream);
                    objectInputStream.popCallback();
                } else {
                    try {
                        callback.defaultReadObject();
                    } catch (final IOException e) {
                        throw new StreamException("Cannot read defaults", e);
                    }
                }
            }
            reader.moveUp();
        }

        return result;
    }