7

私の質問は Java ジェネリックに関するものですが、JPA 関連のコードをいくつか入れて、実際のコンテキストを示します。

JPA 2.0 と Criteria API ベースのクエリを使用しています。すべてのクエリは同じパターンに従っています (単純な属性を比較します。パス ナビゲーションは必要ありません)。そのため、ビジネス ロジックを個別のクラスに保持しながら、JPA を処理するジェネリック クラスを作成しようとしています。私の目標は、エンティティ型と、基準を定義するペア (フィールド名 -> 目的の値) を格納するマップを指定して、いくつかのエンティティ フィールドの値を持つ Bean (または Bean のコレクション) を返すメソッドを持つことです。 .

すべてのエンティティがPersistibleインターフェイスを実装し、転送オブジェクトはすべて から継承しQueryBeanます。これらのクラスは問題に関係がないと考えているため、コードをスキップしています。

次のコードは、私の最初のアプローチのスニペットです (cb が有効な CriteriaBuilder インスタンスであると仮定してください)。

protected <T extends QueryBean, TT extends Persistible> Collection<T> executeQueryEntity
        (Class<T> type, Class<TT> rootType, QueryConfig queryConfig, Map<String, Object> parameters) {
    // (...) Initialization goes here

    CriteriaQuery<T> c = cb.createQuery(type);

    // FROM CLAUSE
    Root<TT> root = c.from(rootType);

    // SELECT CLAUSE
    List<String> constructorParams = queryConfig.getTargetAttributes();
    Selection<?>[] selectArray = new Selection<?>[constructorParams.size()];
    for (int i = 0; i < constructorParams.size(); i++) {
        selectArray[i] = root.get(constructorParams.get(i));
    }
    c.select(cb.construct(type, selectArray));

    // WHERE CLAUSE
    for (String filter : parameters.keySet()) {
        if (queryConfig.getFieldConfiguration().get(filter).compareUsingEquals()) {
            // SOME PREDICATE
        }
        else {
            // SOME OTHER PREDICATE
        }
    }

    // (...) Rest of the code goes here
}

私の QueryConfig インターフェイスは次のとおりです。

public interface QueryConfig {

List<String> getTargetAttributes();
Map<String, FieldConfiguration> getFieldConfiguration();

}

クエリに関する情報 (QueryBean コンストラクターに必要なパラメーターやエンティティ フィールドに関する情報など) を提供するクラスを既に使用しているQueryConfigため、エンティティ型を次のように渡すのではなく、そのクラスから取得するとよいと考えました。クラス パラメータ。この質問から直接行うことはできないと推測するので、次の回避策を試しました。

次のように QueryConfig にメソッドを追加します。

Class< ? extends Persistible> getTargetEntity();

次のような中間メソッドを追加します。

public <T extends QueryBean> Collection<T> queryMany(Class<T> type, QueryConfig config, Map<String, Object> parameters) {
    executeQueryEntity(type, config.getTargetEntity(), parameters);
}

しかし、それはコンパイルされません。理由はここで説明されていると思います:クラスジェネリックの型の不一致ですが、実際には答えがわかりませんでした。Class< TT >私の質問は:パラメータを execute メソッドに渡さないようにする方法はありますか? これは問題に対処する良い方法ですか、それとも全体をリファクタリングする必要がありますか? コードの改善も大歓迎です!

4

1 に答える 1

2

I don't quite get the reason why you think your approach will work: QueryConfig with Class< ? extends Persistible> getTargetEntity(); give no type information that can be referred by compiler, and why do you think the compiler can "guess" the type you are going to return, and do the type checking for you?

One way you can do is providing type information in QueryConfig

public interface QueryConfig <T extends Persistable> {
  Class<T> getTargetEntity();
  List<String> getTargetAttributes();
  Map<String, FieldConfiguration> getFieldConfiguration();
}

and your queryMany method can be like:

public <T extends QueryBean, TT extends Persistible> 
Collection<T> queryMany(Class<T> type, 
                        QueryConfig<TT> config, 
                        Map<String, Object> parameters) {
    executeQueryEntity(type, config.getTargetEntity(), parameters);
}
于 2013-04-24T04:18:55.507 に答える