GlassFish 4 中EclipseLink MOXY实现REST应用简介

译文
开发 后端
最近,随着JAVA EE 7 标准的最终落地,其中Oracle 还发布了GlassFish 4服务器,它可以说是JAVA EE 7标准的一种参考实现。

最近,随着JAVA EE 7 标准的最终落地,其中Oracle 还发布了GlassFish 4服务器,它可以说是JAVA EE 7标准的一种参考实现。 其中,Eclipse旗下的EclipseLink开源项目向JAVE EE 7中贡献了不少力量,其中包括JPA 2.1 (JSR-338)的实现,另外一个贡献是本文向大家介绍的EclipseLink MOXy项目,它是JAVE EE 7JAX-RS(REST标准)的一个默认的JSON Provider

首先简单介绍下Eclipse旗下的EclipseLink开源项目,它主要用来实现快速将JAVA中的对象转化为各种类型的XML,该项目主要有如下的特性:

  • 支持JAXB中最多的注解
  • 同时支持XML和JSON
  • 支持最新的JPA 2.1

对JPA-RS的增强支持

 MOXY有十分强大的将各类JAVA对象 序列化为XML以及XML反序列化为JAVA对象的能力。这在REST架构的应用中,MOXY可以用来实现JAX-RS标准中的各种转换,下面以一个REST的例子进行讲解。如果读者对REST和JAX-RS标准有不清楚的地方,请参考相关的资料。

  我们设计一个最简单的Hello World的REST Webservice。其中Customer对象是一个简单的POJO对象,代码如下:

  1. package org.example.service; 
  2.  
  3. import javax.ejb.*; 
  4. import javax.ws.rs.*; 
  5. import javax.ws.rs.core.MediaType; 
  6. import org.example.model.*; 
  7.  
  8. @Stateless 
  9. @LocalBean 
  10. @Path("/customers"
  11. public class CustomerService { 
  12.  
  13.     @GET 
  14.     @Produces({ 
  15.         MediaType.APPLICATION_XML, 
  16.         MediaType.APPLICATION_JSON 
  17.     }) 
  18.     @Path("{id}"
  19.     public Customer read(@PathParam("id"int id) { 
  20.         Customer customer = new Customer(); 
  21.         customer.setId(id); 
  22.         customer.setName("Jane Doe"); 
  23.  
  24.         PhoneNumber pn = new PhoneNumber(); 
  25.         pn.setType("work"); 
  26.         pn.setValue("5551111"); 
  27.         customer.getPhoneNumbers().add(pn); 
  28.  
  29.         return customer; 
  30.      } 
  31.  

可以看到,Customer对象中有一个PhoneNumber的表示电话号码的Pojo。代码中的注解都是遵守JAX-RS标准的REST相关的注解。其中,用注解

@ MediaType.APPLICATION_XML@ MediaType.APPLICATION_JSON,分别指出该REST会同时以XMLJSON的形式对外发布。而在JAX-RS标准中,用如下的方式,就可以实现REST的对外发布部署:

  1.  package org.example.service; 
  2.  
  3. import javax.ws.rs.ApplicationPath; 
  4. import javax.ws.rs.core.Application; 
  5.  
  6. @ApplicationPath("rest/*"
  7. public class CustomerApplication  extends Application { 
  8.  

其中,@ApplicationPath 注解指定所有服务的相对基址,如果为空字符串,则直接使用上下文根路径。上面表示这个REST服务将以如http://localhost/rest/xxx的形式对外发布,应该的根为rest。
  接下来我们具体看Customer这个POJO,代码如下:

  1. package org.example.model; 
  2.  
  3. import java.util.*; 
  4. import javax.xml.bind.annotation.*; 
  5.  
  6. @XmlRootElement 
  7. public class Customer { 
  8.  
  9.     private int id; 
  10.     private String name; 
  11.     private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); 
  12.  
  13.     public int getId() { 
  14.         return id; 
  15.     } 
  16.  
  17.     public void setId(int id) { 
  18.         this.id = id; 
  19.     } 
  20.  
  21.     public String getName() { 
  22.         return name; 
  23.     } 
  24.  
  25.     public void setName(String name) { 
  26.         this.name = name; 
  27.     } 
  28.  
  29.     @XmlElementWrapper 
  30.     @XmlElement(name="phoneNumber"
  31.     public List<PhoneNumber> getPhoneNumbers() { 
  32.         return phoneNumbers; 
  33.     } 
  34.  

在这个Customer对象中,其中保持了对另外一个对象phoneNumber的引用。使用@XmlElementWrapper,其目的是为了在XML中通过单独设置名为phoneNumber的别名标签去
更清晰的输出。
  接下来请看PhoneNumber类,代码如下:

  1. package org.example.model; 
  2.  
  3. import javax.xml.bind.annotation.*; 
  4.  
  5. public class PhoneNumber { 
  6.  
  7.     private String type; 
  8.     private String value; 
  9.  
  10.     @XmlAttribute 
  11.     public String getType() { 
  12.         return type; 
  13.     } 
  14.  
  15.     public void setType(String type) { 
  16.         this.type = type; 
  17.     } 
  18.  
  19.     @XmlValue 
  20.     public String getValue() { 
  21.         return value; 
  22.     } 
  23.  
  24.     public void setValue(String value) { 
  25.         this.value = value; 
  26.     } 
  27.  

注意,其中使用了注解@XmlAttribute,将type设置为转换后XML中的一个属性,而@XmlValue则将字段value直接序列为值,即如下的样子:

#p#

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <phone-number type="work">555-1234</phone-number>  

 如果不使用@XmlValue注解,则输出的XML为:

  1. <phone-numbertypephone-numbertype="work"> 
  2.   <value>12345</value> 
  3. </phone-number>  

接下来,我们尝试调用这个服务。下面是调用的urlhttp://localhost:8080/CustomerResource/rest/customers/1,则返回的XML为:

  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
  2. <customer id="1"> 
  3.     <name>Jane Doe</name> 
  4.     <phoneNumbers> 
  5.         <phoneNumber type="work">5551111</phoneNumber> 
  6.     </phoneNumbers> 
  7. </customer> 

这个并不奇怪,因为对象是以JAXB的标准去注解的,可以通过REST返回XML。如果在GlassFish 3.1.2的时候,Moxy还不是默认的JSON Provider,有如下的几点值得注意:

  •   POJO中的id属性如果是int类型的会以JSON text类型返回
  • customer对象中的phoneNumbers属性,其实持有的是List<PhoneNumber>,但在转变为JSON时变为JSON对象而不是一个JSON数组,如下:
    1.  
    2.     "id""1"
    3.  
    4.     "name""Jane Doe"
    5.  
    6.     "phoneNumbers": { 
    7.  
    8.         "phoneNumber": { 
    9.  
    10.             "@type""work"
    11.           "$""5551111"  
    12.         } 
    13.     }  

更奇怪的是,由于使用了@XmlAttribute注解和@XmlValue 注解,转变成JSON后,会分别变成“@type”,“$”显的不合理。而在最新的GlassFish 4中,上面的问题已经得到明显改善,输出的JSON如下:

  1.     "id"1
  2.  
  3.     "name""Jane Doe"
  4.  
  5.     "phoneNumbers": { 
  6.  
  7.         "phoneNumber": [ 
  8.  
  9.             "@type""work"
  10.  
  11.             "$""5551111" 
  12.         ] 
  13.     } 

在GlassFish 4中,能够正确将POJO中的如int类型的正确序列化为JSON中的整形,即“id”:1,注意到PhoneNumber类中的value属性由于是String类型,因此在序列化为JSON后依然为String类型。但熟悉JSON的朋友应该清楚,phoneNumbers在这里依然没能转换为最标准的JSON格式,但我们可以使用JAX-RS中的ContextResolver机制,并使用MXOYMOXyJsonConfig类去自定义JSON格式的显示,代码如下:

 

  1. package org.example.service; 
  2.  
  3. import javax.ws.rs.ext.*; 
  4. import org.eclipse.persistence.jaxb.JAXBContextProperties; 
  5. import org.glassfish.jersey.moxy.json.MoxyJsonConfig; 
  6.  
  7. @Provider 
  8. public class MOXyJsonContextResolver implements ContextResolver<MoxyJsonConfig> { 
  9.  
  10.     private final MoxyJsonConfig config; 
  11.  
  12.     public MOXyJsonContextResolver() { 
  13.         config = new MoxyJsonConfig() 
  14.             .setAttributePrefix(""
  15.             .setValueWrapper("value"
  16.             .property(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); 
  17.     } 
  18.  
  19.     @Override 
  20.     public MoxyJsonConfig getContext(Class<?> objectType) { 
  21.         return config; 
  22.     } 
  23.  

其中,通过MoxyJsonConfig类中的setValueWrapper方法,重新设置了使用原来POJO中的字段名作为JSON的key,因此就不带任何多余的符号了,生成的XML如下:

  1.     "id"1
  2.     "name""Jane Doe"
  3.     "phoneNumbers": [ 
  4.         { 
  5.             "type""work"
  6.             "value""5551111" 
  7.         } 
  8.     ] 

可见,这是符合JSON格式标准的输出了。 读者可以进一步通过http://www.eclipse.org/eclipselink/moxy.php访问更多关于MOXY项目的情况,也可以关注http://blog.bdoughan.com/的博客以了解更多关于MXOY项目的用法。

 原文链接:http://www.javacodegeeks.com/2013/06/moxy-is-the-new-default-json-binding-provider-in-glassfish-4.html

责任编辑:陈四芳 来源: javacodegeeks.com
相关推荐

2009-06-11 09:48:04

2009-06-10 15:14:00

2009-06-01 11:23:08

Glassfish部署Glassfish

2013-03-08 11:06:03

JavaEEGlassFish

2009-06-18 15:28:08

Glassfish JSpring

2009-06-11 13:46:38

用户访问权限GlassFish

2009-06-24 13:22:27

Glassfish

2022-03-29 09:00:00

Angular框架REST API

2009-06-22 15:39:45

JSFGlassFish管理

2009-06-11 11:54:00

GlassFishTomcat

2011-04-28 09:23:36

REST

2009-06-11 11:05:23

SUNGlassFish

2009-06-11 13:28:18

Glassfish集成

2020-07-02 21:38:59

物联网教育IOT

2011-10-27 16:24:48

API

2009-06-10 16:02:06

GlassFish下载GlassFish安装

2010-03-19 15:16:11

Python代码

2013-01-21 13:33:33

IBMdW

2019-10-23 10:14:24

TomcatJettyGlassFish

2011-08-01 15:35:51

GlassFishJava 7
点赞
收藏

51CTO技术栈公众号