将摘录投影添加到 spring 数据 rest 存储库导致堆栈溢出错误
adding excerpt projection to spring data rest repository causes stack overflow error
当我们在 REST 存储库上启用 except 投影时,我们面临 WhosebugError
。实体是问题有两个关联,一个 @ManyToOne
与一个 Venue
实体必须内联包含在所有响应中,一个 @OneToMany
与 Trainee
我们一直想要的实体隐藏。实体(相关)片段
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Workshop implements Serializable {
private static final long serialVersionUID = -5516160437873476233L;
private Long id;
// omitted properties
private Venue venue;
private Set<Trainee> trainees;
@Id
@GeneratedValue
public Long getId() {
return id;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinTable(name = "workshop_venue", joinColumns = { @JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "venue_id", referencedColumnName = "id") })
public Venue getVenue() {
return venue;
}
@OneToMany
@JoinTable(name = "workshop_trainees", joinColumns = { @JoinColumn(name = "workshiop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "trainee_id", referencedColumnName = "email") })
@RestResource(exported = false)
@JsonIgnore
public Set<Trainee> getTrainees() {
return trainees;
}
// omitted getters/setters
}
当我添加这个投影时
@Projection(name = "default", types = { Workshop.class })
public interface InlineVenueProjection {
String getName();
Integer getSeatsAvailable();
WorkshopType getWorkshopType();
Date getDate();
Venue getVenue();
}
并在存储库中启用它
@RepositoryRestResource(collectionResourceRel = "workshop", path = "workshops", excerptProjection = InlineVenueProjection.class)
public interface WorkshopRepository extends JpaRepository<Workshop, Long> {
// omitted methods
}
我在 POST 请求中遇到堆栈溢出错误
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.WhosebugError
并在堆栈跟踪中更进一步
Caused by: java.lang.WhosebugError: null
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter.initialValue(ReentrantReadWriteLock.java:286)
at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:180)
at java.lang.ThreadLocal.get(ThreadLocal.java:170)
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReleaseShared(ReentrantReadWriteLock.java:423)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared(AbstractQueuedSynchronizer.java:1341)
at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.unlock(ReentrantReadWriteLock.java:881)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:169)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:140)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:67)
at org.springframework.data.mapping.context.PersistentEntities.getPersistentEntity(PersistentEntities.java:63)
at org.springframework.data.rest.webmvc.mapping.LinkCollectingAssociationHandler.doWithAssociation(LinkCollectingAssociationHandler.java:100)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:352)
你得到堆栈溢出异常的原因是因为我猜在 Venue
(1-Many) 和 Workshop
(Many-1) 之间定义了双向关系。你可以证实我的假设。
当您尝试直接序列化 venue 时,因为关系 workshop 已加载并且它具有对 venue 的引用,因此无休止的递归。
解决方案
为了解决这个问题,Jackson @JsonManagedReference
和 @JsonBackReference
。
工作坊Class
public class Workshop implements Serializable {
...
@ManyToOne(fetch = FetchType.EAGER)
@JoinTable(name = "workshop_venue", joinColumns = { @JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "venue_id", referencedColumnName = "id") })
@JsonManagedReference
public Venue getVenue() {
return venue;
}
...
}
地点Class
public class Venue implements Serializable {
...
@OneToMany
@JsonBackReference
public List<Workshop> getWorkshops() {
return workshops;
}
...
}
希望这对您有所帮助。让我知道这是否有效。
当我们在 REST 存储库上启用 except 投影时,我们面临 WhosebugError
。实体是问题有两个关联,一个 @ManyToOne
与一个 Venue
实体必须内联包含在所有响应中,一个 @OneToMany
与 Trainee
我们一直想要的实体隐藏。实体(相关)片段
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Workshop implements Serializable {
private static final long serialVersionUID = -5516160437873476233L;
private Long id;
// omitted properties
private Venue venue;
private Set<Trainee> trainees;
@Id
@GeneratedValue
public Long getId() {
return id;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinTable(name = "workshop_venue", joinColumns = { @JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "venue_id", referencedColumnName = "id") })
public Venue getVenue() {
return venue;
}
@OneToMany
@JoinTable(name = "workshop_trainees", joinColumns = { @JoinColumn(name = "workshiop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "trainee_id", referencedColumnName = "email") })
@RestResource(exported = false)
@JsonIgnore
public Set<Trainee> getTrainees() {
return trainees;
}
// omitted getters/setters
}
当我添加这个投影时
@Projection(name = "default", types = { Workshop.class })
public interface InlineVenueProjection {
String getName();
Integer getSeatsAvailable();
WorkshopType getWorkshopType();
Date getDate();
Venue getVenue();
}
并在存储库中启用它
@RepositoryRestResource(collectionResourceRel = "workshop", path = "workshops", excerptProjection = InlineVenueProjection.class)
public interface WorkshopRepository extends JpaRepository<Workshop, Long> {
// omitted methods
}
我在 POST 请求中遇到堆栈溢出错误
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.WhosebugError
并在堆栈跟踪中更进一步
Caused by: java.lang.WhosebugError: null
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter.initialValue(ReentrantReadWriteLock.java:286)
at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:180)
at java.lang.ThreadLocal.get(ThreadLocal.java:170)
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReleaseShared(ReentrantReadWriteLock.java:423)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared(AbstractQueuedSynchronizer.java:1341)
at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.unlock(ReentrantReadWriteLock.java:881)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:169)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:140)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:67)
at org.springframework.data.mapping.context.PersistentEntities.getPersistentEntity(PersistentEntities.java:63)
at org.springframework.data.rest.webmvc.mapping.LinkCollectingAssociationHandler.doWithAssociation(LinkCollectingAssociationHandler.java:100)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:352)
你得到堆栈溢出异常的原因是因为我猜在 Venue
(1-Many) 和 Workshop
(Many-1) 之间定义了双向关系。你可以证实我的假设。
当您尝试直接序列化 venue 时,因为关系 workshop 已加载并且它具有对 venue 的引用,因此无休止的递归。
解决方案
为了解决这个问题,Jackson @JsonManagedReference
和 @JsonBackReference
。
工作坊Class
public class Workshop implements Serializable {
...
@ManyToOne(fetch = FetchType.EAGER)
@JoinTable(name = "workshop_venue", joinColumns = { @JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "venue_id", referencedColumnName = "id") })
@JsonManagedReference
public Venue getVenue() {
return venue;
}
...
}
地点Class
public class Venue implements Serializable {
...
@OneToMany
@JsonBackReference
public List<Workshop> getWorkshops() {
return workshops;
}
...
}
希望这对您有所帮助。让我知道这是否有效。