[英]How to serialize Java primitives using Jersey REST
在我的應用程序中,我使用Jersey REST來序列化復雜對象。 這很好用。 但是有一些方法只返回一個int或boolean。
澤西島無法處理原始類型(據我所知),可能是因為它們沒有注釋,而澤西沒有默認注釋。 我通過創建像RestBoolean或RestInteger這樣的復雜類型來解決這個問題,它只包含一個int或boolean值並具有相應的注釋。
有沒有比編寫這些容器對象更簡單的方法?
看看Genson。它幫助了我很多類似的問題。使用Genson你可以使用int,boolean,list等泛型......這是一個簡單的例子。
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getMagicList() {
List<Object> objList = new ArrayList<>();
stringList.add("Random String");
stringList.add(121); //int
stringList.add(1.22); //double
stringList.add(false); //bolean
return Response.status(Status.OK).entity(objList).build();
}
這將產生一個有效的JSON女巫可以像這樣非常簡單地檢索:
Client client = Client.create();
WebResource webResource = client.resource("...path to resource...");
List objList = webResource.accept(MediaType.APPLICATION_JSON).get(ArrayList.class);
for (Object obj : objList) {
System.out.println(obj.getClass());
}
您將看到Genson將幫助您在客戶端解碼JSON並為每個輸出正確的類。
你在寫服務還是客戶? 在服務端,你只需編寫一個MessageBodyWriter來將數據流序列化為類型的Java對象。 在我的用例中,我正在編寫的服務輸出到JSON或XML,在XML的情況下,我只是在我的類的頂部拋出一個JAXB注釋,我就完成了。
您是否看過澤西用戶指南?
告訴Jersey生成適當的JSON文檔(自然json)。 我為rest app和JAXBContext解析器使用相同的類,發現它是最干凈的封裝。
更好的程序員可以實現幫助來迭代.class文件並通過識別@Annotation標簽自動列出適當的類。 我不知道如何在自己的源代碼中運行它。
這兩個鏈接有助於研究這個額外的java行話。 我不知道為什么沒有Jersey參數可以讓所有人都能開箱即用。
WEB-INF / web.xml(片段):
<servlet>
<servlet-name>RESTServlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.myapp.rest.RESTApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RESTServlet</servlet-name>
<url-pattern>/servlet/rest/*</url-pattern>
</servlet-mapping>
com.myapp.rest.RESTApplication.java
package com.myapp.rest;
import java.util.*;
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.ContextResolver;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
public class RESTApplication extends Application implements ContextResolver<JAXBContext> {
private JAXBContext context;
private Class<?>[] types;
public RESTApplication() throws JAXBException {
// list JAXB bean types to be used for REST serialization
types = new Class[] {
com.myapp.rest.MyBean1.class,
com.myapp.rest.MyBean2.class,
};
context = new JSONJAXBContext(JSONConfiguration.natural().build(), types);
}
@Override
public Set<Class<?>> getClasses() {
// list JAXB resource/provider/resolver classes
Set<Class<?>> classes = new HashSet<Class<?>>();
//for(Class<?> type : types)
// classes.add(type);
classes.add(MyBeansResource.class);
classes.add(this.getClass()); // used as a ContextResolver class
return classes;
}
@Override
public JAXBContext getContext(Class<?> objectType) {
// this is called each time when rest path was called by remote client
for (Class<?> type : types) {
if (type==objectType)
return context;
}
return null;
}
}
類MyBean1,MyBean2是普通的java對象,MyBeansResource類是具有@Path rest函數的類。 他們期待標准的jaxp @Annotations在這里和那里沒有什么特別之處。 在這個java術語JSON文件之后
我使用以下環境
jersey-archive.zip有較舊的asm-3.1.jar文件,可能工作正常但是chapter_deps.html鏈接到一個較新的文件。 請參閱頂部的鏈接列表。
編輯我發現了一個優秀的(快速,輕量級只有15KB)注釋發現工具。 請參閱這篇文章,了解我如何在運行時自動發現類型,並且每次添加新的java(jaxb)bean時都不再需要編輯RESTApplication。
我剛剛發現用Jersey返回一個原始類型是有問題的。 我已經決定返回String。 也許這不干凈,但我認為它太臟了。 Java客戶端大多數時間由服務器的同一作者編寫,可以包裝這樣的字符串返回值並將其轉換回int。 用其他語言編寫的客戶端必須以任何方式了解返回類型。
定義RestInteger,RestBoolean可能是另一種選擇,但它更麻煩,我覺得它的吸引力太小了。
或許我在這里錯過了一些重要的東西?
實際上,最好的辦法是編寫一個自定義的ContextResolver Provider,如下所示,使用JSON的自然構建。
@Provider
public class YourContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext context;
private Class<?>[] types = { YourSpecialBean.class };
public YourContextResolver() throws Exception {
this.context = new JSONJAXBContext(
JSONConfiguration.natural().build(), types);
}
public JAXBContext getContext(Class<?> objectType) {
for (int i = 0; i < this.types.length; i++)
if (this.types[i].equals(objectType)) return context;
return null;
}
}
這里唯一需要注意的是Class []中的YourSpecialBean.class。 這定義了此提供程序將自然解析的類類型數組。
我今天遇到了同樣的問題,直到找到一個非常合適的解決方案才放棄。 我無法從1.1.5更新澤西圖書館它是一個遺留系統。 我的休息服務返回一個列表,他們應該遵循這些規則。
從容易到不可能開始。
3)今天沒有什么正常的JSON映射
2)注冊JAXBContextResolver,如下所示
@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
private final JAXBContext context;
private final Set<Class<?>> types;
private Class<?>[] ctypes = { Pojo.class }; //your pojo class
public JAXBContextResolver() throws Exception {
this.types = new HashSet<Class<?>>(Arrays.asList(ctypes));
this.context = new JSONJAXBContext(JSONConfiguration.mapped()
.rootUnwrapping(true)
.arrays("propertyName") //that should rendered as JSONArray even if the List only contain one element but doesn't handle the empty Collection case
.build()
, ctypes);
}
@Override
public JAXBContext getContext(Class<?> objectType) {
return (types.contains(objectType)) ? context : null;
}
}
1)以下方法僅適用於Collections $ EmptyList類。 您是否可以找到一種方法,使其對所有集合都是空的。 可能代碼處理EmptyList所以。
@Provider
@Produces(value={MediaType.APPLICATION_JSON})
public class EmptyListWriter implements MessageBodyWriter<AbstractList> {
private static final String EMPTY_JSON_ARRAY = "[]";
@Override
public long getSize(AbstractList list, Class<?> clazz, Type type, Annotation[] annotations, MediaType mediaType) {
return EMPTY_JSON_ARRAY.length();
}
@Override
public boolean isWriteable(Class<?> clazz, Type type, Annotation[] annotations, MediaType mediaType) {
return clazz.getName().equals("java.util.Collections$EmptyList");
}
@Override
public void writeTo(AbstractList list, Class<?> clazz, Type type, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> headers, OutputStream outputStream) throws IOException, WebApplicationException {
if (list.isEmpty())
outputStream.write(EMPTY_JSON_ARRAY.getBytes());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.