2012-06-01 29 views
13

Tôi đang sử dụng Jersey để triển khai các dịch vụ kiểu REST JAX-RS cùng với Jackson 2.0.2 cho ánh xạ JSON. Một trong những dịch vụ REST trả về một List<EntityA> (chúng ta hãy gọi nó indexA), nơi EntityA chứa List<EntityB> khác trong khi dịch vụ khác chỉ trả về một List<EntityB> (chúng ta hãy gọi nó indexB):Áp dụng bộ lọc Jackson khác nhau cho các cuộc gọi dịch vụ Jersey REST khác nhau

@Entity 
@JsonAutoDetect 
public class EntityA { 
    @Id 
    private String id; 

    @OneToMany 
    private List<EntityB> b; 

    ... 
} 

@Entity 
@JsonAutoDetect 
@JsonFilter("bFilter") 
public class EntityB { 
    @Id 
    private String id; 

    private String some; 
    private String other; 
    private String attributes; 

    ... 
} 

@Path("/a") 
public class AResource { 

    @GET 
    @Path("/") 
    public List<EntityA> indexA() { 
    ... 
    } 
} 

@Path("/b") 
public class BResource { 

    @GET 
    @Path("/") 
    public List<EntityB> indexB() { 
    ... 
    } 
} 

Những gì tôi muốn đạt được là để áp dụng một bộ lọc Jackson đến lời gọi indexA để không phải tất cả các thuộc tính của phần tử con EntityB đều được tuần tự hóa. OTOH, indexB phải trả lại EntityB về tính đầy đủ của nó.

Tôi biết về sự tồn tại của ContextResolver<ObjectMapper> mà tôi đã sử dụng cho các mục đích khác. Thật không may, đối với ContextResolver, có vẻ như không thể phân biệt cả hai yêu cầu dịch vụ vì số Class được cung cấp cho ContextResolver.getContext(Class)ArrayList trong cả hai trường hợp (và nhờ xóa, tôi không thể tìm ra các tham số kiểu chung).

Có móc nào phù hợp hơn khi định cấu hình ObjectMapper/FilterProvider tùy thuộc vào loại đối tượng đang được ánh xạ không?

Tôi có thể sử dụng cách tiếp cận được đề xuất trong How to return a partial JSON response using Java?: Ánh xạ theo cách thủ công đến String, nhưng sẽ giết toàn bộ vẻ đẹp của phương pháp dựa trên chú thích khai báo, vì vậy tôi muốn tránh điều này.

Trả lời

27

Tôi đã ở trong tình trạng tương tự, sau hàng tấn nghiên cứu, tôi đã tìm ra giải pháp là sử dụng @JsonView và Spring có thể đưa ObjectMapper vào Writer JSON mà không làm mất vẻ đẹp của Jersey.

Tôi đang làm việc trên một tập hợp các API REST, tôi muốn nhận danh sách các trường hợp SystemObject và chi tiết một cá thể cụ thể của SystemObject, giống như bạn tôi chỉ muốn giới hạn số lượng thuộc tính của từng cá thể trong danh sách và một số thuộc tính bổ sung trong chi tiết, tôi chỉ xác định Chế độ xem cho chúng và thêm chú thích trong lớp SystemObject. nhưng theo mặc định, tất cả các thuộc tính không có chú thích @JsonView sẽ được xuất ra JSON, nhưng có cấu hình item(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION) Tôi có thể sử dụng để loại trừ chúng.

Vấn đề là tôi phải đặt nó thành đúng để đáp ứng nhu cầu của mình. nhưng tôi không thể thay đổi ObjectMapper có phép chuyển đổi đối tượng thành JSON, bằng cách đọc 3 bài viết dưới đây, tôi có ý tưởng rằng cách duy nhất tôi có thể làm là tiêm ObjectMapper đã sửa đổi thành Jersey. Bây giờ tôi đã nhận được những gì tôi muốn.

Giống như bạn tạo nhiều chế độ xem dựa vào bảng cơ sở dữ liệu.

Những 3 liên kết này sẽ giúp bạn theo những cách khác nhau:

How to create a ObjectMapperProvider which can be used by Spring to inject

Jersey, Jackson, Spring and JSON

Jersey + Spring integration example

REST của tài nguyên:

package com.john.rest.resource; 

import java.util.ArrayList; 
import java.util.List; 

import javax.ws.rs.GET; 
import javax.ws.rs.HeaderParam; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.Context; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Request; 
import javax.ws.rs.core.UriInfo; 

