JAXB RI ClassFactory中的空指针异常 [英] Null Pointer Exception in JAXB RI ClassFactory

查看:108
本文介绍了JAXB RI ClassFactory中的空指针异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我和我的朋友正在开发一个JavaFX应用程序,作为我们学校的规划师。我们有任务(课堂作业),活动,课程和学生信息。为了将数据持久存储在用户的硬盘驱动器上,我们正在使用JAXB。

My friend and I are working on a JavaFX application that acts as a planner for our school. We have tasks (homework for classes), events, courses and student info. In an attempt to store data persistently on the user's hard drive we are using JAXB.

我们已经注释了我们的类,并且可以在包装器中成功编组Task类。问题是从 tasks.xml 文件解组。

We have annotated our classes and can successfully marshall the Task class in a wrapper. The problem is unmarshalling from the tasks.xml file.

@XmlRootElement
public class Task {
    //constructors

    //complete constructor
    public Task(String className, String assignment, String description, LocalDate dueDate) {
        this.className = new SimpleStringProperty(className);
        this.assignment = new SimpleStringProperty(assignment);
        this.description = new SimpleStringProperty(description);

        this.dueDate = new SimpleObjectProperty<LocalDate>(dueDate);
    }

    /**
     * Sets a model data into the task, sets the 
     * due date to be tomorrow.
     */
    public Task() {
        this("", "", "", LocalDate.now().plusDays(1));

        setClassName("English");
        setAssignment("Read");
        setDescription("1984");

        //setDueDate(LocalDate.now());
    }
    //Instance variables

    private final SimpleStringProperty className;
    private final SimpleStringProperty assignment;
    private final SimpleStringProperty description;

    private final ObjectProperty<LocalDate> dueDate;

//  //Getters and setters

    //... Other getters and setters

    @XmlJavaTypeAdapter(LocalDateAdapter.class)
    public final java.time.LocalDate getDueDate() {
        return this.dueDateProperty().get();
    }
    public final void setDueDate(final java.time.LocalDate dueDate) {
        this.dueDateProperty().set(dueDate);
    }
}



TaskListWrapper.java:



TaskListWrapper.java:

    //used in saving the objects to XML

@XmlRootElement(name="tasks")
public class TaskListWrapper {

        private ObservableList<Task> task;

        @XmlElement(name="task")
        public ObservableList<Task> getTasks() {
            return task;
        }

        public void setTasks(ObservableList<Task> tasks) {
            this.task = tasks;
        }

}



AppData.java中的方法



它涉及从文件中保存和解组。

Method in AppData.java

It deals with saving to and unmarshalling from files.

/**
     * Save to XML using JAXB
     * @throws JAXBException 
     * @throws FileNotFoundException 
     */
    public static void save() throws JAXBException, FileNotFoundException {

        //saving other objects
        //...

        TaskListWrapper tl = new TaskListWrapper();

        //MasterTaskList is the entire list of tasks written to memory
        tl.setTasks(AppData.getMasterTaskList());

        saveObject(tl, new File(System.getProperty("user.dir") + "/resources/xml/tasks.xml"));

        saveObject(masterStudentInfo, new File(System.getProperty("user.dir") + "/resources/xml/student_info.xml"));
    }



同一类中的saveObject()方法:



saveObject() method in the same class:

/**
     * Saves a specific Object {@code obj} to an xml file {@code xml} using JAXB.
     * @param obj
     * @param xml
     * @throws FileNotFoundException
     * @throws JAXBException
     */
    private static void saveObject(Object obj, File xml) throws FileNotFoundException, JAXBException {
        //context is used to determine what kind of class is going to be marshalled or unmarshalled
        JAXBContext context = JAXBContext.newInstance(obj.getClass());

        //loads to the XML file
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        //loads the current list of courses to the courses.xml file
        m.marshal(obj, new FileOutputStream(xml));
    }



App.java中的InitFiles()



注意注释指出空指针异常

InitFiles() in App.java

Note the Comment pointing out the null pointer exception

/**
     * Initial setup for all the files for the program. Contains all the
     * persistent data for the planner, such as courses, tasks, and events.
     * <p>
     * All data is saved in {@code [place of installment]/resources/xml/...}.
     * @throws IOException
     */
    public void initFiles() throws IOException{

        //... other files for other objects

        File tasks = new File(System.getProperty("user.dir") + "/resources/xml/tasks.xml");

        //check if each file exists, if so unmarshall 
        if(tasks.exists()){
            try {
                JAXBContext context = JAXBContext.newInstance(TaskListWrapper.class);

                //the file location is correct
                System.out.println(tasks.toString());

                //The context knows that both the Task and TaskListWrapper classes exist
                System.out.println(context.toString());

                Unmarshaller um = context.createUnmarshaller();

                //TODO: null pointer exception
                TaskListWrapper taskList = (TaskListWrapper) um.unmarshal(tasks);
                //System.out.println(umObject.getClass());
            } catch (JAXBException e) {
                e.printStackTrace();
            }

        } else {
            tasks.createNewFile();
        }
        //... other checks for files
    }



