gpt4 book ai didi

java - JAXB RI ClassFactory 中的空指针异常

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:54:37 26 4
gpt4 key购买 nike

介绍

我和我的 friend 正在开发一个 JavaFX 应用程序,它充当我们学校的规划师。我们有任务(类作业)、 Activity 、类(class)和学生信息。为了尝试将数据持久存储在用户的硬盘上,我们使用 JAXB。

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

以下是相关的代码行:

任务.java

@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:

    //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 中的方法

它处理文件的保存和解码。

/**
* 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() 方法:

/**
* 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()

注意指出空指针异常的注释

/**
* 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
}

来自编码的格式良好的 XML 文档:

<?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>

异常:

 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)

空指针在//TODOinitFiles() 中说明方法:

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

我们尝试过的事情:

  • 弄乱名称和注释。命名似乎不是问题所在。
  • 检查文件位置以确保它是正确的。
  • Sysouting JAXBContext 的类知道。它同时识别 TaskTaskListWrapper类。
  • 系统调度 um.toString() .它显示内存中的有效地址,因此 um对象本身不是引发空指针异常的原因。
  • 更改 TaskListWrapper.java 的位置到与 Task.java 相同的包裹.
  • 尝试通过将 XML 文件更改为只有一个来解码单个任务 <task>因为根元素在我更改时有效

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

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

我们寻找答案的地方:

  • http://examples.javacodegeeks.com/core-java/xml/bind/jaxb-unmarshal-example/
  • 大量与 @XMLAttribute 的错误有关的 stackoverflow 问题注解。由于我们不使用那些错误不相关的
  • 学习 Java:第 4 版,作者:Patrick Niemeyer 和 Daniel Leuck。我们已经复制了他们设置解码器的确切方法。他们有一个简单的方法:

    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);抛出空指针异常?

最佳答案

JAXB 与包装器中的 ObservableList 等 FXCollections 不兼容。您必须编写一个 XmlAdapter 以将其解开为一个普通列表。因此编码将起作用但解码不起作用,正如您在堆栈跟踪行中看到的那样:

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

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

public class TaskList {

@XmlElement(name = "task")
List<Task> entries = new ArrayList<>();

public List<Task> getEntries() {
return entries;
}
}

相应的 Adapter 如下所示:

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 最终应该看起来像这样:

//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 约定所说:

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 说:

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

因此在 FX 类(特殊模型)中,您尝试将使用的属性隐藏在私有(private)字段中。但是,如果您需要一个不应编码的公共(public)字段怎么办?然后我建议执行 @XmlAccessorType(XmlAccessType.PROPERTY) 注释。它的 JavaDoc 说:

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

注意 public 这个词的细微差别,所以如果用 @XmlAccessorType(XmlAccessType.PROPERTY) 注释,甚至私有(private) getter/setter 也会被考虑在内。

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

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

这在具有 FX 属性的 FX 类中可能有点棘手。我不会向您推荐它。

关于java - JAXB RI ClassFactory 中的空指针异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28929569/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com