JAXB或JAX-RS用引号将数字包装在我的JSON响应中,将它们转换为字符串。为什么这是默认行为,以及如何解决它? [英] JAXB or JAX-RS is wrapping numbers in my JSON responses with quotes, turning them into strings. Why this is the default behavior, and how to fix it?

查看:108
本文介绍了JAXB或JAX-RS用引号将数字包装在我的JSON响应中,将它们转换为字符串。为什么这是默认行为,以及如何解决它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发RESTful API。我有一个Employee类和一个EmployeeResource类。我还有一个自定义DateAdapter,它将我的Date属性更改为Long时间戳。但是,我的JSON响应将时间戳显示为字符串(用双引号括起来)而不是数字(不带双引号)。这是我的代码的缩写版本和捕获的JSON响应......

I am currently working on a RESTful API. I have an Employee class and an EmployeeResource class. I also have a custom DateAdapter, which changes my Date properties to Long timestamps. However, my JSON responses are showing the timestamps as strings (wrapped in double quotes) rather than numbers (without double quotes). Here is an abbreviated version of my code and captured JSON response...

自定义DateAdapter

Custom DateAdapter

public class DateAdapter extends XmlAdapter<Long, Date> {
    @Override
    public Date unmarshal(Long v) throws Exception {
        return new Date(Long.valueOf(v));  
    }
    @Override
    public Long marshal(Date v) throws Exception {
        return v.getTime();  
    }
}

实体类

@Entity
@javax.xml.bind.annotation.XmlRootElement
@XmlType(propOrder={"createdOn","empId"})
public class Employee implements Serializable {
    private Date createdOn;
    private Integer empId;

    @Column(nullable=false)
    @Temporal(TemporalType.TIMESTAMP)
    @XmlJavaTypeAdapter(DateAdapter.class)
    public Date getCreatedOn() {
        return createdOn;
    }
    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    @Id
    @XmlID
    public Integer getEmpId() {
        return empId;
    }
    public void setEmpId(Integer empId) {
        this.empId = empId;
    }
}

EmployeeResource

EmployeeResource

@Path("/Employees")
@javax.xml.bind.annotation.XmlRootElement 
@XmlType(propOrder={"hateoas","employees"})
public class EmployeeResource {
    List<Employee> employees;

    public List<Employee> getEmployees() {
        return employees;
    }
    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }
    @GET
    @Path("/{id}")
    @Produces("application/json")
    public Response getEmployee(@Context UriInfo ui, @PathParam("id") Integer id) {
        Session session = HibernateUtil.getSession();
        session.beginTransaction();
        Criteria criteria=session.createCriteria(Employee.class);
        criteria.add(Restrictions.eq("empId", new Integer(10150)));
        this.employees = criteria.list();
        return Response.ok(this).build();
    }
}

当前JSON回复

{
  "employees":{
    "createdOn":"1330915130163",
    "empId":"10150"
  }
}

预期的JSON响应

{
  "employees":{
    "createdOn":1330915130163,
    "empId":10150
  }
}

我假设有一些方法可以阻止JAXB或JAX-RS包装引号中的所有数字。有人可以指导我到我可以配置的地方吗?

I'm assuming that there's some way to prevent JAXB or JAX-RS from wrapping all numbers in quotes. Could someone guide me to where I could configure this?

提前致谢!

编辑#1 2012.03。 07
好​​的,经过一些更多的研究,我认为我的问题是使用默认的JSONConfiguration.Notation,MAPPED。看起来像NATURAL JSONConfiguration.Notation会得到我想要的东西。但是,我还没有找到如何应用该应用程序的明确示例。我假设我会在扩展javax.ws.rs.core.Application的ApplicationConfig类中指定它。

EDIT #1 2012.03.07 Ok, so after some more researching, I think my problem is with the default JSONConfiguration.Notation being used, MAPPED . It looks like the NATURAL JSONConfiguration.Notation would get me what I want. However, I haven't found a clear example of how to apply that application wide. I'm assuming I would specify this in my ApplicationConfig class that extends javax.ws.rs.core.Application .

