2010-04-13 33 views
8

Trong ứng dụng của tôi, tôi sử dụng Jersey REST để tuần tự hóa các đối tượng phức tạp. Điều này hoạt động khá tốt. Nhưng có một vài phương pháp mà chỉ đơn giản là trả về một int hoặc boolean.Làm thế nào để tuần tự hóa các nguyên mẫu Java bằng cách sử dụng Jersey REST

Jersey không thể xử lý các loại nguyên thủy (theo kiến ​​thức của tôi), có thể do chúng không có chú thích và Jersey không có chú thích mặc định cho chúng. Tôi đã làm việc xung quanh điều đó bằng cách tạo các kiểu phức tạp như RestBoolean hoặc RestInteger, chỉ đơn giản là giữ một giá trị int hoặc boolean và có các chú thích thích hợp.

Không có cách nào dễ dàng hơn việc viết các đối tượng vùng chứa này?

+3

JAX-RS/Jersey không hỗ trợ serialization các loại nguyên thủy hoặc thậm chí các loại trình bao như Integer, Boolean vv AFAIK, cách tiếp cận bạn đã thực hiện là cách duy nhất. –

+0

OK, cảm ơn bạn! – Olvagor

Trả lời

3

Bạn đang viết dịch vụ hoặc khách hàng? Trong phần cuối của dịch vụ, bạn chỉ cần viết một MessageBodyWriter để tuần tự hóa luồng dữ liệu vào một đối tượng Java cho các loại của bạn. Trong các trường hợp sử dụng của tôi, các dịch vụ tôi đang viết đầu ra cho JSON hoặc XML, và trong trường hợp của XML, tôi chỉ cần ném một chú thích JAXB lên đầu các lớp của tôi và tôi đã hoàn thành.

Bạn đã xem hướng dẫn Người dùng Jersey về vấn đề này chưa?

3.6. Adding support for new representations

2

Trên thực tế đặt cược tốt nhất của bạn là viết một nhà cung cấp tùy chỉnh ContextResolver như sau đó sử dụng natural xây dựng 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; 
    } 
} 

Điều duy nhất đặc biệt ở đây cần lưu ý là lớp YourSpecialBean.class trong lớp []. Điều này định nghĩa một mảng các kiểu lớp mà nhà cung cấp này sẽ giải quyết một cách tự nhiên.

2

Nói Jersey tạo tài liệu JSON thích hợp (json tự nhiên). Tôi sử dụng cùng một lớp cho phần còn lại của ứng dụng và trình giải quyết JAXBContext, đã tìm thấy nó là gói gọn gàng nhất.

Trình lập trình tốt hơn có thể triển khai trình trợ giúp để lặp lại các tệp .class và liệt kê các lớp thích hợp một cách tự động bằng cách xác định thẻ @Annotation. Tôi không biết làm thế nào để làm nó chạy trong một mã nguồn riêng.

Hai liên kết này hữu ích khi nghiên cứu thêm biệt ngữ java này. Tôi không biết tại sao không có tham số Jersey để làm cho tất cả chỉ làm việc ra khỏi hộp.

WEB-INF/web.xml (đoạn):

<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; 
    } 
} 

Lớp MyBean1, MyBean2 là đồng bằng đối tượng java và lớp MyBeansResource là một với @Path chức năng còn lại. Không có gì đặc biệt trong họ mong đợi tiêu chuẩn jaxp @Annotations ở đây và ở đó.Sau khi thuật ngữ java này tài liệu JSON có

  • zero hoặc Danh sách phần tử đơn mảng luôn viết như mảng json ([] trường)
  • số nguyên nguyên thủy và các lĩnh vực boolean được viết như nguyên thủy json (không trích dẫn)