import org.codehaus.jackson.map.annotate.JsonView; 
import org.springframework.stereotype.Component; 

import com.midtronics.esp.common.EspException; 
import com.midtronics.esp.common.SystemObject; 
import com.midtronics.esp.mobile.model.SystemObjectView; 
import com.midtronics.esp.model.accesscontrol.AccessControlBean; 
import com.midtronics.esp.model.site.SiteBean; 

@Component 
@Path("/hierarchy") 
public class Hierarchy { 

    // Allows to insert contextual objects into the class, 
    // e.g. ServletContext, Request, Response, UriInfo 
    @Context 
    UriInfo uriInfo; 

    @Context 
    Request request; 

    // Return the list of sites 
    @GET 
    @Path("sites") 
    @Produces(MediaType.APPLICATION_JSON) 
    @JsonView({SystemObjectView.ObjectList.class}) 
    public List<SystemObject> listSite(
      @HeaderParam("userId") String userId, 
      @HeaderParam("password") String password) { 
     ArrayList<SystemObject> sites= new ArrayList<SystemObject>(); 

     try{ 
      if(!AccessControlBean.CheckUser(userId, password)){ 
       throw new WebApplicationException(401); 
      } 
      SystemObject.GetSiteListByPage(sites, 2, 3); 

      return sites; 
     } catch(EspException e){ 
      throw new WebApplicationException(401); 
     } catch (Exception e) { 
      throw new WebApplicationException(500); 
     } 
    } 

    // Return the number of sites 
    @GET 
    @Path("sites/total") 
    @Produces(MediaType.TEXT_PLAIN) 
    public String getSiteNumber(@HeaderParam("userId") String userId, 
      @HeaderParam("password") String password) { 
     try{ 
      return Integer.toString(SiteBean.GetSiteTotal()); 
     } catch(EspException e){ 
      throw new WebApplicationException(401); 
     } catch (Exception e) { 
      throw new WebApplicationException(500); 
     } 
    } 

} 

mô hình REST:

package com.john.rest.model; 

import java.io.Serializable; 
import java.util.ArrayList; 

import javax.xml.bind.annotation.XmlRootElement; 

import org.codehaus.jackson.annotate.JsonIgnore; 
import org.codehaus.jackson.annotate.JsonProperty; 
import org.codehaus.jackson.map.annotate.JsonView; 

import com.midtronics.esp.mobile.model.SystemObjectView; 
import com.midtronics.esp.model.common.ICommonDAO; 

@XmlRootElement 
public class SystemObject implements Serializable 
{ 
    private static final long serialVersionUID = 3989499187492868996L; 

    @JsonProperty("id") 
    @JsonView({SystemObjectView.ObjectList.class, SystemObjectView.ObjectDetail.class}) 
    protected String objectID = ""; 

    @JsonProperty("parentId") 
    protected String parentID = ""; 

    @JsonProperty("name") 
    @JsonView({SystemObjectView.ObjectList.class, SystemObjectView.ObjectDetail.class}) 
    protected String objectName = ""; 

    //getters... 
    //setters... 

} 

REST của xem mô hình:

package com.john.rest.model; 

public class SystemObjectView { 
    public static class ObjectList { }; 

    public static class ObjectDetail extends ObjectList { } 
} 
+3

Nếu tôi lên có thể bỏ phiếu này 20 lần tôi sẽ. Cho đến khi tôi đọc điều này, tôi không biết bạn có thể áp dụng JsonView cho phương thức tài nguyên Jersey để chọn chế độ xem để tuần tự hóa. Nếu điều đó được mô tả trong tài liệu tôi đã bỏ lỡ nó hoàn toàn. BTW - hoạt động mà không có mùa xuân (tôi đang sử dụng Felix). Cảm ơn nhiều! – sfitts

+0

Tôi không nghĩ rằng bạn đã bỏ lỡ điều này trong tài liệu. Tôi đã tìm kiếm một cách tốt để làm điều này trong một thời gian dài, và không bao giờ tìm thấy một cho đến khi tôi thấy bài đăng này. –

+0

Nhờ được báo cáo, dự án README hiện bao gồm mô tả ngắn gọn các chú thích có thể áp dụng cho các điểm cuối JAX-RS - https://github.com/FasterXML/jackson-jaxrs-providers - và hy vọng các vùng chứa khác (Spring, Restlet) có/thêm một cái gì đó tương tự. – StaxMan

Các vấn đề liên quan