gpt4 book ai didi

java - JAXB 这会导致无限深的XML

转载 作者:行者123 更新时间:2023-12-01 09:26:24 25 4
gpt4 key购买 nike

我正在编写一个简单的预算程序,其中有一个预算类和一系列类别类。每个类别类可以有子类别类。当我尝试使用 JAXB 将数据保存到 XML 文件时,出现错误com.sun.istack.internal.SAXException2:在对象图中检测到循环。这将导致无限深的XML

我搜索了该错误,发现它是由父子关系引起的,其中父级引用子级,子级引用父级。大多数答案是使用@XMLTransient。

我的问题是我的类别类既不引用预算父项,也不引用类别父项(如果存在)。

我是 JAXB 新手,但不是 Java。我使用这个应用程序作为 JAXB 和 JavaFX 的学习体验。

以下是我的预算和类别类别。

package budget.model;

import java.time.LocalDate;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import budget.util.BudgetProperties.DayOfWeek;
import budget.util.LocalDateAdapter;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;


@XmlRootElement(name = "budget")
public class Budget {

// default to Sunday
ObjectProperty<DayOfWeek> startOfWeek = new SimpleObjectProperty<DayOfWeek>(DayOfWeek.SUNDAY);
ObjectProperty<LocalDate> startDate = new SimpleObjectProperty<LocalDate>();
IntegerProperty daysBeyondWeek = new SimpleIntegerProperty(3);
IntegerProperty numberOfWeeks = new SimpleIntegerProperty();
ObservableList<Category> categories = FXCollections.observableArrayList();

// startOfWeek
public DayOfWeek getStartOfWeek() {
return this.startOfWeek.getValue();
}
public void setStartOfWeek(DayOfWeek startOfWeek) {
this.startOfWeek.set(startOfWeek);
}
public ObjectProperty<DayOfWeek> startOfWeekProperty() {
return this.startOfWeek;
}

// startDate
@XmlJavaTypeAdapter(LocalDateAdapter.class)
public LocalDate getStartDate() {
return this.startDate.getValue();
}
public void setStartDate(LocalDate startDate){
this.startDate.set(startDate);
}
public ObjectProperty<LocalDate> startDateProperty() {
return this.startDate;
}

// daysBeyondWeek
public Integer getDaysBeyondWeek() {
return this.daysBeyondWeek.getValue();
}
public void setDaysBeyondWeek(Integer daysBeyondWeek) {
this.daysBeyondWeek.set(daysBeyondWeek);
}
public IntegerProperty daysBeyondWeekProperty() {
return this.daysBeyondWeek;
}

// numberOFWeeks
public Integer getNumberOfWeeks() {
return this.numberOfWeeks.getValue();
}
public void setNumberOfWeeks(Integer numberOfWeeks) {
this.numberOfWeeks.set(numberOfWeeks);
}
public IntegerProperty numberOfWeeksProperty() {
return numberOfWeeks;
}

// categories
public ObservableList<Category> getCategories () {
return categories;
}
public void setCategories(ObservableList<Category> categories) {
this.categories = categories;
}
public ObservableList<Category> categoriesProperty () {
return categories;
}
}



package budget.model;

