简体   繁体   中英

JAXB unmarshalling returning Null

I'm making this example GUI that simply moves computer parts from one side to another, with the ability to load and save list (in xml) to the desktop. Everything works fine except for the reloading of saved xml files. I think it has something to do with the annotations in the Save.java. That being said I'm not sure what is needed or if that is the issue. Any help will be appreciated.

Window.java

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.BorderLayout;

import javax.swing.JButton;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.DefaultListModel;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JMenu;
import javax.swing.ListSelectionModel;

import java.awt.Component;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;

import javax.swing.BoxLayout;
import javax.swing.JList;

import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;

public class Window {

    private JFrame frame;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Window window = new Window();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public Window() {
        initialize();
    }

    public void addTo(JPanel displayPanel, Component contentToAdd)
    {
        displayPanel.add(contentToAdd);
    }

    public void initialize() {

        //setting the dimension for the JList panels
        Dimension sidePanelSize = new Dimension(180, 540);

        frame = new JFrame();
        frame.setBounds(100, 100, 480, 540);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Creating the menu bar 
        JMenuBar menuBar = new JMenuBar();
        frame.setJMenuBar(menuBar);

        //adding File option to menu bar
        JMenu mnFile = new JMenu("File");
        menuBar.add(mnFile);

        //adding load option to File
        JMenuItem mntmLoad = new JMenuItem("Load");
        mnFile.add(mntmLoad);

        //adding save option to File
        JMenuItem mntmSave = new JMenuItem("Save");
        mnFile.add(mntmSave);

        //adding exit option to File
        JMenuItem mntmExit = new JMenuItem("Exit");
        mnFile.add(mntmExit);

        //creating Jpanel that will hold JList for computer parts 
        //that you can choose 
        final JPanel itemPanel = new JPanel();
        itemPanel.setPreferredSize(sidePanelSize);
        itemPanel.setBackground(Color.WHITE);
        itemPanel.setLayout(new BorderLayout());

        //Create the model that will hold the computer items
        //For loop to add the strings to the model
        DefaultListModel<String> model = new DefaultListModel<>();
        for (String items : new String [] {"Case", "Motherboard", "CPU", "GPU", "PSU", "RAM", "HDD"})
            model.addElement(items);
        //Create JList(itemList) and set its model to the one 
        //holding the computer parts
        final JList<String> itemList = new JList<>(model);

        //Setting attributes for the JList(itemList) - font, Number of elements you can select at a time
        itemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        itemList.setFont(new Font("SegoeUI", Font.BOLD, 11));
        //adding the JList to the Panel
        itemPanel.add(itemList, BorderLayout.WEST);
        //adding the Panel to the frame
        frame.getContentPane().add(itemPanel, BorderLayout.WEST);

        //creating two panels that are used for centering the JList buttons
        JPanel buttonContainer = new JPanel();
        JPanel buttonList = new JPanel();
        GridBagConstraints c = new GridBagConstraints();

        //setting the layout managers for the panels and 
        //adding color to the background
        buttonList.setLayout(new BoxLayout(buttonList, BoxLayout.Y_AXIS));
        buttonContainer.setLayout(new GridBagLayout());
        buttonContainer.setBackground(new Color(238, 238, 238));

        //adding the button to add content from Jlist on the left(itemList)
        //to the right JList(addToList)
        JButton addButton = new JButton(">>");
        buttonList.add(addButton);

        //adding the button to remove content form the JList(addToList)
        JButton deleteButton = new JButton("<<");
        buttonList.add(deleteButton);

        //setting where to start inputing element into the
        //grid of the ButtonContainer
        c.gridx = 0;
        c.gridy = 0;

        //adding the button panel container and its constraints 
        //to the main container
        //finally adding it all to the main frame
        buttonContainer.add(buttonList, c);
        frame.getContentPane().add(buttonContainer, BorderLayout.CENTER);

        //creating the JList that we will add and remove from
        final JList<String> addToList = new JList<>(new DefaultListModel<String>());

        //creating the panel to hold the JList(addToList)
        //setting its size and layout in the manager
        //finally adding it to the main frame
        final JPanel displayPanel = new JPanel();
        displayPanel.setPreferredSize(sidePanelSize);
        displayPanel.setBackground(Color.WHITE);
        displayPanel.add(addToList, BorderLayout.EAST);
        frame.getContentPane().add(displayPanel, BorderLayout.EAST);    



        //Here is all the action listeners for button click events and menu events
        //contains all the methods for the action events
        final ActionListeners b = new ActionListeners();

        //Listener that adds selected computer parts from left JList(itemList) to the right JList(addToList)
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                b.addContent(itemList, addToList);
            }
        });

        //Listener that removes selected computer part from the JList(addToList) 
        deleteButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                b.removeContent(addToList);
            }
        });

        //Listener that calls the save methods to save JList(addToList) content into xml
        mntmSave.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                b.saveContent((DefaultListModel<String>) addToList.getModel());
            }
        });

        //Listener that call the load methods to load xml into the JList(addToList)
        mntmLoad.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                b.loadContent(addToList);
            }
        });

        //Exits the program entirely 
        mntmExit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                b.exitProgram();
            }
        });
    }
}

Load.java

import java.io.File;

import javax.swing.DefaultListModel;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;


