web-dev-qa-db-ja.com

GenericEntity <List <T >>を介してRESTful ResponseオブジェクトでJava-genericsテンプレートタイプを使用する

汎用のJAX-RSリソースクラスがあり、汎用のfindAllメソッドを定義しました

_public abstract class GenericDataResource<T extends GenericModel> {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response findAll() {
        Query query = em.createNamedQuery(modelClass.getSimpleName()+".findAll");
        List<T> list = query.getResultList();
        return Response.ok(new GenericEntity<List<T>>(list) {}).build();
    }
}
_

およびユーザークラス:

_public class User extends GenericModel {
    ...
}
_

そして、ここにサブクラス定義の例があります:

_@Path("users")
public class UserResource extends GenericDataResource<User> {

    public UserResource() {
        super(User.class);
    }
}
_

私は例外を下回ります:

_com.Sun.jersey.api.MessageException: A message body writer for Java class 
Java.util.Vector, and Java type Java.util.List<T>, 
and MIME media type application/json was not found exception.
_

TをUserなどの定義済みクラスに置き換えると、次のようになります。

GenericEntity<List<User>>(list)

その後、正常に動作します。

ジェネリックTでどのように機能させるかについてのアイデアはありますか?

14
Emin

ソースコードがコンパイルされると、次の行で作成される(匿名)クラス:

new GenericEntity<List<T>>(list) {}

型変数を使用して、その親を参照します。型変数は実行時に値を持たないため、このようなジェネリックを使用することはできません。呼び出し側サイトからいわゆるタイプトークンを渡す必要があります。これは、findAll()の呼び出し元からトークンを渡す必要がある例ですが、コンストラクターでトークンを要求し、インスタンス変数に保存することもできます。

public abstract class GenericDataResource<T extends GenericModel> {
  public Response findAll(GenericEntity<List<T>> token) {
    Query query = em.createNamedQuery(modelClass.getSimpleName() + ".findAll");
    List<T> list = query.getResultList();
    return Response.ok(token).build();
  }
}

発信者は次のようなトークンを送信します

new GenericEntity<List<User>>() {}

パラメータ化されていないサブクラスのみを使用する場合、findAll()はリフレクションを利用してトークンを作成する場合があります(テストされていません。

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response findAll() {
  Query query = em.createNamedQuery(modelClass.getSimpleName()+".findAll");
  List<T> list = query.getResultList();
  return Response.ok(new GenericEntity(list, getType())).build();
}

目的の型を返すには、getType()を実装する必要があります。 ParameterizedType のサブクラスになり、タイプList<DAO<User>>を示すことができます

11
Raffaele

回答に加えて、クライアントでResponseオブジェクトを読み取るには:

List<MyObject> list = response.readEntity(new GenericType<List<MyObject>>(){}));
9
jediz

Responseサーバーに送信されたリクエストに応答してオブジェクトがクライアントに返されます。 Responseクラスには、Response.ResponseBuilderタイプのフィールドに設定された各プロパティを収集するResponse.ResponseBuilder内部クラスがあります。 Response.ResponseBuilderは、Builderデザインパターンを適用してResponseオブジェクトを構築します。

Build()メソッドは、ビルド中に形成されたResponse.ResponseBuilderオブジェクトのチェーンを接続する役割を果たします。例えば。

Response.status(200);   

statusメソッドは、STATUSの割り当て後にResponse.ResponseBuilderを返します

 Response.status(200).entity( AnyObj );

エンティティオブジェクトは、Response.ResponseBuilder型のエンティティ(返されるペイロード)を割り当て、レスポンスの変数のインスタンスに割り当てられます。その後、statusはステータスを割り当て、Response.ResponseBuilderインスタンスを返します。ビルダーは、build()メソッドの呼び出し時にそれらを接続します。

Response.status(200).entity( obj ).build(); 

最後に、buildメソッドは完全な(プロパティが設定された)応答を構築します。

ここで、GenericEntityオブジェクトの問題が発生します。ジェネリック型Tの応答エンティティを表します。

例えば、

GenericEntity> obj = new GenericEntity>(lst){}; Response.status(200).entity(obj).build();

objは、上記のリストのタイプです。エンティティメソッドは、汎用的なObject typeを受け入れます。特定のタイプの必要が生じた場合、それをGenericEntityタイプの引数として渡して、実行時に特定のタイプのオブジェクトにキャストされるようにする必要があります。

実用

私のジャージーフレームワークに、配列オブジェクトのリストオブジェクトであるJSON Javaモデルの応答オブジェクトの一部としてクライアントに返すように応答させたい。

したがって、新しいGenericEntity> ---オブジェクト/ペイロードをListタイプにキャストしますnew GenericEntity ---ランタイムタイプはStringになります


Webサービス側のリソース

public Response findAllFruits(@QueryParam("frtID") String frtID ) {

         List<String> lst = new ArrayList<String>();
         lst.add("Banana");
         lst.add("Apple");

         GenericEntity<List<String>> obj = new GenericEntity<List<String>>(lst) {};


          return Response.status(200).entity( obj ).build(); 

    } 

出力応答がクライアントに返送されました。 [「バナナ」、「アップル」]


応答エンティティの読み方

List<CustomType> myObj= response.readEntity(new GenericType<List<CustomType>>() {});
2
Yergalem

それを解決するために、GenericEntityを返すメソッドを作成してから、ジェネリッククラスから呼び出します。

@XmlRootElement
public abstract class AbstractRest<T extends IEntity> {

    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}


public abstract class SmartWebServiceNEW<R extends AbstractRest<T>> {

    @GET
    @Produces({MediaType.APPLICATION_XML})
    public Response findAll() {
        List<T> lista = getDelegate().findAll();
        if (lista == null || lista.isEmpty()) {
            return Response.status(Response.Status.NO_CONTENT).build();
        }
        List<R> retorno = new ArrayList<R>();
        for (T it : lista) {
            retorno.add(toRest(it));
        }
        GenericEntity entity = listToGenericEntity(retorno);
        return Response.ok(entity).build();
    }

    protected abstract GenericEntity listToGenericEntity(List<R> restList);   
}

@Path("/something")
@RequestScoped
public class MyEntityResource extends SmartWebServiceNEW<MyEntityExtendingAbstractRest> {

 @Override
    protected GenericEntity listToGenericEntity(List<MyEntityExtendingAbstractRest> restList) {
        return new GenericEntity<List<MyEntityExtendingAbstractRest>>(restList) {
        };
    }

}
1
cristianchiess