在对象图中检测到循环。这将导致无限深度的XML

时间:2013-06-25 10:51:01

标签: java hibernate jaxb

我有两个DTO对象,例如A和B,它们具有getter和setter,用于从数据库中获取数据。问题是当我调用A时,B被调用,B再次将自身指向A并创建一个循环。

我无法忽略/隐藏创建循环的方法。我需要获取A和B的全部数据。

有没有办法实现它?

请帮忙

这是导致问题的代码。这是调用环境DTO的应用程序DTO

@OneToMany(mappedBy="application", fetch=FetchType.LAZY
        ,cascade=CascadeType.ALL
        )
public Set<EnvironmentDTO> getEnvironment() {
    return environment;
}

public void setEnvironment(Set<EnvironmentDTO> environment) {
    this.environment = environment;
}

这是调用应用程序DTO的环境DTO

@ManyToOne(targetEntity=ApplicationDTO.class )
@JoinColumn(name="fk_application_Id") 
public ApplicationDTO getApplication() {
    return application;
}

public void setApplication(ApplicationDTO application) {
    this.application = application;
}

这里创建周期

这是我的休息调用,它将以XML格式生成结果,我认为创建XML循环时正在创建

@GET
@Path("/get")
@Produces({MediaType.APPLICATION_XML})
public List<ApplicationDTO> getAllApplications(){
    List<ApplicationDTO> allApplication = applicationService.getAllApplication();
    return allApplication;
}

这是应用程序DTO类

@Entity
@Table(name="application")
@org.hibernate.annotations.GenericGenerator(
name ="test-increment-strategy",strategy = "increment")