public class Load {
    //loads the file into the JList to be displayed in the program
    public DefaultListModel<String> loadXMLFile() {
        //array that holds the content from the xml file

        //model that will have xml file's content added to it 
        //from the array
        DefaultListModel<String> modelToReturn = new DefaultListModel<>();
        String[] partsList = null;

        try {
            String homeDir = System.getProperty("user.home");
            File file = new File(homeDir + "/Desktop/xml.xml");

            JAXBContext jaxbContext = JAXBContext.newInstance(Save.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

            Save load = (Save) jaxbUnmarshaller.unmarshal(file);
            partsList = new String [load.getPartsList().length];

          } catch (JAXBException e) {
            e.printStackTrace();
          }

        //adds the strings in the arrayToReturn
        //to the model that will be returned
        for(int i = 0; i < partsList.length; i++)
        {
            modelToReturn.addElement(partsList[i]);
        }

        return modelToReturn;
    }
}

ActionListeners.java

import java.io.File;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class ActionListeners {

    public void addContent(JList<String> itemList, JList<String> addToList)
    {
        //gets the value selected to be added to other other JList
        List<String> selected = itemList.getSelectedValuesList();
        //gets the model of the List to be added too
        DefaultListModel<String> displayModel = (DefaultListModel<String>) addToList.getModel();

        //adds the elements to the JList
        for (String item: selected) 
        {
            displayModel.addElement(item);
        }
    }

    public void removeContent(JList<String> addToList)
    {
        //gets the element selected to be removed
        List<String> selected = addToList.getSelectedValuesList();
        //gets the model of the JList where content will be removed
        DefaultListModel<String> displayModel = (DefaultListModel<String>) addToList.getModel();

        //removes the selected element
        for (String item: selected) {
            displayModel.removeElement(item);
        }
    }

    public void saveContent(DefaultListModel<String> addToList)
    {
        Save saveFile = new Save();
        //adds the content in the JList to be saved
        //to the object
        saveFile.setPartsList(addToList);

        try {
            JAXBContext jaxbContext = 
                    JAXBContext.newInstance(Save.class);
            Marshaller jaxbMarshaller = 
                    jaxbContext.createMarshaller();
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            String homeDir = System.getProperty("user.home");

            jaxbMarshaller.marshal(saveFile, new File(homeDir + "/Desktop", "xml.xml"));

            jaxbMarshaller.marshal(saveFile, System.out);
        } catch (JAXBException e) {
            e.printStackTrace();
        }

        //saves the content
        //saveFile.saveFileXml();
    }

    public void loadContent(JList<String> addToList)
    {
        Load loadFile = new Load();
        //gets the model of the JList that loaded content will be added too
        DefaultListModel<String> newModel= (DefaultListModel<String>) addToList.getModel();
        //makes sure the model is clear
        newModel.removeAllElements();
        //makes model that the loaded content will be set too
        DefaultListModel<String> loadedModel = loadFile.loadXMLFile();

        //adds the loaded elements from the file to JList's model
        for(int i = 0; i < loadedModel.getSize(); i++)
        {
            newModel.addElement(loadedModel.get(i));
        }
    }

    public void exitProgram()
    {
        //closes the entire program
        System.exit(0);
    }
}

Save.java

import javax.swing.DefaultListModel;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


@XmlRootElement (name = "lists")
public class Save {
    //array that will hold the content to be saved
    String[] partsListSave;

    //method to set the array partsListSave
    //with the content that will be saved
     public void setPartsList(DefaultListModel<String> model) {
         //Initialize the array with the length of the content
         //to be added
         partsListSave = new String[model.getSize()];

         //adds the content to the array
         for (int i = 0; i < model.getSize(); i++)
         {
             partsListSave[i] = model.getElementAt(i);
         }
     } 

    @XmlElement (name = "parts")
    public String[] getPartsList() {
        return partsListSave;
    }
}

xml.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<lists>
    <parts>Motherboard</parts>
    <parts>Motherboard</parts>
    <parts>Motherboard</parts>
    <parts>Motherboard</parts>
</lists>

Your Save.java class needs an appropriate setter method:

public void setPartsList(String[] partsListSave) {
    this.partsListSave = partsListSave;
}

To verify this, I created file xml.xml :

<lists>
    <parts>Part 1</parts>
    <parts>Part 2</parts>
    <parts>Part 3</parts>
</lists>

And a test class with:

public static void main(String[] args) throws Exception {
    File file = new File("xml.xml");

    JAXBContext jaxbContext = JAXBContext.newInstance(Save.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    Save load = (Save) jaxbUnmarshaller.unmarshal(file);

    for (String parts : load.getPartsList())
        System.out.println(parts);
}

With your Save.java , it failed with NPE. Adding the setter worked.

Minimal, Complete, and Verifiable .


Note

Your question is partly based on a misunderstanding.

The JAXB unmarshaller (the call to jaxbUnmarshaller.unmarshal(file); ) does not return null - it returns an instance of Save , as it should. unmarshal() itself never returns null (see API docs of Unmarshaller : "An unmarshal method never returns null.") - however the fields in the instance it returns may be null .

In this case the field Save.partsListSave is null , because JAXB cannot set it, since there is no appropriate setter, as explained above.

The NullPointerException you see is caused by trying to use the value returned by getPartsList() , which is null .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM