2012-06-01 16 views
13

ジャージーを使用してJSONマッピング用にジャクソン2.0.2とともにJAX-RS RESTスタイルのサービスを実装しています。私が達成したい何異なるジャージーRESTサービスコール用に異なるジャクソンフィルタを適用する

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

は適用することです。これらのRESTサービスの一つは、別のサービスがちょうど(のはindexBそれを呼びましょう)List<EntityB>を返すのに対し、EntityAは別のList<EntityB>が含まれているList<EntityA>を(のはindexAそれを呼びましょう)を返します子のEntityB要素のすべての属性がシリアライズされないように、indexA呼び出しに対するJacksonフィルター。 OTOH、indexBは、EntityBを完全に返す必要があります。

私は既に他の目的のために使用しているContextResolver<ObjectMapper>の存在を知っています。残念なことに、ContextResolverの場合、どちらのサービスでもContextResolver.getContext(Class)に提供されているClassArrayListであるため、両方のサービス呼び出しを区別することは不可能です(タイプ消去のおかげで、ジェネリックタイプのパラメータはわかりません)。

マッピングされているエンティティタイプに応じて、ObjectMapper/FilterProviderの設定に適したフックがありますか。

Stringに手動でマッピングするHow to return a partial JSON response using Java?で提案されているアプローチを使用できますが、これは宣言的アノテーションベースのアプローチの美しさを完全に打ち消してしまうので、これを避けてください。

答えて

27

同じ状況で、私はそれを理解しました。解決策は、@JsonViewとスプリングを使用して、ObjectMapperをジャーナルの美しさを殺すことなくJSON Writerに挿入できるようにすることです。

私はのインスタンスのリストとSystemObjectという特定のインスタンスの詳細を取得したいと思います。ちょうどあなたのように、私はちょうどあなたのように各インスタンスのプロパティの数をリスト内のいくつかの追加のプロパティと詳細については、私はそれらのビューを定義し、SystemObjectクラスのアノテーションを追加します。デフォルトでは、@JsonView注釈のないすべてのプロパティがJSONに出力されますが、除外に使用できる設定item(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION)があります。

問題は、自分の必要性を満たすためにはそれを真に設定しなければならないということです。オブジェクトをJSONに変換するObjectMapperを変更することはできません。以下の3つの記事を読んで、私ができる方法はModified ObjectMapperをJerseyに挿入することです。 今私は欲しいものを手に入れました。

データベーステーブルに対して複数のビューを作成するようです。

これらの3つのリンクは、さまざまな方法であなたを助ける:

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

Jersey, Jackson, Spring and JSON

Jersey + Spring integration example

RESTリソース:

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

} 

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モデルビュー:

package com.john.rest.model; 

public class SystemObjectView { 
    public static class ObjectList { }; 

    public static class ObjectDetail extends ObjectList { } 
} 
+3

私はこれを20回投票することができれば、私はだろう。この記事を読むまで、JerseyViewをJerseyリソースメソッドに適用して、シリアライズするビューを選択することはできませんでした。それがドキュメントに記述されていれば私は完全にそれを逃した。 BTW - Springなしで動作します(私はFelixを使用しています)。どうもありがとう! – sfitts

+0

私はあなたがドキュメントでこれを見逃したとは思わない。私は長い間これを行う良い方法を探していましたが、私はこの記事を見て初めて見つけました。 –

+0

JAX-RSエンドポイントに適用できる注釈の簡単な説明(https://github.com/FasterXML/jackson-jaxrs-providers)とうまくいけば他のコンテナ(Spring、Restlet) /類似のものを追加/追加する。 – StaxMan

関連する問題