< h2>来自编组的格式良好的XML文档:

Well-Formed XML document from the marshalling:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tasks>
    <task>
        <assignment>Book</assignment>
        <className>Math</className>
        <description>problems</description>
        <dueDate>2015-01-17</dueDate>
    </task>
    <task>
        <assignment>Textbook</assignment>
        <className>Religion</className>
        <description>problems</description>
        <dueDate>2015-01-17</dueDate>
    </task>
    <task>
        <assignment>Read</assignment>
        <className>English</className>
        <description>1984</description>
        <dueDate>2015-03-05</dueDate>
    </task>
</tasks>



例外情况:



The exception:

 java.lang.NullPointerException
    at com.sun.xml.internal.bind.v2.ClassFactory.create0(Unknown Source)
    at com.sun.xml.internal.bind.v2.ClassFactory.create(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.startPacking(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.startPacking(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Scope.add(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.property.ArrayERProperty$ReceiverImpl.receive(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.endElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at org.sjcadets.planner.App.initFiles(App.java:136)
    at org.sjcadets.planner.App.start(App.java:68)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(Unknown Source)
    at com.sun.javafx.application.LauncherImpl$$Lambda$51/1390460753.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(Unknown Source)
    at com.sun.javafx.application.PlatformImpl$$Lambda$45/1051754451.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$164(Unknown Source)
    at com.sun.javafx.application.PlatformImpl$$Lambda$47/231444107.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(Unknown Source)
    at com.sun.javafx.application.PlatformImpl$$Lambda$46/1775282465.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$141(Unknown Source)
    at com.sun.glass.ui.win.WinApplication$$Lambda$37/1109371569.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

空指针位于<$ c $中所述的 // TODO c> initFiles()方法:

The null pointer is at the //TODO stated in the initFiles() method:

JAXBContext context = JAXBContext.newInstance(TaskListWrapper.class);

                    //the file location is correct
                    System.out.println(tasks.toString());

                    //The context knows that both the Task and TaskListWrapper classes exist
                    System.out.println(context.toString());

                    Unmarshaller um = context.createUnmarshaller();

                    //TODO: null pointer exception
                    TaskListWrapper taskList = (TaskListWrapper) um.unmarshal(tasks);



我们尝试过的事情:




  • 弄乱名字和注释。这似乎不是命名问题。

  • 调用文件位置以确保它是正确的。

  • 系统播放 JAXBContext 知道。它识别任务 TaskListWrapper 类。

  • Sysouting um.toString()。它在内存中显示一个有效的地址,因此 um 对象本身不会抛出nullpointer异常。

  • 更改位置 TaskListWrapper.java Task.java 相同的包。

  • 尝试通过将XML文件更改为只有一个< task> 来解组单个任务,因为当我更改

    Things we have tried:

    • Messing with the names and annotations. It doesn't seem like naming is the issue.
    • Sysouting the File location to make sure it is correct.
    • Sysouting the classes that the JAXBContext knows. It recognizes both the Task and TaskListWrapper classes.
    • Sysouting um.toString(). It shows a valid address in memory, so the um object itself is not what is throwing the nullpointer exception.
    • Changing the location of TaskListWrapper.java to the same package as Task.java.
    • Trying to unmarshal a single Task by changing the XML file to have only one <task> as the root element works when I change

      TaskListWrapper taskList = (TaskListWrapper) um.unmarshal(tasks);
      

      Task taskList = (Task) um.unmarshal(tasks);
      


      • http://examples.javacodegeeks.com/core-java/xml/bind/jaxb-unmarshal-example/
      • A multitude of stackoverflow questions which had to do with bug with the @XMLAttribute annotation. Since we don't use those that bug is not relevant
      • Learning Java: 4th Edition by Patrick Niemeyer and Daniel Leuck. We have copied their exact way of setting up the unmarshaller. They have a simple approach:

      JAXBContext context = JAXBContext.newInstance(Inventory.class);
      Unmarshaller unmarshaller = context.createUnmarshaller();
      Inventory inventory = (Inventory) unmarshaller.unmarshall(
          new File("zooinventory.xml") );
      


      为什么 TaskListWrapper taskList =(TaskListWrapper)um.unmarshal(tasks); 抛出空指针异常?

      Why is TaskListWrapper taskList = (TaskListWrapper) um.unmarshal(tasks); throwing a null pointer exception?

      推荐答案

      JAXB与包装器中的ObservableList等FXCollections不兼容。您必须编写一个XmlAdapter来将其解开为正常的List。所以编组将起作用但不能解组,正如你在堆栈跟踪中看到的那样:

      JAXB isn't compatible to FXCollections like the ObservableList in your wrapper. You have to write an XmlAdapter to untangle it to a normal List. So marshalling will function but unmarshalling not, as you can see in the line of the stacktrace:

      at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.startPacking(Unknown Source)
      

      Lister $ CollectionLister ,它不知道如何处理未知来源。所以Adpater应该像这样使用ListWrapper:

      There is the Lister$CollectionLister which don't know what to do with the Unknown Source. So an Adpater should use a ListWrapper like this:

      public class TaskList {
      
        @XmlElement(name = "task")
        List<Task> entries = new ArrayList<>();
      
        public List<Task> getEntries() {
          return entries;
        }
      }
      

      相应的适配器如下所示:

      The corresponding Adapter look like this:

      public class TaskListAdapter extends XmlAdapter<TaskList, ObservableList<Task>> {
      
        @Override
        public ObservableList<Task> unmarshal(TaskList v) throws Exception {
          ObservableList<Task> list = FXCollections.observableArrayList(v.entries);
          return list;
        }
      
        @Override
        public TaskList marshal(ObservableList<Task> v) throws Exception {
          TaskList taskList = new TaskList();
          v.stream().forEach((item) -> {
            taskList.entries.add(item);
          });
          return taskList;
        }
      }
      

      这样你的TaskListWrapper最终应该是这样的:

      So that your TaskListWrapper should finaly look like this:

      //used in saving the objects to XML
      
      @XmlRootElement(name="tasks")
      public class TaskListWrapper {
      
              private ObservableList<Task> task;
      
      
              @XmlJavaTypeAdapter(TaskListAdapter.class)
              public ObservableList<Task> getTasks() {
                  return task;
              }
      
              public void setTasks(ObservableList<Task> tasks) {
                  this.task = tasks;
              }
      
      }
      

      顺便说一下,还有你使用了很多FX属性,所以也许你最好用 @XmlAccessorType(XmlAccessType.PROPERTY)注释你的类任务,并确保为每个字段设置一个getter / setter存在。就像FXProperties惯例所说:

      And by the way, there are a lot of FX Properties you use, so maybe you better annotate your class Task with @XmlAccessorType(XmlAccessType.PROPERTY) and make sure, that for every field to be set a getter/setter exist. Like the FXProperties convention says:

      private final StringProperty description = new SimpleStringProperty();
      public String getDescription() {
        return description.get();
      }
      public void setDescription(String description) {
        this.description.set(description);
      }
      public StringProperty descriptionProperty(){
        return description;
      }
      

      注释 @XmlAccessType(XmlAccessorType.PROPERTY)在此处详细描述: JAXB JavaDoc 。如果在包或类上没有注释,则默认值为 @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER),其中JavaDoc表示:

      The Annotation @XmlAccessType(XmlAccessorType.PROPERTY) is described in detail here: JAXB JavaDoc. If on a package or class nothing is annotated, than the default will be @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER), where the JavaDoc says:


      每个公共getter / setter对和每个公共字段都将自动绑定到
      ,除非通过XmlTransient注释。

      Every public getter/setter pair and every public field will be automatically bound to XML, unless annotated by XmlTransient.

      因此,在FX类(特殊模型)中,您尝试在私有字段中隐藏已使用的属性。但是如果你需要一个不应该编组的公共领域呢?然后我建议做 @XmlAccessorType(XmlAccessType.PROPERTY)注释。它的JavaDoc说:

      So in a FX class (a model in special) you try to hide the used properties in private fields. But what if you need a public field that should not be marshalled? Then I recommend doing the @XmlAccessorType(XmlAccessType.PROPERTY) annotation. The JavaDoc of it says:


      JAXB绑定类中的每个getter / setter对将自动绑定到XML的
      ,除非通过XmlTransient注释。

      Every getter/setter pair in a JAXB-bound class will be automatically bound to XML, unless annotated by XmlTransient.

      观察一个单词的差别 public ,所以如果用 @XmlAccessorType(XmlAccessType.PROPERTY)进行注释,即使是私人的getter / setter也会被考虑在内。

      Watch at the little difference in one word public, so if annotated with @XmlAccessorType(XmlAccessType.PROPERTY) even private getter/setter will be taken into account.

      但我认为大多数人使用 @XmlAccessorType(XmlAccessType.FIELD)其中JavaDoc说:

      But I think most of the people use @XmlAccessorType(XmlAccessType.FIELD) where the JavaDoc says:


      JAXB绑定类中的每个非静态非瞬态字段都将自动绑定到
      ,除非由XmlTransient注释。

      Every non static, non transient field in a JAXB-bound class will be automatically bound to XML, unless annotated by XmlTransient.

      在具有FX属性的FX类中,这可能有点棘手。我不推荐给你。

      This can be a bit tricky in an FX class with FX properties. I wouldn't recommend it to you.

      这篇关于JAXB RI ClassFactory中的空指针异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