tôi sử dụng môi trường sau đây

  • Sun Java JDK1.6.x
  • Apache Tomcat 6.x
  • Thư viện Jersey v1.14 (jersey-archive-1.14.zip)
  • thư mục webapps/myapp/WEB-INF/lib có asm-3.3.1.jar, jackson-core-asl.jar, jersey-client .jar, jersey-core.jar, jersey-json.jar, jersey-server.jar, thư viện jersey-servlet.jar
  • thêm tùy chọn chú thích-detector.jar nếu bạn sử dụng infomas-asl công cụ khám phá

jersey-archive.zip có tệp asm-3.1.jar cũ hơn, có thể hoạt động tốt nhưng chapter_deps.html liên kết đến một tệp mới hơn. Xem danh sách liên kết ở trên cùng.

Chỉnh sửa Tôi đã tìm thấy công cụ khám phá chú thích xuất sắc (nhanh, nhẹ chỉ 15KB). Xem bài viết này về cách tôi tự động phát hiện các kiểu trong thời gian chạy và không còn cần chỉnh sửa RESTApplication mỗi lần thêm hạt java (jaxb) mới.

https://github.com/rmuller/infomas-asl/issues/7

4

Có một cái nhìn tại Genson Nó đã giúp tôi rất nhiều với một tương tự problem.With Genson bạn có thể sử dụng Generics như int, boolean, danh sách và vân vân ... Dưới đây là một ví dụ nhanh.

@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(); 
} 

này sẽ tạo ra một phù thủy JSON hợp lệ có thể được lấy ra rất đơn giản như thế này:

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()); 
    } 

Bạn sẽ thấy rằng Genson sẽ giúp bạn giải mã các JSON trên các mặt hàng cũng và đầu ra lớp đúng cho mỗi.

+0

Liên kết html đúng với dự án Genson là http://code.google.com/p/genson/ – Whome

2

Tôi vừa phát hiện ra rằng việc trả về kiểu nguyên thủy với Jersey là vấn đề. Tôi đã quyết định trả lại String. Có lẽ điều này không sạch sẽ, nhưng tôi không nghĩ nó quá bẩn thỉu. Máy khách Java, được viết bởi cùng một tác giả của máy chủ hầu hết các lần, có thể bọc một giá trị trả về chuỗi như vậy và chuyển nó trở lại thành int. Khách hàng được viết bằng các ngôn ngữ khác phải biết về các loại trả lại theo bất kỳ cách nào.

Xác định RestInteger, RestBoolean có thể là một tùy chọn khác, tuy nhiên nó cồng kềnh hơn và tôi thấy quá ít lợi thế trong đó là hấp dẫn.

Hoặc có thể tôi thiếu điều gì đó quan trọng ở đây?

+1

điều này chắc chắn không nên quá cồng kềnh và được bao gồm trong lớp jersey theo ý kiến ​​của tôi. Tôi đã đưa ra kết luận tương tự vào Chủ nhật lúc 10 giờ tối, tôi sẽ đối phó với chuỗi ha darn. – JesseBoyd

2

Tôi đã có cùng một vấn đề ngày hôm nay và không bỏ cuộc cho đến khi tôi tìm thấy một giải pháp phù hợp thực sự tốt. Tôi không thể cập nhật thư viện áo từ 1.1.5 nó là một Legacy System. My Rest Service trả về một Danh sách và họ phải tuân theo các quy tắc đó.

  1. Lists rỗng được trả lại như [] (hầu như không thể) Lists
  2. Một phần tử được trả lại như [] (khó khăn nhưng chỉ cấu hình bản đồ)
  3. Nhiều Lists phần tử được trả lại như [] (dễ)

Bắt đầu từ dễ đến không thể.

3) không có gì hiện nay bình thường JSON Mapping

2) Đăng ký JAXBContextResolver như

@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) Các phương pháp sau đây sau đây chỉ hoạt động cho lớp Collections $ EmptyList. Bạn có thể tìm cách làm cho nó chung cho tất cả các Bộ sưu tập chúng trống không. Có thể mã đối phó với EmptyList như vậy.

@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());    
    } 
} 
Các vấn đề liên quan