JAXB或JAX-RS在我的JSON响应中用引号包装数字,将它们转换为字符串。 为什么这是默认行为,以及如何解决它?

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

自定义DateAdapter

public class DateAdapter extends XmlAdapter { @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

 @Path("/Employees") @javax.xml.bind.annotation.XmlRootElement @XmlType(propOrder={"hateoas","employees"}) public class EmployeeResource { List employees; public List getEmployees() { return employees; } public void setEmployees(List 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将所有数字包装在引号中。 有人可以指导我到我可以配置的地方吗?

提前致谢!

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

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

注意:我是EclipseLink JAXB(MOXy)的负责人,也是JAXB 2(JSR-222)专家组的成员。

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

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

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

 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, MessageBodyWriter{ @Context protected Providers providers; public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; } public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap 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 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 resolver = providers.getContextResolver(JAXBContext.class, mediaType); JAXBContext jaxbContext; if(null == resolver || null == (jaxbContext = resolver.getContext(type))) { return JAXBContext.newInstance(type); } else { return jaxbContext; } } } 

了解更多信息