import java.time.LocalDate;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import budget.util.BudgetProperties.RepeatFrequency;
import budget.util.LocalDateAdapter;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Category {

StringProperty name = new SimpleStringProperty("");
ObservableList<Category> children = FXCollections.observableArrayList();
StringProperty comments = new SimpleStringProperty("");
ObjectProperty<RepeatFrequency> repeatFrequency = new SimpleObjectProperty<RepeatFrequency>();
ObjectProperty<LocalDate> dueDate = new SimpleObjectProperty<LocalDate>();
DoubleProperty budgetAmount = new SimpleDoubleProperty();
DoubleProperty actualAmount = new SimpleDoubleProperty();

// name
public String getName() {
return name.getValue();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty nameProperty() {
return name;
}

// children
public ObservableList<Category> getChildren() {
return children;
}
public void setChildren(ObservableList<Category> children) {
this.children.setAll(children);
}
public void addChild(Category category) {
this.children.add(category);
}

// isParent
public Boolean isParent() {
// return this.parent.getValue();
if (children == null || children.isEmpty() || children.size() == 0) {
return false;
} else {
return true;
}
}

// comments
public String getComments() {
return comments.getValue();
}
public void setComments(String comments) {
this.comments.set(comments);
}
public StringProperty commentsProperty() {
return comments;
}

// repeatFrequency
public RepeatFrequency getRepeatFrequency() {
return this.repeatFrequency.getValue();
}
public void setRepeatFrequency(RepeatFrequency repeatFrequency) {
this.repeatFrequency.set(repeatFrequency);
}
public ObjectProperty<RepeatFrequency> repeatFrequencyProperty() {
return this.repeatFrequency;
}

// dueDate
@XmlJavaTypeAdapter(LocalDateAdapter.class)
public LocalDate getDueDate() {
return this.dueDate.getValue();
}
public void setDueDate(LocalDate dueDate) {
this.dueDate.set(dueDate);
}
public ObjectProperty<LocalDate> dueDateProperty() {
return this.dueDate;
}

// budgetAmount
public Double getBudgetAmount() {
return this.budgetAmount.getValue();
}
public void setBudgetAmount(Double budgetAmount) {
this.budgetAmount.set(budgetAmount);
}
public DoubleProperty budgetAmountProperty() {
return this.budgetAmount;
}

// actualAmount
public Double getActualAmount() {
return this.actualAmount.getValue();
}
public void setActualAmount(Double actualAmount) {
this.actualAmount.set(actualAmount);
}
public DoubleProperty actualAmountProperty() {
return this.actualAmount;
}

}

还有另一个类处理编码。该类的函数如下

    public void saveBudgetData(Budget budget) {
File file = new File(path + BUDGET_FILE);
try {
JAXBContext context = JAXBContext
.newInstance(Budget.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

// Marshalling and saving XML to the file.
m.marshal(budget, file);

} catch (Exception e) { // catches ANY exception
logger.error("exception: ", e);
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Could not save data");
alert.setContentText("Could not save data to file:\n" + file.getPath());

alert.showAndWait();
}
}

我理解这是类别之间的递归关系。这就是它所提示的吗?我在搜索中没有看到这种情况。

谢谢。

清理了预算和类别类别

package budget.model;

import java.time.LocalDate;
import java.util.ArrayList;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import budget.util.BudgetProperties.DayOfWeek;
import budget.util.LocalDateAdapter;


@XmlRootElement(name = "budget")
public class BudgetNoFX {

// default to Sunday
DayOfWeek startOfWeek = DayOfWeek.SUNDAY;
// default to now
LocalDate startDate = LocalDate.now();
// number of days beyond week end to include in list of due bills
// default to 3
Integer daysBeyondWeek = new Integer(3);
Integer numberOfWeeks = new Integer(0);
ArrayList<CategoryNoFX> categories = new ArrayList<CategoryNoFX>();

// startOfWeek
public DayOfWeek getStartOfWeek() {
return this.startOfWeek;
}
public void setStartOfWeek(DayOfWeek startOfWeek) {
this.startOfWeek = startOfWeek;
}

// startDate
@XmlJavaTypeAdapter(LocalDateAdapter.class)
public LocalDate getStartDate() {
return this.startDate;
}
public void setStartDate(LocalDate startDate){
this.startDate = startDate;
}

// daysBeyondWeek
public Integer getDaysBeyondWeek() {
return this.daysBeyondWeek;
}
public void setDaysBeyondWeek(Integer daysBeyondWeek) {
this.daysBeyondWeek = daysBeyondWeek;
}

// numberOFWeeks
public Integer getNumberOfWeeks() {
return this.numberOfWeeks;
}
public void setNumberOfWeeks(Integer numberOfWeeks) {
this.numberOfWeeks = numberOfWeeks;
}

// categories
public ArrayList<CategoryNoFX> getCategories () {
return categories;
}
public void setCategories(ArrayList<CategoryNoFX> categories) {
this.categories = categories;
}
}


package budget.model;

import java.time.LocalDate;
import java.util.ArrayList;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import budget.util.BudgetProperties.RepeatFrequency;
import budget.util.LocalDateAdapter;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class CategoryNoFX {

public static final String ROOT_CATEGORY = "ROOT";

String name = new String("");
ArrayList<CategoryNoFX> children = new ArrayList<CategoryNoFX>();
String comments = new String("");
// default to monthly
RepeatFrequency repeatFrequency = RepeatFrequency.MONTHLY;
LocalDate dueDate = LocalDate.now();
Double budgetAmount = new Double(0);
Double actualAmount = new Double(0);

// name
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

// children
public ArrayList<CategoryNoFX> getChildren() {
return children;
}
public void setChildren(ArrayList<CategoryNoFX> children) {
this.children = children;
}
public void addChild(CategoryNoFX category) {
this.children.add(category);
}

// isParent
public Boolean isParent() {
if (children == null || children.isEmpty() || children.size() == 0) {
return false;
} else {
return true;
}
}

// comments
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}

// repeatFrequency
public RepeatFrequency getRepeatFrequency() {
return this.repeatFrequency;
}
public void setRepeatFrequency(RepeatFrequency repeatFrequency) {
this.repeatFrequency = repeatFrequency;
}

// dueDate
@XmlJavaTypeAdapter(LocalDateAdapter.class)
public LocalDate getDueDate() {
return this.dueDate;
}
public void setDueDate(LocalDate dueDate) {
this.dueDate = dueDate;
}

// budgetAmount
public Double getBudgetAmount() {
return this.budgetAmount;
}
public void setBudgetAmount(Double budgetAmount) {
this.budgetAmount = budgetAmount;
}

// actualAmount
public Double getActualAmount() {
return this.actualAmount;
}
public void setActualAmount(Double actualAmount) {
this.actualAmount = actualAmount;
}
}

我更新了 saveBudgetData 函数以使用新的预算类别

    public void saveBudgetData(BudgetNoFX budget) {
File file = new File(path + BUDGET_FILE);
try {
JAXBContext context = JAXBContext
.newInstance(BudgetNoFX.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

// Marshalling and saving XML to the file.
m.marshal(budget, file);

} catch (Exception e) { // catches ANY exception
logger.error("exception: ", e);
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Could not save data");
alert.setContentText("Could not save data to file:\n" + file.getPath());

alert.showAndWait();
}
}

最佳答案

我有点尴尬。我知道你必须小心递归,这就是我的问题。

在构建用户界面之前,我对一些值进行了硬编码 - 创建了预算并添加了一些类别。我应该发布该代码。我小时候就将其中一个类别设置为它自己。

Category food = new Category();
food.setName("Food");
categories.add(food);
Category groceries = new Category();
groceries.setBudgetAmount(new Double(120));
groceries.setName("Groceries");
// groceries.setParentCategory("Food");
groceries.setRepeatFrequency(RepeatFrequency.WEEKLY);
food.addChild(food); <-- problem line

一旦我将有问题的行修复为

food.addChild(groceries); 

它开始工作了。

我通过注释掉 XML 的保存函数找到了它,而是将我的预算对象写到屏幕上。

我最近读过这个教程:http://code.makery.ch/library/javafx-8-tutorial/并构建了另一个简单的应用程序。这就是 LocalDateAdapter 类的来源。在第 5 部分中,他解释了 jaxb 和列表。我对代码进行了一些更改以更好地处理我的列表,并且我得到了令我满意的 xml 输出。

感谢您花时间查看我的代码并帮助我。如果我完成了这件事,也许我会将应用程序/代码发布到互联网上。我以前从未这样做过,但不知道最好的地方。

再次感谢。克里斯

关于java - JAXB 这会导致无限深的XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39800730/

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