新聞中心
最近,隨著JAVA EE 7 標(biāo)準(zhǔn)的最終落地,其中Oracle 還發(fā)布了GlassFish 4服務(wù)器,它可以說(shuō)是JAVA EE 7標(biāo)準(zhǔn)的一種參考實(shí)現(xiàn)。 其中,Eclipse旗下的EclipseLink開(kāi)源項(xiàng)目向JAVE EE 7中貢獻(xiàn)了不少力量,其中包括JPA 2.1 (JSR-338)的實(shí)現(xiàn),另外一個(gè)貢獻(xiàn)是本文向大家介紹的EclipseLink MOXy項(xiàng)目,它是JAVE EE 7中JAX-RS(REST標(biāo)準(zhǔn))的一個(gè)默認(rèn)的JSON Provider。

首先簡(jiǎn)單介紹下Eclipse旗下的EclipseLink開(kāi)源項(xiàng)目,它主要用來(lái)實(shí)現(xiàn)快速將JAVA中的對(duì)象轉(zhuǎn)化為各種類型的XML,該項(xiàng)目主要有如下的特性:
- 支持JAXB中最多的注解
- 同時(shí)支持XML和JSON
- 支持最新的JPA 2.1
對(duì)JPA-RS的增強(qiáng)支持
MOXY有十分強(qiáng)大的將各類JAVA對(duì)象 序列化為XML以及XML反序列化為JAVA對(duì)象的能力。這在REST架構(gòu)的應(yīng)用中,MOXY可以用來(lái)實(shí)現(xiàn)JAX-RS標(biāo)準(zhǔn)中的各種轉(zhuǎn)換,下面以一個(gè)REST的例子進(jìn)行講解。如果讀者對(duì)REST和JAX-RS標(biāo)準(zhǔn)有不清楚的地方,請(qǐng)參考相關(guān)的資料。
我們?cè)O(shè)計(jì)一個(gè)最簡(jiǎn)單的Hello World的REST Webservice。其中Customer對(duì)象是一個(gè)簡(jiǎn)單的POJO對(duì)象,代碼如下:
- package org.example.service;
- import javax.ejb.*;
- import javax.ws.rs.*;
- import javax.ws.rs.core.MediaType;
- import org.example.model.*;
- @Stateless
- @LocalBean
- @Path("/customers")
- public class CustomerService {
- @GET
- @Produces({
- MediaType.APPLICATION_XML,
- MediaType.APPLICATION_JSON
- })
- @Path("{id}")
- public Customer read(@PathParam("id") int id) {
- Customer customer = new Customer();
- customer.setId(id);
- customer.setName("Jane Doe");
- PhoneNumber pn = new PhoneNumber();
- pn.setType("work");
- pn.setValue("5551111");
- customer.getPhoneNumbers().add(pn);
- return customer;
- }
- }
可以看到,Customer對(duì)象中有一個(gè)PhoneNumber的表示電話號(hào)碼的Pojo。代碼中的注解都是遵守JAX-RS標(biāo)準(zhǔn)的REST相關(guān)的注解。其中,用注解
@ MediaType.APPLICATION_XML和@ MediaType.APPLICATION_JSON,分別指出該REST會(huì)同時(shí)以XML和JSON的形式對(duì)外發(fā)布。而在JAX-RS標(biāo)準(zhǔn)中,用如下的方式,就可以實(shí)現(xiàn)REST的對(duì)外發(fā)布部署:
- package org.example.service;
- import javax.ws.rs.ApplicationPath;
- import javax.ws.rs.core.Application;
- @ApplicationPath("rest/*")
- public class CustomerApplication extends Application {
- }
其中,@ApplicationPath 注解指定所有服務(wù)的相對(duì)基址,如果為空字符串,則直接使用上下文根路徑。上面表示這個(gè)REST服務(wù)將以如http://localhost/rest/xxx的形式對(duì)外發(fā)布,應(yīng)該的根為rest。
接下來(lái)我們具體看Customer這個(gè)POJO,代碼如下:
- package org.example.model;
- import java.util.*;
- import javax.xml.bind.annotation.*;
- @XmlRootElement
- public class Customer {
- private int id;
- private String name;
- private List
phoneNumbers = new ArrayList (); - public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- @XmlElementWrapper
- @XmlElement(name="phoneNumber")
- public List
getPhoneNumbers() { - return phoneNumbers;
- }
- }
在這個(gè)Customer對(duì)象中,其中保持了對(duì)另外一個(gè)對(duì)象phoneNumber的引用。使用@XmlElementWrapper,其目的是為了在XML中通過(guò)單獨(dú)設(shè)置名為phoneNumber的別名標(biāo)簽去
更清晰的輸出。
接下來(lái)請(qǐng)看PhoneNumber類,代碼如下:
- package org.example.model;
- import javax.xml.bind.annotation.*;
- public class PhoneNumber {
- private String type;
- private String value;
- @XmlAttribute
- public String getType() {
- return type;
- }
- public void setType(String type) {
- this.type = type;
- }
- @XmlValue
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- }
注意,其中使用了注解@XmlAttribute,將type設(shè)置為轉(zhuǎn)換后XML中的一個(gè)屬性,而@XmlValue則將字段value直接序列為值,即如下的樣子:
#p#
555-1234
如果不使用@XmlValue注解,則輸出的XML為:
12345
接下來(lái),我們嘗試調(diào)用這個(gè)服務(wù)。下面是調(diào)用的url http://localhost:8080/CustomerResource/rest/customers/1,則返回的XML為:
Jane Doe 5551111
這個(gè)并不奇怪,因?yàn)閷?duì)象是以JAXB的標(biāo)準(zhǔn)去注解的,可以通過(guò)REST返回XML。如果在GlassFish 3.1.2的時(shí)候,Moxy還不是默認(rèn)的JSON Provider,有如下的幾點(diǎn)值得注意:
- POJO中的id屬性如果是int類型的會(huì)以JSON text類型返回
- customer對(duì)象中的phoneNumbers屬性,其實(shí)持有的是List
,但在轉(zhuǎn)變?yōu)镴SON時(shí)變?yōu)镴SON對(duì)象而不是一個(gè)JSON數(shù)組,如下:
- {
- "id": "1",
- "name": "Jane Doe",
- "phoneNumbers": {
- "phoneNumber": {
- "@type": "work",
- "$": "5551111"
- }
- }
- }
更奇怪的是,由于使用了@XmlAttribute注解和@XmlValue 注解,轉(zhuǎn)變成JSON后,會(huì)分別變成“@type”,“$”顯的不合理。而在最新的GlassFish 4中,上面的問(wèn)題已經(jīng)得到明顯改善,輸出的JSON如下:
- "id": 1,
- "name": "Jane Doe",
- "phoneNumbers": {
- "phoneNumber": [
- "@type": "work",
- "$": "5551111"
- ]
- }
- }
在GlassFish 4中,能夠正確將POJO中的如int類型的正確序列化為JSON中的整形,即“id”:1,注意到PhoneNumber類中的value屬性由于是String類型,因此在序列化為JSON后依然為String類型。但熟悉JSON的朋友應(yīng)該清楚,phoneNumbers在這里依然沒(méi)能轉(zhuǎn)換為最標(biāo)準(zhǔn)的JSON格式,但我們可以使用JAX-RS中的ContextResolver機(jī)制,并使用MXOY中MOXyJsonConfig類去自定義JSON格式的顯示,代碼如下:
- package org.example.service;
- import javax.ws.rs.ext.*;
- import org.eclipse.persistence.jaxb.JAXBContextProperties;
- import org.glassfish.jersey.moxy.json.MoxyJsonConfig;
- @Provider
- public class MOXyJsonContextResolver implements ContextResolver
{ - private final MoxyJsonConfig config;
- public MOXyJsonContextResolver() {
- config = new MoxyJsonConfig()
- .setAttributePrefix("")
- .setValueWrapper("value")
- .property(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
- }
- @Override
- public MoxyJsonConfig getContext(Class> objectType) {
- return config;
- }
- }
其中,通過(guò)MoxyJsonConfig類中的setValueWrapper方法,重新設(shè)置了使用原來(lái)POJO中的字段名作為JSON的key,因此就不帶任何多余的符號(hào)了,生成的XML如下:
- {
- "id": 1,
- "name": "Jane Doe",
- "phoneNumbers": [
- {
- "type": "work",
- "value": "5551111"
- }
- ]
- }
可見(jiàn),這是符合JSON格式標(biāo)準(zhǔn)的輸出了。 讀者可以進(jìn)一步通過(guò)http://www.eclipse.org/eclipselink/moxy.php訪問(wèn)更多關(guān)于MOXY項(xiàng)目的情況,也可以關(guān)注http://blog.bdoughan.com/的博客以了解更多關(guān)于MXOY項(xiàng)目的用法。
原文鏈接:http://www.javacodegeeks.com/2013/06/moxy-is-the-new-default-json-binding-provider-in-glassfish-4.html
當(dāng)前文章:GlassFish4中EclipseLinkMOXY實(shí)現(xiàn)REST應(yīng)用簡(jiǎn)介
當(dāng)前路徑:http://www.dlmjj.cn/article/dhiedcg.html


咨詢
建站咨詢
