尝试在http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/调整示例,我遇到了json和递归循环的问题。
(代码已更改为保护) Resource.java
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
@Entity
@Table(name = "resources")
public class Resource implements TestableSerializable, Syncable<Resource> {
private static final long serialVersionUID = -1L;
private UUID resourceID;
private String name;
private Date lastUpdated;
private String lastAction;
@JsonManagedReference
private Set<ResourceEvents> events = new HashSet<ResourceEvents>(0);
@JsonIgnore
private Set<Credential> credentials = new HashSet<Credential>(0);
public Resource() {
super();
this.resourceID = UUID.randomUUID();
this.lastAction = Syncable.ADD;
this.lastUpdated = new Date();
}
public Resource(UUID resourceID) {
super();
this.resourceID = (resourceID == null ? UUID.randomUUID() : resourceID);
this.lastAction = Syncable.ADD;
this.lastUpdated = new Date();
}
@SyncConstructor(fields={"resourceID", "name"})
public Resource(UUID resourceID, String name) {
super();
this.resourceID = (resourceID == null ? UUID.randomUUID() : resourceID);
this.name = name;
this.lastUpdated = new Date();
this.lastAction = Syncable.ADD;
}
public Resource(UUID resourceID, String name, Set<Event> events, Set<Credential> credentials) {
super();
this.resourceID = (resourceID == null ? UUID.randomUUID() : resourceID);
this.name = name;
this.lastUpdated = new Date();
this.lastAction = Syncable.ADD;
//this.events = events;
this.credentials = credentials;
}
public void changeToMatch(Resource resource) {
this.resourceID = resource.getResourceID();
this.name = resource.getName();
if (resource.getLastAction().equals(Syncable.DELETE)) {
this.markDeleted();
}
}
@Override
public int compareTo(Resource anotherResource) {
return this.lastUpdated.compareTo(anotherResource.getLastUpdated());
}
@Override
public void markDeleted() {
this.lastUpdated = new Date();
this.lastAction = DELETE;
}
@Override
public void markUpdated() {
this.lastUpdated = new Date();
this.lastAction = UPDATE;
}
@Id
@Type(type="uuid-char")
@Column(name = "id", unique = true, nullable = false, length = 36)
public UUID getResourceID() {
return this.resourceID;
}
public void setResourceID(UUID resourceID) {
this.resourceID = resourceID;
}
@Column(name = "name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "lastUpdated", length = 23)
@Type(type = "****************.UtcTimestampType")
public Date getLastUpdated() {
return this.lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Column(name = "lastAction", length = 10)
public String getLastAction() {
return this.lastAction;
}
public void setLastAction(String lastAction) {
this.lastAction = lastAction;
}
@OneToMany(fetch = FetchType.EAGER, mappedBy = "resourceEventId.resource", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST})
public Set<ResourceEvents> getResourceEvents() {
return this.events;
}
public void setResourceEvents(Set<ResourceEvents> events) {
this.events = events;
}
@Override
public List<Error> test() {
// TODO Auto-generated method stub
return null;
}
@Override
public int hashCode() {
int result = 1;
//result = prime * result + ((events == null) ? 0 : events.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((resourceID == null) ? 0 : resourceID.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Resource other = (Resource) obj;
if (events == null) {
if (other.events != null)
return false;
} else if (!events.equals(other.events))
return false;
if (flags == null) {
if (other.flags != null)
return false;
} else if (!flags.equals(other.flags))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (resourceID == null) {
if (other.resourceID != null)
return false;
} else if (!resourceID.equals(other.resourceID))
return false;
return true;
}
@Override
public String toString() {
return "Resource [resourceID=" + resourceID + ", name=" + name
+ ", lastUpdated="
+ lastUpdated + ", lastAction=" + lastAction + ", events="
+ events + "]";
}
}
Events.java
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
@Entity
@Table(name = "events")
public class Event implements TestableSerializable, Syncable<Event> {
private static final long serialVersionUID = -1L;
private UUID id;
private String name;
private Date lastUpdated;
private String lastAction;
@JsonManagedReference
private Set<ResourceEvents> resources = new HashSet<ResourceEvents>(0);
public Event() {
this.lastAction = Syncable.ADD;
this.lastUpdated = new Date();
}
public Event(UUID id, String name) {
super();
this.id = id;
this.lastAction = Syncable.ADD;
this.lastUpdated = new Date();
}
@SyncConstructor(fields={"id", "name"})
public Event(UUID id, String name, Set<Resource> resources) {
super();
this.id = id;
this.name = name;
//this.resources = resources;
this.lastAction = Syncable.ADD;
this.lastUpdated = new Date();
}
public void changeToMatch(Event event) {
this.id = event.getId();
this.name = event.getName();
if (event.getLastAction().equals(Syncable.DELETE)) {
this.markDeleted();
}
}
@Override
public int compareTo(Event anotherEvent) {
return this.lastUpdated.compareTo(anotherEvent.getLastUpdated());
}
@Override
public void markDeleted() {
this.lastUpdated = new Date();
this.lastAction = DELETE;
}
@Override
public void markUpdated() {
this.lastUpdated = new Date();
this.lastAction = UPDATE;
}
@Id
@Type(type="uuid-char")
@Column(name = "id", unique = true, nullable = false, length = 36)
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "lastUpdated", length = 23)
@Type(type = "com.cuadra.lup.persistence.types.UtcTimestampType")
public Date getLastUpdated() {
return this.lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Column(name = "lastAction", length = 10)
public String getLastAction() {
return this.lastAction;
}
public void setLastAction(String lastAction) {
this.lastAction = lastAction;
}
@OneToMany(fetch = FetchType.EAGER, mappedBy = "resourceEventId.event", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST})
public Set<ResourceEvents> getResourceEvents() {
return this.resources;
}
public void setResourceEvents(Set<ResourceEvents> resources) {
this.resources = resources;
}
@Override
public List<Error> test() {
// TODO Auto-generated method stub
return null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Event other = (Event) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
ResourceEvents.java
import java.util.Date;
import java.util.List;
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
@Entity
@Table(name = "resourceEvents")
@AssociationOverrides({
@AssociationOverride(name = "resourceEventId.resource",
joinColumns = @JoinColumn(name = "resource", nullable = false, updatable = true)),
@AssociationOverride(name = "resourceEventId.event",
joinColumns = @JoinColumn(name = "event", nullable = false, updatable = true)) })
public class ResourceEvents implements TestableSerializable {
private static final long serialVersionUID = 1L;
private ResourceEventId resourceEventId = new ResourceEventId ();
private Date lastUpdated;
private String lastAction;
public ResourceEvents () {
}
public ResourceEvents (Resource resource, Event event) {
getResourceEventId().setResource(resource);
getResourceEventId().setEvent(event);
this.lastAction = Syncable.ADD;
this.lastUpdated = new Date();
}
@EmbeddedId
public ResourceEventId getResourceEventId() {
return resourceEventId;
}
public void setResourceEventId(ResourceEventId resourceEventId) {
this.resourceEventId = resourceEventId;
}
@Transient
public Resource getResource() {
return getResourceEventId().getResource();
}
public void setResource(Resource resource) {
getResourceEventId().setResource(resource);
}
@Transient
public Event getEvent() {
return getResourceEventId().getEvent();
}
public void setEvent(Event event) {
getResourceEventId().setEvent(event);
}
@Temporal(TemporalType.DATE)
@Column(name = "lastUpdated", nullable = false, length = 25)
public Date getLastUpdated() {
return this.lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Column(name = "lastAction", nullable = false, length = 10)
public String getLastAction() {
return this.lastAction;
}
public void setLastAction(String lastAction) {
this.lastAction = lastAction;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ResourceEvents that = (ResourceEvents) o;
if (getResourceEventId() != null ? !getResourceEventId().equals(that.getResourceEventId())
: that.getResourceEventId() != null)
return false;
return true;
}
public int hashCode() {
return (getResourceEventId() != null ? getResourceEventId().hashCode() : 0);
}
@Override
public List<Error> test() {
// TODO Auto-generated method stub
return null;
}
}
ResourceEventId
import java.io.Serializable;
import java.util.List;
import javax.persistence.ManyToOne;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class ResourceEventId implements TestableSerializable {
ObjectMapper mapper = new ObjectMapper();
private static final long serialVersionUID = 1L;
@JsonBackReference
private Resource resource;
@JsonBackReference
private Event event;
ResourceEventId () {
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
@ManyToOne
public Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
@ManyToOne
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ResourceEventId that = (ResourceEventId) o;
if (resource != null ? !resource.equals(that.resource) : that.resource != null) return false;
if (event != null ? !event.equals(that.event) : that.event != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (resource != null ? resource.hashCode() : 0);
result = 31 * result + (event != null ? event.hashCode() : 0);
return result;
}
@Override
public List<Error> test() {
// TODO Auto-generated method stub
return null;
}
}
错误消息
11-Apr-2017 15:45:38.210 WARNING [https-nio-8443-exec-1] org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException Handling of [org.springframework.http.converter.HttpMessageNotWritableException] resulted in Exception
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:478)
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:127)
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:127)
at org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper.sendError(SaveContextOnUpdateOrErrorResponseWrapper.java:87)
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.sendServerError(DefaultHandlerExceptionResolver.java:313)
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleHttpMessageNotWritable(DefaultHandlerExceptionResolver.java:370)
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException(DefaultHandlerExceptionResolver.java:140)
at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:138)
at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:75)
at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1164)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:232)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:105)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1078)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:760)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1524)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
11-Apr-2017 15:45:38.215 SEVERE [https-nio-8443-exec-1] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [slaveService] in context with path [] threw exception [Request processing failed; nested exception is
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class
com.******.common.model.ResourceEventId and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[303]-> com.*****.model.Resource["resourceEvents"]->org.hibernate.collection.internal.PersistentSet[0]->
com.*****.model.ResourceEvents["resourceEventId"]); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.*****.model.ResourceEventId and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[303]->com.cuadra.lup.persistence.common.model.Resource["resourceEvents"]->org.hibernate.collection.internal.PersistentSet[0]->com.*****.model.ResourceEvents["resourceEventId"])] with root cause
com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.*****.common.model.ResourceEventId and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[303]->com.*****.model.Resource["resourceEvents"]->org.hibernate.collection.internal.PersistentSet[0]->com.*****.common.model.ResourceEvents["resourceEventId"])
at
:::: EDIT :::: 可序列化错误已得到修复,但现在是主要问题
Could not write JSON: Infinite recursion (StackOverflowError)
答案 0 :(得分:0)
我会回答我自己的问题。
正如评论中所述,我忘记了导致序列化错误的@Embeddable。
至于无限递归,我只需要添加com.fasterxml.jackson.annotation.JsonIdentityInfo;
@Entity
@Table(name = "events")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,
property="@id")
public class Event implements TestableSerializable, Syncable<Event> {
和
@Entity
@Table(name = "resources")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class Resource implements TestableSerializable, Syncable<Resource> {