2016-09-30 22 views
0

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

我已经搜索了这个错误,并且发现它是由父级引用子级和子引用父级的父级子级关系引起的。大多数答案都是使用@XMLTransient。

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

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

以下是我的Budget和Category类。

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(); 
     } 
    } 
+0

试图定义一个CLEA预算上课不使用JavaFX的字段it.it必须是一个POJO – Cris

+0

我清理预算和类别删除JavaFX和他们只是的POJO。我仍然有同样的错误。 –

+0

请发送清洁代码 – Cris

回答

1

我有点不好意思。我知道你必须小心递归,这是我的问题。

在构建UI之前,我对某些值进行了硬编码 - 创建了预算并添加了一些类别。我应该发布该代码。我已经将其中一个类别设置为一个孩子。

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输出。

感谢您花时间查看我的代码并帮助我。 如果我完成了这个工作,也许我会把应用/代码发布到互联网上。我从来没有这样做过,但不知道最好的地方。

再次,谢谢。 克里斯