EDIT#2 2012.03.10
Ok ,经过一些研究,我决定使用JSON解析器库,杰克逊。它似乎是使用默认配置的最完整的JSON解决方案。默认情况下,日期被转换为相应的时间戳并序列化为数字(无引号)。我遇到的唯一缺点是Jackson目前不支持JAXB注释,@ XMLID和@XmlIDREF。由于我在我的数据模型中有直接的自引用(上面没有显示),我创建了另一个要讨论的问题。如果有人有兴趣点击此处关注该主题...

EDIT #2 2012.03.10 Ok, so after some more researching I decided to use the JSON parser library, Jackson. It seems to be the most complete JSON solution out there using just the default configuration. By default Dates are translated to their corresponding timestamps and serialized as numbers (w/o quotes). The only drawback I have come across is that Jackson currently does not support the JAXB annotations, "@XmlID" and "@XmlIDREF". Since I have direct self-references in my data model (not shown above), I have created another question to discuss. If anyone is interested click here to follow that thread...

推荐答案

注意:我是 EclipseLink JAXB(MOXy) 的主角和 JAXB 2(JSR-222) 专家组。

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

您正在使用的JAX-RS实现可能正在使用 JAXB(JSR-222) 实现与 Jettison 生成JSON。 Jettison提供了一个与JSON交互的StAX API,因为StAX API没有任何类型的WRT文本输入,所有简单的值都被视为字符串:

The JAX-RS implementation you are using may be using a JAXB (JSR-222) implementation with something like Jettison to produce JSON. Jettison provides a StAX API to interact with JSON, since that StAX APIs don't have any sort of typing WRT text, all the simple values get treated as strings:

  • http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html

获取行为您正在寻找可以使用不同的绑定解决方案。我们将此支持添加到EclipseLink 2.4的MOXy组件中:

To get the behaviour you are looking for you can use a different binding solution. We are adding this support into the MOXy component for EclipseLink 2.4:

  • http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html

要在JAX-RS环境中将MOXy配置为JSON绑定提供程序,可以创建 MessageBodyReader / MessageBodyWriter 如下所示:

To configure MOXy as your JSON-binding provider in a JAX-RS environment, you could create a MessageBodyReader/MessageBodyWriter that looks like:

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
import javax.xml.transform.stream.StreamSource;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.*;
import javax.xml.bind.*;

@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class MOXyJSONProvider implements 
    MessageBodyReader<Object>, MessageBodyWriter<Object>{

    @Context
    protected Providers providers;

    public boolean isReadable(Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    public Object readFrom(Class<Object> type, Type genericType,
        Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
        throws IOException, WebApplicationException {
        try {
            Unmarshaller u = getJAXBContext(type, mediaType).createUnmarshaller();
            u.setProperty("eclipselink.media-type", mediaType.toString());
            u.setProperty("eclipselink.json.include-root", false);//tiny fix
            return u.unmarshal(new StreamSource(entityStream), (Class) genericType);
        } catch(JAXBException jaxbException) {
            throw new WebApplicationException(jaxbException);
        }
    }

    public boolean isWriteable(Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    public void writeTo(Object object, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException,
        WebApplicationException {
        try {
            Marshaller m = getJAXBContext(Customer.class, mediaType).createMarshaller();
            m.setProperty("eclipselink.media-type", mediaType.toString());
            m.setProperty("eclipselink.json.include-root", false);
            m.marshal(object, entityStream);
        } catch(JAXBException jaxbException) {
            throw new WebApplicationException(jaxbException);
        }
    }

    public long getSize(Object t, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    private JAXBContext getJAXBContext(Class<?> type, MediaType mediaType) 
        throws JAXBException {
        ContextResolver<JAXBContext> resolver 
            = providers.getContextResolver(JAXBContext.class, mediaType);
        JAXBContext jaxbContext;
        if(null == resolver || null == (jaxbContext = resolver.getContext(type))) {
            return JAXBContext.newInstance(type);
        } else {
            return jaxbContext;
        }
    }

}

更多信息

  • https://stackoverflow.com/a/8989659/383861
  • http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-15.html
  • http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html

这篇关于JAXB或JAX-RS用引号将数字包装在我的JSON响应中,将它们转换为字符串。为什么这是默认行为,以及如何解决它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