Java 在JPA实体序列化(JSON)上防止JAX-RS中的无限递归(不使用Jackson注释)
我有一个实体如下:Java 在JPA实体序列化(JSON)上防止JAX-RS中的无限递归(不使用Jackson注释),java,jpa,jackson,jax-rs,resteasy,Java,Jpa,Jackson,Jax Rs,Resteasy,我有一个实体如下: @XmlRootElement @Entity @Table(name="CATEGORY") @Access(AccessType.FIELD) @Cacheable @NamedQueries({ @NamedQuery(name="category.countAllDeleted", query="SELECT COUNT(c) FROM Category c WHERE c.deletionTimestamp IS NOT NULL"), @Named
@XmlRootElement
@Entity
@Table(name="CATEGORY")
@Access(AccessType.FIELD)
@Cacheable
@NamedQueries({
@NamedQuery(name="category.countAllDeleted", query="SELECT COUNT(c) FROM Category c WHERE c.deletionTimestamp IS NOT NULL"),
@NamedQuery(name="category.findAllNonDeleted", query="SELECT c from Category c WHERE c.deletionTimestamp IS NULL"),
@NamedQuery(name="category.findByCategoryName", query="SELECT c FROM Category c JOIN c.descriptions cd WHERE LOWER(TRIM(cd.name)) LIKE ?1")
})
public class Category extends AbstractSoftDeleteAuditableEntity<Integer> implements za.co.sindi.persistence.entity.Entity<Integer>, Serializable {
/**
*
*/
private static final long serialVersionUID = 4600301568861226295L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="CATEGORY_ID", nullable=false)
private int id;
@ManyToOne
@JoinColumn(name="PARENT_CATEGORY_ID")
private Category parent;
@OneToMany(cascade= CascadeType.ALL, mappedBy="category")
private List<CategoryDescription> descriptions;
public void addDescription(CategoryDescription description) {
if (description != null) {
if (descriptions == null) {
descriptions = new ArrayList<CategoryDescription>();
}
descriptions.add(description);
}
}
/* (non-Javadoc)
* @see za.co.sindi.entity.IDBasedEntity#getId()
*/
public Integer getId() {
// TODO Auto-generated method stub
return id;
}
/* (non-Javadoc)
* @see za.co.sindi.entity.IDBasedEntity#setId(java.io.Serializable)
*/
public void setId(Integer id) {
// TODO Auto-generated method stub
this.id = (id == null) ? 0 : id;
}
/**
* @return the parent
*/
public Category getParent() {
return parent;
}
/**
* @param parent the parent to set
*/
public void setParent(Category parent) {
this.parent = parent;
}
/**
* @return the descriptions
*/
public List<CategoryDescription> getDescriptions() {
return descriptions;
}
/**
* @param descriptions the descriptions to set
*/
public void setDescriptions(List<CategoryDescription> descriptions) {
this.descriptions = descriptions;
}
}
有一些问题需要回答,例如,需要使用特定于Jackson的注释。我的项目要求严格遵守JavaEE特定的框架。有没有一种解决方案可以用来防止无限递归而不使用Jackson注释?如果没有,我们可以创建一个配置文件(XML文件等),Jackson可以用它代替注释吗?原因是应用程序不仅必须绑定到特定于Wildfly的库。是。创建专用数据结构(例如数据传输对象或DTO)并映射要从HTTP端点发送的字段 你的担忧混杂在一起,结果往往很糟糕
JPA实体是针对数据结构的API,REST表示(JSON或XML DTO)是REST API提供的数据负载。我想说,您在这里有几个选项:
transient
关键字或让JAX-RS忽略某些属性/字段(它们不会被封送)类别的ID,而不是整个对象
@JsonIgnore
之外,还有一些特定于Jackson的解决方案,如:
- --
可用于以更灵活的方式实现相同的目的(例如,它允许您定义何时要返回没有依赖项的简化对象(仅相关对象的ID)以及何时返回整个对象;您可以指定要使用的视图,例如在JAX-RS入口点上@JsonView
- 这将在编组对象时识别循环依赖项,并防止无限递归(对象的第一次命中意味着将其作为一个整体,相同对象的每一次命中意味着仅放置其ID)
这就是说,最好将向用户提供和接受的数据与内部数据分开。我没有混用任何东西。我的RESTful WS返回一个
集合
,JBoss使用RESTEasy
(JAX-RS实现)它在内部使用Jackson将我的实体转换为JSON字符串。这是在容器级别完成的,我无法控制它。@BuhakeSindi您可能误解了答案。基本上,答案是:“使用DTO”,通常我都会同意。DTO似乎是解决这个问题的完美方案。因此,在您的整个项目中,您根本没有使用任何第三方库,只使用javaee api?@peeskillet是的。我相信这是可能的,这个项目将证明这一点。
@XmlRootElement
@Entity
@Table(name="CATEGORY_DESCRIPTION")
@Access(AccessType.FIELD)
@Cacheable
public class CategoryDescription extends AbstractModifiableAuditableEntity<CategoryDescriptionKey> implements za.co.sindi.persistence.entity.Entity<CategoryDescriptionKey>, Serializable {
/**
*
*/
private static final long serialVersionUID = 4506134647012663247L;
@EmbeddedId
private CategoryDescriptionKey id;
@MapsId("categoryId")
@ManyToOne/*(fetch=FetchType.LAZY)*/
@JoinColumn(name="CATEGORY_ID", insertable=false, updatable=false, nullable=false)
private Category category;
@MapsId("languageCode")
@ManyToOne/*(fetch=FetchType.LAZY)*/
@JoinColumn(name="LANGUAGE_CODE", insertable=false, updatable=false, nullable=false)
private Language language;
@Column(name="CATEGORY_NAME", nullable=false)
private String name;
@Column(name="DESCRIPTION_PLAINTEXT", nullable=false)
private String descriptionPlainText;
@Column(name="DESCRIPTION_MARKDOWN", nullable=false)
private String descriptionMarkdown;
@Column(name="DESCRIPTION_HTML", nullable=false)
private String descriptionHtml;
/* (non-Javadoc)
* @see za.co.sindi.entity.IDBasedEntity#getId()
*/
public CategoryDescriptionKey getId() {
// TODO Auto-generated method stub
return id;
}
/* (non-Javadoc)
* @see za.co.sindi.entity.IDBasedEntity#setId(java.io.Serializable)
*/
public void setId(CategoryDescriptionKey id) {
// TODO Auto-generated method stub
this.id = id;
}
/**
* @return the category
*/
public Category getCategory() {
return category;
}
/**
* @param category the category to set
*/
public void setCategory(Category category) {
this.category = category;
}
/**
* @return the language
*/
public Language getLanguage() {
return language;
}
/**
* @param language the language to set
*/
public void setLanguage(Language language) {
this.language = language;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the descriptionPlainText
*/
public String getDescriptionPlainText() {
return descriptionPlainText;
}
/**
* @param descriptionPlainText the descriptionPlainText to set
*/
public void setDescriptionPlainText(String descriptionPlainText) {
this.descriptionPlainText = descriptionPlainText;
}
/**
* @return the descriptionMarkdown
*/
public String getDescriptionMarkdown() {
return descriptionMarkdown;
}
/**
* @param descriptionMarkdown the descriptionMarkdown to set
*/
public void setDescriptionMarkdown(String descriptionMarkdown) {
this.descriptionMarkdown = descriptionMarkdown;
}
/**
* @return the descriptionHtml
*/
public String getDescriptionHtml() {
return descriptionHtml;
}
/**
* @param descriptionHtml the descriptionHtml to set
*/
public void setDescriptionHtml(String descriptionHtml) {
this.descriptionHtml = descriptionHtml;
}
}
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: za.co.sindi.unsteve.persistence.entity.Category["descriptions"]->org.hibernate.collection.internal.PersistentBag[0]->za.co.sindi.unsteve.persistence.entity.CategoryDescription["category"]->za.co.sindi.unsteve.persistence.entity.Category["descriptions"]->