【问题标题】:Copying List in Setter makes XML Unmarshaller not work在 Setter 中复制 List 使 XML Unmarshaller 不起作用
【发布时间】:2022-02-03 13:53:29
【问题描述】:

我有一个这样的 DataBean:

@XmlRootElement
public class DataBean {
    private List<String> data;

    @XmlElement(name = "data")
    public List<String> getData() {
        return data != null ? Collections.unmodifiableList(data) : null;
    }

    public void setData(List<String> data) {
        data = new ArrayList<>(data);
        data.sort(Comparator.naturalOrder());
        this.data = data;
    }
}

在 DataBean 内部,列表必须排序,否则 DataBean 在我的域中不可用。为了避免副作用,我将列表复制到setter中,然后排序。

编组这个 bean 工作正常,但解组时,数据列表是空的(不是 null)。下面是一些代码来演示:

public class XmlTester {

    public static void main(String[] args) {
        List<String> data = Arrays.asList("one", "two", "three", "four");
        DataBean dataBean = new DataBean();
        dataBean.setData(data);
        System.out.printf("Data in original bean: %s%n%n", dataBean.getData().toString());

        try {
            String xmlString = serialize(dataBean);
            System.out.printf("XML:%n%s%n", xmlString);
            DataBean deserializedDataBean = deserialize(xmlString);
            System.out.printf("Data in deserialized bean: %s%n%n", deserializedDataBean.getData().toString());
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    private static String serialize(DataBean dataBean) throws JAXBException {
        StringWriter w = new StringWriter();
        JAXBContext jc = JAXBContext.newInstance(DataBean.class);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(dataBean, w);
        return w.toString();
    }

    private static DataBean deserialize(String xmlString) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(DataBean.class);
        Unmarshaller um = context.createUnmarshaller();
        return (DataBean) um.unmarshal(new StringReader(xmlString));
    }
}

这会产生以下输出:

Data in original bean: [four, one, three, two]

XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataBean>
    <data>four</data>
    <data>one</data>
    <data>three</data>
    <data>two</data>
</dataBean>

Data in deserialized bean: []

如果我从 bean 的 setter 中删除行 data = new ArrayList&lt;&gt;(data);,解组就像一个魅力,所以复制操作似乎是个问题。

为什么复制会使反序列化 bean 中的列表为空,我可以在不删除复制操作的情况下解决此问题吗?

当然,我可以测试数据是否已排序,如果不是,则抛出 IllegalArgumentException,但我更愿意在 setter 中对副本进行排序。

【问题讨论】:

    标签: java xml jaxb unmarshalling


    【解决方案1】:
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlRootElement
    public class DataBean {
    
    
        @XmlElement(name = "data")
        private List<String> data;
    
        public List<String> getData() {
            return data != null ? Collections.unmodifiableList(data) : null;
        }
    
        public void setData(List<String> data) {
            data = new ArrayList<>(data);
            data.sort(Comparator.naturalOrder());
            this.data = data;
        }
    }
    
    Data in original bean: [four, one, three, two]
    
    XML:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <dataBean>
        <data>four</data>
        <data>one</data>
        <data>three</data>
        <data>two</data>
    </dataBean>
    
    Data in deserialized bean: [four, one, three, two]
    

    【讨论】:

    • 是的,这解决了,谢谢!我猜如果你这样设置,解组器不使用设置器,而是使私有字段可访问并通过反射设置它?我仍然不明白为什么它以前不起作用,你能解释一下吗? :)
    • 这样访问字段还是通过setter和getter来访问的。我猜 XmlElement 在装饰方法时会忽略设置器。虽然 XmlElement 可以装饰方法,但 XmlElement 的 cmets 并不能解释装饰方法时的行为。
    • 我确实试了一下并调试过,你的版本中没有使用setter。
    • 我调试的时候setter和getter都用到了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多