使用 eclipselink 的 JPA Stackoverflowexception
JPA Stackoverflowexception using eclipselink
当我试图从我的应用程序中获取一个项目或项目列表时,我得到一个 java.lang.WhosebugError
异常。
我正在将 JPA 与 eclipselink 结合使用。
我得到以下堆栈跟踪:
java.lang.WhosebugError
java.lang.WhosebugError
at java.util.concurrent.ConcurrentHashMap$BaseIterator.<init>(ConcurrentHashMap.java:3391)
at java.util.concurrent.ConcurrentHashMap$ValueIterator.<init>(ConcurrentHashMap.java:3430)
at java.util.concurrent.ConcurrentHashMap$ValuesView.iterator(ConcurrentHashMap.java:4683)
at org.eclipse.yasson.internal.ComponentMatcher.searchComponentBinding(ComponentMatcher.java:187)
at org.eclipse.yasson.internal.ComponentMatcher.getSerializerBinding(ComponentMatcher.java:143)
at org.eclipse.yasson.internal.serializer.SerializerBuilder.build(SerializerBuilder.java:73)
at org.eclipse.yasson.internal.serializer.ObjectSerializer.marshallProperty(ObjectSerializer.java:102)
at org.eclipse.yasson.internal.serializer.ObjectSerializer.serializeInternal(ObjectSerializer.java:61)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:63)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializerCaptor(AbstractContainerSerializer.java:95)
我尝试了在多个网站上找到的多种解决方案:
- JsonIgnore
- Jsonmanagedreference & Jsonbckreference
- JsonIgnoreProperties
- JsonIdentityInfo
- 实体图
即使上面列出的所有内容都应该有效,none 其中似乎也有效。到目前为止,我发现的唯一 "solution" 是删除吸气剂,但这消除了建立双向关系的目的,因为您无法访问它们。
有人知道我做错了什么吗,或者有人有其他可行的解决方案吗?
下面是一些代码片段:
用户Class:
@Entity
@Table(name = "users")
@NamedEntityGraph(
name = "user-entity-graph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("username"),
@NamedAttributeNode("email"),
@NamedAttributeNode("biography"),
@NamedAttributeNode("website"),
@NamedAttributeNode("longitude"),
@NamedAttributeNode("latitude"),
@NamedAttributeNode(value = "role", subgraph = "role-subgraph"),
@NamedAttributeNode(value = "followers", subgraph = "followers-subgraph"),
@NamedAttributeNode(value = "following", subgraph = "followers-subgraph"),
},
subgraphs = {
@NamedSubgraph(
name = "role-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("name")
}
),
@NamedSubgraph(
name = "followers-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("username"),
@NamedAttributeNode("email"),
@NamedAttributeNode("biography"),
@NamedAttributeNode("website"),
@NamedAttributeNode("longitude"),
@NamedAttributeNode("latitude"),
}
),
}
)
@NamedQueries({
@NamedQuery(name = "user.getAllUsers", query = "SELECT u FROM User u"),
@NamedQuery(name = "user.getUserById", query = "SELECT u FROM User u WHERE u.id = :id"),
@NamedQuery(name = "user.getUserByUsername", query = "SELECT u FROM User u WHERE u.username = :username"),
@NamedQuery(name = "user.getUserByEmail", query = "SELECT u FROM User u WHERE u.email = :email")
})
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
@XmlTransient
private String password;
@Column(length = 160)
private String biography;
@Column
private String website;
private double longitude;
private double latitude;
@ManyToOne(fetch = FetchType.LAZY)
private Role role;
@ManyToMany(
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.LAZY
)
@JoinTable(
name = "followers",
joinColumns = @JoinColumn(name = "follower"),
inverseJoinColumns = @JoinColumn(name = "following")
)
private Set<User> followers;
@ManyToMany(
mappedBy = "followers",
fetch = FetchType.LAZY
)
private Set<User> following;
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
private Set<Tweet> tweets;
角色Class:
@Entity
@Table(name = "roles")
@NamedEntityGraph(
name = "role-entity-graph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("name"),
@NamedAttributeNode(value = "permissions", subgraph = "permission-subgraph"),
@NamedAttributeNode(value = "users", subgraph = "user-subgraph"),
},
subgraphs = {
@NamedSubgraph(
name = "permission-subgraph",
attributeNodes = {
@NamedAttributeNode("name"),
}
),
@NamedSubgraph(
name = "roles-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("name")
}
),
@NamedSubgraph(
name = "user-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("username"),
@NamedAttributeNode("email")
}
),
}
)
@NamedQueries({
@NamedQuery(name = "role.getAllRoles", query = "SELECT r FROM Role r"),
@NamedQuery(name = "role.getRoleById", query = "SELECT r FROM Role r WHERE r.id = :id"),
@NamedQuery(name = "role.getRoleByName", query = "SELECT r FROM Role r WHERE r.name = :name")
})
public class Role implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(unique = true, nullable = false)
private String name;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH}, fetch = FetchType.LAZY)
@JoinTable(
name = "role_permission",
joinColumns = @JoinColumn(name = "role_id"),
inverseJoinColumns = @JoinColumn(name = "permission_id")
)
private Set<Permission> permissions;
@OneToMany(mappedBy = "role", fetch = FetchType.LAZY)
private Set<User> users;
实施片段:
@PersistenceContext(unitName = "kwetterDB")
private EntityManager em;
@Override
public List<Role> all() {
EntityGraph eg = em.getEntityGraph("role-entity-graph");
return em.createNamedQuery("role.getAllRoles", Role.class).setHint("javax.persistence.fetchgraph", eg).getResultList();
}
我的 RoleController 的片段:
@Stateless
@Path("/roles")
public class RoleController {
@Inject
private RoleService roleService;
@Inject
private PermissionService permissionService;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response all() {
return Response.status(Response.Status.OK).entity( roleService.all()).build();
}
pom.xml:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0.1-b5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.24.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="kwetterDB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/myapp</jta-data-source>
<properties>
<!--<property name="javax.persistence.schema-generation.database.action" value="create"/>-->
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
搜索了一段时间后,我发现我必须使用 ObjectMapper 来触发 Json 注释。
资料来源:
适用于 @JsonIgnore
、@JsonBackReference
、@JsonManagedReference
、@JsonIgnoreProperties
和 @JsonIdentityInfo
。
在我的控制器中更改以下行:
return Response.status(Response.Status.OK).entity( roleService.all()).build();
致:
return Response.status(Response.Status.OK).entity(new ObjectMapper().writeValueAsString(roleService.all())).build();
当我试图从我的应用程序中获取一个项目或项目列表时,我得到一个 java.lang.WhosebugError
异常。
我正在将 JPA 与 eclipselink 结合使用。
我得到以下堆栈跟踪:
java.lang.WhosebugError
java.lang.WhosebugError
at java.util.concurrent.ConcurrentHashMap$BaseIterator.<init>(ConcurrentHashMap.java:3391)
at java.util.concurrent.ConcurrentHashMap$ValueIterator.<init>(ConcurrentHashMap.java:3430)
at java.util.concurrent.ConcurrentHashMap$ValuesView.iterator(ConcurrentHashMap.java:4683)
at org.eclipse.yasson.internal.ComponentMatcher.searchComponentBinding(ComponentMatcher.java:187)
at org.eclipse.yasson.internal.ComponentMatcher.getSerializerBinding(ComponentMatcher.java:143)
at org.eclipse.yasson.internal.serializer.SerializerBuilder.build(SerializerBuilder.java:73)
at org.eclipse.yasson.internal.serializer.ObjectSerializer.marshallProperty(ObjectSerializer.java:102)
at org.eclipse.yasson.internal.serializer.ObjectSerializer.serializeInternal(ObjectSerializer.java:61)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:63)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializerCaptor(AbstractContainerSerializer.java:95)
我尝试了在多个网站上找到的多种解决方案:
- JsonIgnore
- Jsonmanagedreference & Jsonbckreference
- JsonIgnoreProperties
- JsonIdentityInfo
- 实体图
即使上面列出的所有内容都应该有效,none 其中似乎也有效。到目前为止,我发现的唯一 "solution" 是删除吸气剂,但这消除了建立双向关系的目的,因为您无法访问它们。
有人知道我做错了什么吗,或者有人有其他可行的解决方案吗?
下面是一些代码片段:
用户Class:
@Entity
@Table(name = "users")
@NamedEntityGraph(
name = "user-entity-graph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("username"),
@NamedAttributeNode("email"),
@NamedAttributeNode("biography"),
@NamedAttributeNode("website"),
@NamedAttributeNode("longitude"),
@NamedAttributeNode("latitude"),
@NamedAttributeNode(value = "role", subgraph = "role-subgraph"),
@NamedAttributeNode(value = "followers", subgraph = "followers-subgraph"),
@NamedAttributeNode(value = "following", subgraph = "followers-subgraph"),
},
subgraphs = {
@NamedSubgraph(
name = "role-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("name")
}
),
@NamedSubgraph(
name = "followers-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("username"),
@NamedAttributeNode("email"),
@NamedAttributeNode("biography"),
@NamedAttributeNode("website"),
@NamedAttributeNode("longitude"),
@NamedAttributeNode("latitude"),
}
),
}
)
@NamedQueries({
@NamedQuery(name = "user.getAllUsers", query = "SELECT u FROM User u"),
@NamedQuery(name = "user.getUserById", query = "SELECT u FROM User u WHERE u.id = :id"),
@NamedQuery(name = "user.getUserByUsername", query = "SELECT u FROM User u WHERE u.username = :username"),
@NamedQuery(name = "user.getUserByEmail", query = "SELECT u FROM User u WHERE u.email = :email")
})
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
@XmlTransient
private String password;
@Column(length = 160)
private String biography;
@Column
private String website;
private double longitude;
private double latitude;
@ManyToOne(fetch = FetchType.LAZY)
private Role role;
@ManyToMany(
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.LAZY
)
@JoinTable(
name = "followers",
joinColumns = @JoinColumn(name = "follower"),
inverseJoinColumns = @JoinColumn(name = "following")
)
private Set<User> followers;
@ManyToMany(
mappedBy = "followers",
fetch = FetchType.LAZY
)
private Set<User> following;
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
private Set<Tweet> tweets;
角色Class:
@Entity
@Table(name = "roles")
@NamedEntityGraph(
name = "role-entity-graph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("name"),
@NamedAttributeNode(value = "permissions", subgraph = "permission-subgraph"),
@NamedAttributeNode(value = "users", subgraph = "user-subgraph"),
},
subgraphs = {
@NamedSubgraph(
name = "permission-subgraph",
attributeNodes = {
@NamedAttributeNode("name"),
}
),
@NamedSubgraph(
name = "roles-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("name")
}
),
@NamedSubgraph(
name = "user-subgraph",
attributeNodes = {
@NamedAttributeNode("id"),
@NamedAttributeNode("username"),
@NamedAttributeNode("email")
}
),
}
)
@NamedQueries({
@NamedQuery(name = "role.getAllRoles", query = "SELECT r FROM Role r"),
@NamedQuery(name = "role.getRoleById", query = "SELECT r FROM Role r WHERE r.id = :id"),
@NamedQuery(name = "role.getRoleByName", query = "SELECT r FROM Role r WHERE r.name = :name")
})
public class Role implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(unique = true, nullable = false)
private String name;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH}, fetch = FetchType.LAZY)
@JoinTable(
name = "role_permission",
joinColumns = @JoinColumn(name = "role_id"),
inverseJoinColumns = @JoinColumn(name = "permission_id")
)
private Set<Permission> permissions;
@OneToMany(mappedBy = "role", fetch = FetchType.LAZY)
private Set<User> users;
实施片段:
@PersistenceContext(unitName = "kwetterDB")
private EntityManager em;
@Override
public List<Role> all() {
EntityGraph eg = em.getEntityGraph("role-entity-graph");
return em.createNamedQuery("role.getAllRoles", Role.class).setHint("javax.persistence.fetchgraph", eg).getResultList();
}
我的 RoleController 的片段:
@Stateless
@Path("/roles")
public class RoleController {
@Inject
private RoleService roleService;
@Inject
private PermissionService permissionService;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response all() {
return Response.status(Response.Status.OK).entity( roleService.all()).build();
}
pom.xml:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0.1-b5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.24.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="kwetterDB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/myapp</jta-data-source>
<properties>
<!--<property name="javax.persistence.schema-generation.database.action" value="create"/>-->
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
搜索了一段时间后,我发现我必须使用 ObjectMapper 来触发 Json 注释。
资料来源:
适用于 @JsonIgnore
、@JsonBackReference
、@JsonManagedReference
、@JsonIgnoreProperties
和 @JsonIdentityInfo
。
在我的控制器中更改以下行:
return Response.status(Response.Status.OK).entity( roleService.all()).build();
致:
return Response.status(Response.Status.OK).entity(new ObjectMapper().writeValueAsString(roleService.all())).build();