JAX-RS 2.0 與 XML/JSON 資料轉換 - 神奇的 MOXy & Jackson
在前幾次的 JAX-RS 2.0 文章之中,介紹的都是 Java 基本型別的處理方式,不過我們一般比較常用的,反而是各種自訂 JavaBeans 型別與 XML/JSON 資料格式之間的轉換。資料轉換在 JAX-RS 2.0 裡頭,雖然不是預設就會啟用的功能,但是也不難。建立 JAX-RS 2.0 專案為了示範方便,請執行底下的指令,建立一個使用 Grizzly 的 Jersey 專案: mvn archetype:generate -DarchetypeGroupId=org.glassfish.jersey.archetypes -DarchetypeArtifactId=jersey-quickstart-grizzly2 -DarchetypeVersion=2.5.1 -DgroupId=tw.com.codedata -DartifactId=jaxbdemo -Dpackage=tw.com.codedata.jaxbdemo -DinteractiveMode=false 刪除自動產生的
package tw.com.codedata.jaxbdemo;
import java.io.*;
public class Region implements Serializable
{
static final long serialVersionUID = 20140124L;
private int regionId;
private String regionDescription;
public Region() {}
public Region(int regionId, String regionDescription)
{
this.regionId = regionId;
this.regionDescription = regionDescription;
}
public int getRegionId()
{
return regionId;
}
public void setRegionId(int regionId)
{
this.regionId = regionId;
}
public String getRegionDescription()
{
return regionDescription;
}
public void setRegionDescription(String regionDescription)
{
this.regionDescription = regionDescription;
}
}
package tw.com.codedata.jaxbdemo;
import java.util.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("/regions")
public class RegionService
{
private static List<Region> regionList = null;
private static Region errorRegion = null;
static
{
regionList = new ArrayList<Region>();
regionList.add(new Region(1, "Eastern"));
regionList.add(new Region(2, "Western"));
regionList.add(new Region(3, "Northern"));
regionList.add(new Region(4, "Southern"));
errorRegion = new Region(0, "Error");
}
public RegionService()
{
}
@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public int create(Region region)
{
regionList.add(region);
return 1;
}
@GET
@Path("/{regionId}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Region retrieve(@PathParam("regionId") int regionId)
{
for (Region region : regionList)
{
if (region.getRegionId() == regionId) return region;
}
return errorRegion;
}
@DELETE
@Path("/{regionId}")
public int delete(@PathParam("regionId") int regionId)
{
int found = 0;
for (Region r : regionList)
{
if (r.getRegionId() == regionId)
{
regionList.remove(r);
found = 1;
}
}
return found;
}
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<Region> retrieveAll()
{
return regionList;
}
@PUT
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public int update(Region region)
{
int found = 0;
int targetId = region.getRegionId();
for (Region r : regionList)
{
if (r.getRegionId() == targetId)
{
r.setRegionDescription(region.getRegionDescription());;
found = 1;
}
}
return found;
}
}
整個專案目錄架構如下: 執行之後,雖然可以透過 RESTClient 看到 WADL (Web Application Description Language) 檔案: 但是卻沒辦法正確觸發 原因就在於,Jersey 目前的設定只能處理簡單的 Java 型別,但是對於 POJO 與 XML/JSON 格式之間的轉換,就無能為力了。 XML 支援在 Java 與 REST 的邂逅(二)JAX-RS 核心 Annotation 裡頭提到,如果想要提供 XML 支援,也就是讓
JAX-RS 2.0 的規格要求 Implementation 必須支援上面提到的幾種作法。不過 JAXP 的 Application supplied JAXB classes 指的就是有加上 JAXB 相關 Annotation 的 Java 類別。這種方式比較簡單,適合用在初學或是沒有詭異需求的時候。 以我們的範例來說,只要修改一下前面的 package tw.com.codedata.jaxbdemo;
import java.io.*;
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "region")
@XmlAccessorType(XmlAccessType.FIELD)
public class Region implements Serializable
{
...
}
Jersey 就可以順利進行 Marshalling 跟 Unmarshalling,把 JSON 支援Jersey 把 JSON 這部份的支援設計成 Extension Module,目前可以透過底下任意一個 3rd-Party Library 來達成:
只要 Jersey 在 CLASSPATH 發現這幾個 Library 的存在,就會自動註冊使用。 MOXy因為 EclipseLink 貢獻了 EclipseLink MOXy 這個 JSON-Binding Provider 給 JAX-RS 2.0,而 Jersey 又是 JAX-RS 2.0 的 Reference Implementation,所以 MOXy 順理成章就變成是 Jersey 建議使用的 JSON-Binding Library。 檢查剛剛由 Maven 自動產生的 <!-- uncomment this to get JSON support:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
-->
打開這一段註解,重新再編譯一次,執行後應該就可以順利觸發 Jackson網路上有些人比較喜歡使用 Jackson 這個 JSON Processor,所以 Jersey 當然也支援。Jackson 有一個 Jackson JAX-RS Providers 子計畫,用來為 JAX-RS 2.0 提供 JSON、XML、與 Smile 三種資料格式的轉換。從 Jackson 2.2 版開始,這個子計畫會取代以前的 Extension Module,比方說 透過 Maven 使用 Jackson JAX-RS Providers 的時候,請在專案的 <dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.3.0</version>
</dependency>
然後一樣為 檢視 <dependencies>
<!-- builds on shared base JAX-RS handling code... -->
<dependency>
<artifactId>jackson-jaxrs-base</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
</dependency>
<!-- Extends Jackson core, mapper, and also (sort of optionally) on JAXB annotation handler -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${version.jackson.core}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${version.jackson.core}</version>
</dependency>
<!-- also need JAXB annotation support -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${version.jackson.jaxb}</version>
</dependency>
<!-- test deps should come from parent, including jersey -->
</dependencies>
|

Java 學習之路




