Java RESTful返回对象内部的对象,将其带到toString而不是转换为JSON

时间:2016-12-13 11:37:58

标签: java json rest

  

(注意:如果这篇文章的布局不是最好的,我很抱歉,我很高兴   花了很多时间来计算这个编辑器的功能)

嗨,我正在做一个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;
    }

}

2 个答案:

答案 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获得了帮助。

希望它确实是帮助,谢谢。