2015-08-21 96 views
1

我正在製作此示例GUI,它只是將計算機部件從一側移動到另一側,並具有將列表(以xml形式)加載並保存到桌面的功能。一切工作正常,除了重新加載保存的XML文件。我認爲這與Save.java中的註釋有關。這就是說我不確定需要什麼或如果這是問題。任何幫助將不勝感激。JAXB解組返回空

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> 
+0

由於您的問題是XML的解組,所以Window.java和ActionListeners.java可能與您的問題無關,但xml.xml的內容非常相關。請參閱http://stackoverflow.com/help/mcve – Andreas

+0

@Andreas我添加了其他文件,以防某些方式與他們的情況相關。 –

+0

請參閱我提供的MCVE鏈接。我指的是「最小」部分,您儘可能簡潔地陳述您的問題,因此Stack Overflow中的好人不需要浪費時間讀取無用的信息。我的第二點是你需要提供'xml.xml'的內容,如果Save.java沒問題,我們還有什麼可以幫助確定嗎? – Andreas

回答

1

Save.java類需要一個適當的setter方法:

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

爲了驗證這一點,我創建的文件xml.xml

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

並配有測試類:

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); 
} 

有了您Save.java,它與NPE失敗。添加setter工作。

最小,完整和可驗證


注意

你的問題部分是基於一種誤解。

的JAXB解組(調用jaxbUnmarshaller.unmarshal(file);)不返回null - 它返回的Save一個實例,因爲它應該。 unmarshal()本身從不返回null(請參閱API docs of Unmarshaller:「解組方法永不返回空值。」) - 但是它返回的實例中的字段可能是null

在這種情況下,字段Save.partsListSavenull,因爲JAXB無法設置它,因爲沒有合適的設置器,如上所述。

您看到的NullPointerException是由於嘗試使用getPartsList()返回的值null而導致的。

+0

ahhh我明白了。非常感謝你。看起來我不明白,當寫作班級用於閱讀和寫作,他們不能有任何額外的內容?我不確定這100%是否正確,但有幫助。再次感謝。 –

+0

你的Swing代碼需要一種設置值的方法,Marshaller需要一種設置值的方法,因此爲每個方法提供一種方法是適當的。現在,您可以考慮將Swing代碼放在其他Swing代碼所在的位置,並保留類保存「乾淨」的XML類。在這種情況下,你的Swing代碼也會使用'setPartsList(String [])'方法。 – Andreas

+0

爲了完整起見,unmarshaller不返回null(它不能),它返回一個非Save的''Save'實例。但是,裏面的字段是'null'。我提交了一個編輯來澄清。 – sleske