(注意:如果这篇文章的布局不是最好的,我很抱歉,我很高兴 花了很多时间来计算这个编辑器的功能)
嗨,我正在做一个RESTful Web项目,我遇到一个问题,返回一个包含另一个对象的对象(但是里面的对象实际上是" Object")。
在我的情况下,我有公司,客户和优惠券资源。然后,每一个都包含字段,类级别的@XMLRootElement注释,空构造函数(以及接收参数的构造函数),当然还有getter和setter。
对于服务,类级别有注释:
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
get方法是自我:
@GET
@Path("/myCompany)
public Message getMyCompany(){
Message message;
try{
message = new MessageSuccess(company);
} catch(Exception e){
message = new MessageError(e.getMessage());
}
return message;
}
现在构建Message对象的方式,它是一个抽象类(也包含@XMLRootElement),它有三个字段:
messageType (enum)
value (Object)
message (String)
它具有资源的所有功能(getter和setter,构造等......)
有两个类扩展了Message。 它们还有一个空的构造函数和参数化的构造函数,它们没有@XMLRootElement注释。
现在的问题是,当客户端执行get方法时,它会收到一个
的JSON对象messageType: 'SUCCESS'
value: 'com.publicCodes.resources.Company@6c4sad546d'
基本上它返回Company对象的toString()。 我不知道如何解决这个问题。 由于不良做法,返回servlet的Response对象不是一个选项。 退回公司对象它的自我也不是一个选择。
感谢并等待您的解决方案!
**
为那些想看实际代码的人编辑:
** 这是Message抽象类:
package com.publicCouponRest.util;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
@XmlRootElement
public abstract class Message {
private MessageResultType messageType;
private Object value;
private String message;
public Message() {
}
public Message(MessageResultType messageType, String message) {
this.messageType = messageType;
this.message = message;
}
public Message(MessageResultType messageType, Object value) {
this.messageType = messageType;
this.value = value;
}
public MessageResultType getMessageType() {
return messageType;
}
public void setMessageType(MessageResultType messageType) {
this.messageType = messageType;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
这是MessageSuccess扩展Message:
package com.publicCouponRest.util;
public class MessageSuccess extends Message {
public MessageSuccess() {
}
public MessageSuccess(Object value) {
super(MessageResultType.SUCCESS, value);
}
}
当然还有公司资源:
package com.publicCodes.resources;
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
import com.publicCouponRest.services.AttributeKeys;
@XmlRootElement
public class Company {
private long id;
private String compName;
private String password;
private String email;
private Map<Long, Coupon> coupons;
private CompanyStatus companyStatus;
private AttributeKeys userType = AttributeKeys.COMPANY;
public Company(long id, String compName, String password, String email, Map<Long, Coupon> coupons, CompanyStatus companyStatus) {
this(compName, password, email);
this.id = id;
this.coupons = coupons;
this.companyStatus = companyStatus;
}
public Company(String compName, String password, String email) {
super();
this.compName = compName;
this.password = password;
this.email = email;
}
public Company() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getCompName() {
return compName;
}
public void setCompName(String compName) {
this.compName = compName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Map<Long, Coupon> getCoupons() {
return coupons;
}
public CompanyStatus getCompanyStatus() {
return companyStatus;
}
public void setCompanyStatus(CompanyStatus companyStatus) {
this.companyStatus = companyStatus;
}
public void setCoupons(Map<Long, Coupon> coupons) {
this.coupons = coupons;
}
public AttributeKeys getUserType() {
return userType;
}
public void setUserType(AttributeKeys userType) {
this.userType = userType;
}
}
答案 0 :(得分:1)
确定。我认为你和杰克森有太多的乐趣了:
你试图把任何对象&#39;在节点中。不是吗?
为此,您必须使用注释:
@XmlAnyElement(lax=false)
如下所示:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public abstract class Message {
....
@XmlAnyElement(lax=false)
private Object value;
....
应该是必要的。这样,您就可以将任何传入的XML数据节点放在该Object中(JAXB必须知道该Object的类,并且该类必须注释,但它允许您管理未确定的类)
(编辑):
另一方面:对象 - &gt; XML:现在的问题是您要向JAXB发送您的公司&#39;对象,但它只看到一个&#39;对象&#39;因为你告诉它它是&#39; Object&#39;类型的对象,而JAXB只知道如何序列化&#39; Object.class&#39;调用它的.toString()因为Object.class没有得到任何JAXB注释。尝试返回此方法的结果而不是对象:
(数据将是您的回复和clazz Company.class或其他)
import javax.xml.bind.JAXBContext;
import javax.xml.transform.dom.DOMResult;
import org.w3c.dom.Element;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
...
public static Element marshallToElement(Object data, Class clazz) {
DOMResult res = null;
try {
JAXBContext ctx = JAXBContextManager.getInstance(clazz.getPackage().getName());
Marshaller marshaller = ctx.createMarshaller();
res = new DOMResult();
marshaller.marshal(data, res);
} catch (JAXBException e) {
LOG.error(e);
}
return ((Document)res.getNode()).getDocumentElement();
}
这样你就会返回一个JAXBElement,这是一组节点&#39; JAXB将知道如何编组。
此时,如果它适合你,它是一个缓存JAXBContext的好习惯,它可以做得很好(JAXBContext是线程安全的,Marshallers NO)并且它对JAXB来说是一个重要的任务。执行:
JAXBContextManager.getInstance(clazz.getPackage().getName())
因此,每次转换只尝试一次。
<强> PS:强>
尝试仅将JAXB注释放在最终的类中,我遇到了问题(因为我在注释的子类中使用注释......最后在同一个类中使用所有注释更清晰)
答案 1 :(得分:0)
Jersey/JAX-RS 2 client
我认为您阅读了一些WebTarget API,它是如何工作的以及它返回的内容。并返回Response
对象
然后你可以改变你的方法:
@GET
@Path("/myCompany)
public Response getMyCompany() {
Message message;
try {
message = new MessageSuccess(company);
return Response.status(200).entity(message).build();
} catch (Exception e) {
message = new MessageError(e.getMessage());
return Response.status(500).entity(message).build();
}
}
之后,您应该将其添加到main
方法中:
WebTarget target = client.target(BASE).path("myCompany");
Response response = target.request().accept(...).post(Entity.json(message));//modify this line to suit your needs
Message message = response.readEntity(Message.class);
以前尝试过类似的事情,我从@peeskillet
的答案this stackoverflow page获得了帮助。
希望它确实是帮助,谢谢。