Marshall a List to XML works - but how to unmarshall?

久未见 提交于 2019-12-20 03:51:25

问题


I can marshall a ObservableList using a "Wrapper"-class like below. But I cannot unmarshall it back to the wrapperclass it was before.

The idea is: I have an ObservableList of "Expenses". I put this List into a wrapper-class and save this class to XML. The result looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<List>
    <root>
        <category>[none]</category>
        <period>Year</period>
        <title>asd</title>
        <value>354</value>
    </root>
</List>

I cannot bring it back to the wrapper-object. I really appreciate any kind of help.

Main-class JAXBContext (visible for all):

JAXBContext jc = JAXBContext.newInstance(MyWrapperForList.class, Expense.class);

Main-class SAVEBUTTON:

public class SaveButtonListener implements EventHandler<ActionEvent> {

    @Override
    public void handle(ActionEvent arg0) {

        File serializedFile = new File(PATH);

        try {
            if (serializedFile.exists() == false)
            serializedFile.createNewFile();

            PrintWriter xmlOut = new PrintWriter(serializedFile);

            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            List<Expense> saveList = new ArrayList<>();

            saveList.addAll(data);



            MyWrapperForList<Expense> wrapper = new MyWrapperForList<>(saveList);
                JAXBElement<MyWrapperForList> jaxbElement = new JAXBElement<>(
new QName("List"), MyWrapperForList.class, wrapper);



        m.marshal(jaxbElement, xmlOut);

            xmlOut.flush();
            xmlOut.close();

Main-class-LOADBUTTON:

public class LoadButtonListener implements EventHandler<ActionEvent> {

    @Override
    public void handle(ActionEvent arg0) {


        try {
            Unmarshaller unmarshaller = jc.createUnmarshaller();




StreamSource xml = new StreamSource(PATH);
                MyWrapperForList<Expense> unwrapper = unmarshaller.unmarshal(xml,
 MyWrapperForList.class).getValue();

            List<Expense> tempList = new ArrayList<>();
            tempList.addAll(unwrapper.getItems());


            System.out.println(tempList.get(0).getTitle());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Wrapper-class:

public class MyWrapperForList {

private List<Expense> list;

public MyWrapperForList() {
    list = new ArrayList<>();
}

public MyWrapperForList(List<Expense> expenses) {
    this.list = expenses;
}

@XmlAnyElement(lax=true)
public List<Expense> getItems() {
    return list;
}

}

Expense-class:

@XmlRootElement(name = "root") public class Expense {

private String title;
private String category;
private String period;
private String value;

public Expense() {} //Default constructor is needed for XML-handling

public Expense(String title, String value, String period, String category) {
    this.title = title;
    this.value = value;
    this.period = period;
    this.category = category;
}

@XmlElement(name = "title")
public String getTitle() {
    return this.title;
}

@XmlElement(name = "category")
public String getCategory() {
    return this.category;
}

@XmlElement(name = "period")
public String getPeriod() {
    return this.period;
}

@XmlElement(name = "value")
public String getValue() {
    return this.value;
}

}

I used this tutorial from Blaise Doughan: http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html


回答1:


MyListWrapper

If you want MyWrapperForList to unmarshal holding an instance of ObservableList then you will need to setup your class in one of the following ways.

Property of Type ObservableList

import javax.xml.bind.annotation.XmlAnyElement;
import javafx.collections.*;

public class MyWrapperForList<T> {

    private ObservableList<T> list;

    public MyWrapperForList() {
        list = FXCollections.<T>observableArrayList();
    }

    public MyWrapperForList(ObservableList<T> list) {
        this.list = list;
    }

    @XmlAnyElement(lax = true)
    public ObservableList<T> getItems() {
        return list;
    }

}

List Property Initialized to Instance of ObservableList

import java.util.List;
import javax.xml.bind.annotation.XmlAnyElement;
import javafx.collections.*;

public class MyWrapperForList<T> {

    private List<T> list = FXCollections.<T>observableArrayList();

    public MyWrapperForList() {
        list = FXCollections.<T>observableArrayList();
    }

    public MyWrapperForList(List<T> list) {
        this.list = list;
    }

    @XmlAnyElement(lax = true)
    public List<T> getItems() {
        return list;
    }

}

Demo Code

Input (nub.xml)

<List>
    <root>
        <category>[none]</category>
        <period>Year</period>
        <title>dfg</title>
        <value>4</value>
    </root>
    <root>
        <category>[none]</category>
        <period>Year</period>
        <title>ROBO</title>
        <value>1234</value>
    </root>
</List>

Demo

import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(MyWrapperForList.class, Expense.class);

        //UNMARSHALLING
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        StreamSource xml = new StreamSource("src/forum18594548/nub.xml");
        MyWrapperForList<Expense> wrapper = (MyWrapperForList<Expense>) unmarshaller.unmarshal(xml, MyWrapperForList.class).getValue();
        List<Expense> data = wrapper.getItems();

        System.out.println(data.getClass());
        for(Expense expense : data) {
            System.out.println(expense);
        }
   }

}

Output

class com.sun.javafx.collections.ObservableListWrapper
forum18594548.Expense@789df61d
forum18594548.Expense@4a8927c8

UPDATE

First: Thanks for you work Blaise!! I'm really glad for what you do to me! I tried what you wrote here (it was nearly the same as I had) and I got a similar (same type of) output as you got. BUT the objects in the lists are all referenced with null. If I write System.out.println(data.get(0).getTitle()); it says null. There is the exact amount of objects in the list, but all attributes are referenced with null. :(

I think I got tunnel vision on the ObservableList aspect only to miss your real problem was with how you mapped the Expense class. Since you only have get methods you should map to the fields using @XmlAccessorType(XmlAccessType.FIELD) as follows.

import javax.xml.bind.annotation.*;

@XmlRootElement(name="root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Expense {

    private String title;
    private String category;
    private String period;
    private String value;

    public Expense() {
    }

    public Expense(String title, String value, String period, String category) {
        this.title = title;
        this.value = value;
        this.period = period;
        this.category = category;
    }

    public String getTitle() {
        return this.title;
    }

    public String getCategory() {
        return this.category;
    }

    public String getPeriod() {
        return this.period;
    }

    public String getValue() {
        return this.value;
    }

}


来源:https://stackoverflow.com/questions/18594548/marshall-a-list-to-xml-works-but-how-to-unmarshall

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!