gpt4 book ai didi

java - 防止 JAX-RS 中 JPA 实体序列化 (JSON) 的无限递归(不使用 Jackson 注释)

转载 作者:搜寻专家 更新时间:2023-11-01 02:42:23 26 4
gpt4 key购买 nike

我有一个实体如下:

@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;
}
}

和:

@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;
}
}

返回 Collection<Category> 时使用 JAX-RS 并在 JBoss Wildfly 8.2.0-Final 上部署,我得到以下堆栈跟踪:

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"]->

在类似 this question 的问题中有答案。 ,这需要使用 Jackson 特定的注释。我的项目要求是严格坚持使用 Java EE 特定框架。有没有一种解决方案可以在不使用 Jackson 注释的情况下防止无限递归?如果没有,我们可以创建一个 Jackson 可以用来代替注释的配置文件(XML 文件等)吗?这样做的原因是应用程序不能只绑定(bind)到 Wildfly 特定库。

最佳答案

我会说你在这里有几个选择:

  1. 使用transient 关键字或@XmlTransient让 JAX-RS 忽略一些属性/字段(它们不会被编码),
  2. 使用 DTO 更好地为最终用户反射(reflect)您的数据结构;随着时间的推移,您的实体、它在 RDBMS 中的建模方式以及您返回给用户的内容之间的差异将越来越大,
  3. 结合使用上述两个选项并将某些字段标记为 transient ,同时提供其他“JAX-RS 友好”访问器,例如仅返回 Category 的 ID 而不是整个对象。

除了 @JsonIgnore 之外还有一些 Jackson 特定的解决方案,例如:

  • Jackson views -- @JsonView 可用于以更灵活的方式实现相同的方式(例如,它允许您定义何时要返回没有依赖项的简化对象(只是相关对象的 ID)以及何时返回整个对象;您指定要使用的 View ,例如在 JAX-RS 入口点上,
  • Object Identity这将在编码对象时识别循环依赖并防止无限递归(对象的第一次命中意味着将其作为一个整体按原样放置,同一对象的每一次其他命中意味着仅放置其 ID)。

我确信还有其他解决方案,但考虑到上述解决方案,从长远来看,我个人会选择 DTO。您可以使用一些自动映射解决方案,例如 Dozer来帮助你完成这个讨厌的重复工作。
话虽这么说,但最好将您提供给用户并从用户那里接受的数据与您的内部数据分开。

关于java - 防止 JAX-RS 中 JPA 实体序列化 (JSON) 的无限递归(不使用 Jackson 注释),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30683768/

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