@XmlRootElement
public class ApplicationDTO implements Serializable {

@XmlAttribute
public Long appTypeId;

private static final long serialVersionUID = -8027722210927935073L;

private Long applicationId;

private String applicationName;

private ApplicationTypeDTO applicationType;

private String applicationDescription;

private Integer owner;

private Integer createdBy;

private Integer assignedTo;

private Date createTime;

private Date modifiedTime;

private Set<EnvironmentDTO> environment;

@Id
@GeneratedValue(generator = "test-increment-strategy")
@Column(name = "applicationId")
public Long getApplicationId() {
    return applicationId;
}

private void setApplicationId(Long applicationId) {
    this.applicationId = applicationId;
}

@Column(name = "applicationName")
public String getApplicationName() {
    return applicationName;
}

public void setApplicationName(String applicationName) {
    this.applicationName = applicationName;
}

@ManyToOne(targetEntity=ApplicationTypeDTO.class 
        ,fetch = FetchType.LAZY
        )
@JoinColumn(name="applicationType")

public ApplicationTypeDTO getApplicationType() {
    return applicationType;
}

public void setApplicationType(ApplicationTypeDTO applicationType) {
    this.applicationType = applicationType;
}

@Column(name = "description")
public String getApplicationDescription() {
    return applicationDescription;
}

public void setApplicationDescription(String applicationDescription) {
    this.applicationDescription = applicationDescription;
}

@Column(name = "owner")
public Integer getOwner() {
    return owner;
}

public void setOwner(Integer owner) {
    this.owner = owner;
}

@Column(name = "createdBy")
public Integer getCreatedBy() {
    return createdBy;
}

public void setCreatedBy(Integer createdBy) {
    this.createdBy = createdBy;
}

@Column(name = "assignedTo")
public Integer getAssignedTo() {
    return assignedTo;
}

public void setAssignedTo(Integer assignedTo) {
    this.assignedTo = assignedTo;
}

@Column(name = "createTime")
public Date getCreateTime() {
    return createTime;
}

public void setCreateTime(Date createTime) {
    this.createTime = createTime;
}

@Column(name = "modifiedTime")
public Date getModifiedTime() {
    return modifiedTime;
}

public void setModifiedTime(Date modifiedTime) {
    this.modifiedTime = modifiedTime;
}

@OneToMany(mappedBy="application", fetch=FetchType.LAZY
        ,cascade=CascadeType.ALL
        )
public Set<EnvironmentDTO> getEnvironment() {
    return environment;
}

public void setEnvironment(Set<EnvironmentDTO> environment) {
    this.environment = environment;
}

这是环境DTO课程

@Entity
@Table(name="environment")

@org.hibernate.annotations.GenericGenerator(
name = "test-increment-strategy",
strategy = "increment")
@XmlRootElement
public class EnvironmentDTO implements Serializable {

@XmlAttribute
public Long envTypeId;

@XmlAttribute
public Long appId;

private static final long serialVersionUID = -2756426996796369998L;

private Long environmentId;

private String environmentName;

private EnvironmentTypeDTO environmentType;

private Integer owner;

private Date createTime;

private Set<InstanceDTO> instances;

private ApplicationDTO application;

@Id
@GeneratedValue(generator = "test-increment-strategy")
@Column(name = "envId")
public Long getEnvironmentId() {
    return environmentId;
}

private void setEnvironmentId(Long environmentId) {
    this.environmentId = environmentId;
}

@Column(name = "envName")
public String getEnvironmentName() {
    return environmentName;
}

public void setEnvironmentName(String environmentName) {
    this.environmentName = environmentName;
}

@ManyToOne(targetEntity=EnvironmentTypeDTO.class)
@JoinColumn(name = "envType")
public EnvironmentTypeDTO getEnvironmentType() {
    return environmentType;
}

public void setEnvironmentType(EnvironmentTypeDTO environmentType) {
    this.environmentType = environmentType;
}

@Column(name = "owner")
public Integer getOwner() {
    return owner;
}

public void setOwner(Integer owner) {
    this.owner = owner;
}

@Temporal(TemporalType.DATE)
@Column(name = "createTime")
public Date getCreateTime() 
{
    return createTime;
}

public void setCreateTime(Date createTime) {
    this.createTime = createTime;
}

@OneToMany(mappedBy="environment", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
public Set<InstanceDTO> getInstances() {
    return instances;
}

public void setInstances(Set<InstanceDTO> instances) {
    this.instances = instances;
}

@ManyToOne(targetEntity=ApplicationDTO.class )
@JoinColumn(name="fk_application_Id")
//@XmlTransient 
public ApplicationDTO getApplication() {
    return application;
}

public void setApplication(ApplicationDTO application) {
    this.application = application;
}

3 个答案:

答案 0 :(得分:9)

您的对象图是循环的。这没有什么本质上的错误,这是使用JPA的自然结果。

问题不在于您的对象图是循环的,而是您以无法处理周期的格式对其进行编码。这不是Hibernate的问题,而是一个JAXB问题。

我的建议是阻止JAXB尝试封送application类的EnvironmentDTO属性。没有该属性,循环图就变成了树。您可以通过使用@XmlTransient注释该属性来执行此操作。

(忏悔:我通过阅读a blog post by Mr Doughan了解了这个注释,我在阅读了这个问题的答案后遇到了这个注释!)

答案 1 :(得分:5)

注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。

MOXy提供@XmlInverseReference扩展来处理此用例。下面是如何在具有双向关系的两个实体上应用此映射的示例。

<强>客户

import javax.persistence.*;

@Entity
public class Customer {

    @Id
    private long id;

    @OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
    private Address address;

}

<强>地址

import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;

@Entity
public class Address implements Serializable {

    @Id
    private long id;

    @OneToOne
    @JoinColumn(name="ID")
    @MapsId
    @XmlInverseReference(mappedBy="address")
    private Customer customer;

}

了解更多信息

答案 2 :(得分:1)

我的建议是不要将您的JPA实体类暴露给您的Web服务。您可以创建不同的POJO类并将JPA实体转换为POJO。例如:

这是您的JPA实体

import javax.persistence.*;

@Entity
public class Customer {

    @Id
    private long id;

    @OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
    private Address address;

}

您应该将此课程用于您的网络服务:

public class CustomerModel{
    private long id;
    //you can call different WS to get the Address class, or combine to this model

    public void setFromJpa(Customer customer){
        this.id = customer.id;
    }
}