XStream 在转换器中获取父对象

XStream get parent object in converter

对于本地转换器,当编组到 XML 时,有没有办法访问父对象?

我需要使用存储在父对象中的 ID 来编组包含来自第三方来源的项目的集合。

唉,好像没有办法查询到当前对象的对象路径。还是有?

我找到了一个稍微反射的解决方案:

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.springframework.util.ReflectionUtils;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.path.Path;

import lombok.Data;

public class XStreamGetInfoFromParentTest {

    @Test
    public void smokeTest() {
        InputStream file = XStreamGetInfoFromParentTest.class.getResourceAsStream("XStreamGetInfoFromParentTest.xml");

        XStream xStream = new XStream() {
            @Override
            public void registerConverter(Converter converter, int priority) {
                Converter myConverter = new MyConverterWrapper(converter);
                super.registerConverter(myConverter, priority);
            }
        };
        xStream.processAnnotations(Papa.class);
        xStream.processAnnotations(Baby.class);

        Papa papa = (Papa) xStream.fromXML(file);

        System.out.println(papa);
    }

    public class MyConverterWrapper implements Converter {

        private Converter converter;
        private boolean isBabyClass;

        public MyConverterWrapper(Converter converter) {
            this.converter = converter;
        }

        @Override
        public boolean canConvert(Class type) {
            this.isBabyClass = type.equals(Baby.class);
            return converter.canConvert(type);
        }

        @Override
        public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
            this.converter.marshal(source, writer, context);
        }

        @SuppressWarnings({ "unchecked", "rawtypes" })
        @Override
        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
            if (isBabyClass) {
                AbstractReferenceUnmarshaller runm = (AbstractReferenceUnmarshaller) context;

                Field field = ReflectionUtils.findField(AbstractReferenceUnmarshaller.class, "values");
                field.setAccessible(true);
                Map values = (Map) ReflectionUtils.getField(field, runm);

                values.forEach((key, value) -> {
                    System.out.println(key + " : " + value);
                });

                Papa papa = (Papa) values.get(new Path("/papa"));
                System.out.println(papa.firstname);
            }

            return converter.unmarshal(reader, context);
        }

    }

    @XStreamAlias("papa")
    @Data
    public class Papa {

        @XStreamAsAttribute
        private String firstname;

        private int age;

        private List<Baby> babies;

    }

    @XStreamAlias("baby")
    @Data
    public class Baby {
        private String firstname;
    }

}

xml:

<?xml version="1.0" encoding="UTF-8"?>
<papa firstname="Adam">
        <age>33</age>
        <babies>  
            <baby>
                <firstname>Eva</firstname>
            </baby>
        </babies>
</papa>