我的设置:
JBoss AS 7.1.1使用JPA,Hibernate(连接到PostgreSQL),RESTEasy,Jackson 1.9.2 for JSON,EclipseLink MOXy 2.4.1 for XML
我有两个实体 - 群组和用户。一个组包含许多用户(一对多)。我正在宣布与JPA注释的双向关系(见下文),所以我必须使用@JsonManagedReference
/ @JsonBackReference
(对于JSON)和@XmlInverseReference
(对于XML)来防止周期。这可以按预期工作,除非我尝试通过REST创建用户,在使用XML时我无法将她分配给组。使用JSON时,它可以工作:
Jackson JSON 作品(成功添加Jane Doe并将她放入第5组):
POST request to /user
Content-Type: application/json
Accept: application/json
Body: {"name":"Jane Doe", "group":{"id":5}}
Response:
{
"id": 12,
"name":"Jane Doe"
}
Hibernate: insert into users (group_id, name, id) values (5, 'Jane Doe', 12)
这是使用Jackson添加用户后的GroupEndpoint响应:
GET request to /group
Accept: application/json
Response:
[{"id":5,"name":"My User Group","users":[{"id":12,"name":"Jane Doe"}]}
MOXy XML 不起作用(Jane Doe是孤儿):
POST request to /user
Content-Type: application/xml
Accept: application/xml
Body: <name>Jane Doe</name><group><id>5</id></group>
Response:
<user><name>Jane Doe</name><id>12</id></user>
Hibernate: insert into users (group_id, name, id) values (null, 'Jane Doe', 12)
这是使用MOXy添加用户后的GroupEndpoint响应:
GET request to /group
Accept: application/xml
Response:
<collection>
<group><id>5</id><name>My User Group</name></group>
</collection>
我已尝试过@XmlID
和@XmlIDREF
同样的问题。 @XmlTransient
同样会忽略编组和解组的子到父关系。
我的问题:
如何在没有MOXy忽略新用户的组字段(标记为@XmlInverseReference)的情况下,通过用户REST端点将用户添加到组?
我应该扩充我的REST端点,创建XmlAdapter,还是编写自定义序列化程序?我错过了一个带有不同注释的简单解决方案吗? 是否有一种完全不同的方法通过REST首选暴露关系对象?非常感谢任何帮助。
以下是群组实体:
@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Group implements Serializable {
@Id
private Long id;
@Column
private String name;
@OneToMany(mappedBy="group", cascade=CascadeType.ALL)
@JsonManagedReference("group-user")
private Set<User> users;
// Omitting getters and setters etc...
}
这是用户实体:
@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
@Id
private Long id;
@Column
private String name;
@ManyToOne
@JsonBackReference("group-user")
@XmlInverseReference(mappedBy="users")
private Group group;
// Omitting getters and setters etc...
}
这是User REST端点:
@Stateful
@Path("/user")
@TransactionAttribute
public class UserEndpoint {
@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;
@POST
@Consumes({"application/xml","application/json"})
public User create(User entity) {
em.joinTransaction();
em.persist(entity);
return entity;
}
}
这是Group REST端点(包含以显示需要防止循环):
@Stateful
@Path("/group")
@TransactionAttribute
public class GroupEndpoint {
@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;
@GET
@Produces({"application/xml","application/json"})
public List<Group> listAll() {
final List<Group> results = em.createQuery("SELECT x FROM Group x").getResultList();
return results;
}
}
添加杰克逊的用户后,这是GroupEndpoint MOXy 响应,以测试周期:
GET request to /group
Accept: application/xml
Response:
<collection>
<group>
<id>5</id>
<name>My User Group</name>
<users><id>12</id><name>Jane Doe</name></users>
</group>
</collection>
答案 0 :(得分:2)
注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。
现在,EclipseLink 2.5.0中已实现对用例的支持。您可以从以下链接下载夜间标签(盯着2013年3月1日)。
JAVA模型
现在,MOXy支持在关系的两个方向上指定@XmlInverseReference
注释。单独指定时,它就像@XmlTransient
一样用于编组,为了使其可写,您需要将其与@XmlElement
结合使用。
用户强>
import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;
@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
@Id
private Long id;
@Column
private String name;
@ManyToOne
//@JsonBackReference("group-user")
@XmlElement
@XmlInverseReference(mappedBy="users")
private Group group;
public Group getGroup() {
return group;
}
// Omitting other getters and setters etc...
}
<强>组强>
import java.io.Serializable;
import java.util.Set;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;
@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Group implements Serializable {
@Id
private Long id;
@Column
private String name;
@OneToMany(mappedBy="group", cascade=CascadeType.ALL)
//@JsonManagedReference("group-user")
@XmlElement
@XmlInverseReference(mappedBy="group")
private Set<User> users;
public Set<User> getUsers() {
return users;
}
// Omitting other getters and setters etc...
}
DEMO CODE
<强>演示强>
下面是一些可以运行的代码,以证明一切正常。除了XML用例之外,MOXy还可以用于处理JSON。
import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
// XML USE CASE
StringReader xml = new StringReader("<user><name>Jane Doe</name><group><id>5</id></group></user>");
User userFromXML = (User) unmarshaller.unmarshal(xml);
System.out.println(userFromXML.getGroup().getUsers());
// JSON USE CASE
StringReader json = new StringReader("{\"name\":\"Jane Doe\", \"group\":{\"id\":5}}");
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
StreamSource jsonSource = new StreamSource(json);
User userFromJSON = unmarshaller.unmarshal(jsonSource, User.class).getValue();
System.out.println(userFromJSON.getGroup().getUsers());
}
}
<强>输出强>
以下是运行演示代码的输出,显示后向指针已正确设置。
[forum14844691.User@147ee929]
[forum14844691.User@685c53ff]
更多信息