4

Javaで次のことを正しく行うには? オブジェクトのリストを作成できる汎用ルーチンが必要です。このルーチンでは、これらのオブジェクトのクラスのコンストラクターが特定のパラメーターをサポートすることを期待しています。

List<T>明確にするために: このルーチンで JSON 文字列からを作成したいと思います。これは、より大きな逆シリアル化コードの一部です。サポートされているそれぞれが、指定された を作成するTコンストラクターを実装することをどうにかして指定できれば、ルーチンを次のように書くことができます。TJSONObject

interface CreatableFromJSONObject<T> {
    T(JSONObject object);     // Complains about missing return type.
} 

static <T> List<T extends CreatableFromJSONObject> jsonArrayToList(JSONArray array) {
    List<T> result = new ArrayList<T>();
    for (int i = 0; i < array.length; ++i) {
         JSONObject jsonObject = array.getJSONObject(i);
         result.add(T(jsonObject));    // If T has one constructor with 1 one argument JSONObject
    }
    return result;
}

次に、このインターフェイスを実装するサンプル クラスを使用します。

class SomeClass implements CreatableFromJSONObject {
    SomeClass(JSONObject object) throws JSONException {
        // implementation here
    }
}

目的の方法を次のように使用できます。

List<SomeClass> list = jsonArrayToList<SomeClass>(someJSONArray);

現在、StackOverflow でこれに関するヒットがかなりあります。Javaはインターフェイスで特定のコンストラクターの指定をサポートしておらず、静的メソッド(代替ルートとなる)もサポートしていないため、上記で概説したことは不可能であることがわかりました。同じ理由で不可能です)。

では、これを達成する最善の方法は何でしょうか?

私の現在の最善の試みは次のとおりです。

public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Constructor<T> fromJSONObjectConstructor) {
    List<T> result = new ArrayList<T>();
    try {
        for (int i = 0; i < jsonArray.length(); i++) {
            result.add(fromJSONObjectConstructor.newInstance(jsonArray.getJSONObject(i)));
        }
    } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
    } catch (InstantiationException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
    return result;
}

次に、このメソッドでサポートする必要がある各クラスに追加します。

public class SomeClass {
    public static final Constructor<SomeClass> jsonObjectConstructor;
    static {
        try {
            jsonObjectConstructor = CafellowEntity.class.getConstructor(JSONObject.class);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    SomeClass(JSONObject object) throws JSONException {
        // Implementation here
    }
}

私が使用するもの

List<SomeClass> list = jsonArrayToList(myJSONArray, SomeClass.jsonObjectConstructor);

これは、一般的な実装をまったく使用せず、特定の目的のために必要な場所にルーチンで実際に作業を行っている (この場合) 数行のコードを配置することを除いて、私が思いつくことができる最もきれいなソリューションです。クラス。

助言がありますか?このソリューションと代替ソリューションのパフォーマンスはどうですか? このJavaのようにサポートしないことで、おそらくこれをしたくないと言っているのでしょうが、とにかくそれについて疑問に思うことを妨げるものではありません.

4

2 に答える 2

4

ある種の異常なデシリアライゼーションを行っていない限り、この設計は非常に複雑でエラーが発生しやすいものです。Android には、すでにこれを実行できる優れた JSON パーサーがバンドルされており、うまく実行できます。現在カスタム コンストラクターを定義している各型は、1 行のコードで逆シリアル化できます。

final CustomObj obj = new Gson().fromJson(jsonObj.toString(), CustomObj.class);

これを既存のメソッドに組み込むと、次のようになります。

public static <T> List<T> jsonArrayToList(final JSONArray jsonArray,
        Class<T> clazz) {
    if (jsonArray == null || clazz == null)
        return null;

    final Gson gson = new Gson();
    List<T> result = new ArrayList<T>(jsonArray.length());
    for (int i = 0; i < jsonArray.length(); i++) {
        try {
            result.add(gson.fromJson(jsonArray.getJSONObject(i).toString(),
                    clazz));
        } catch (final JSONException je) {
            je.printStackTrace();
            return null;
        }
    }

    return result;
}
于 2013-02-25T22:28:51.390 に答える
0

コンストラクター インスタンスを省略し、代わりに clazz インスタンスを使用することで、ソリューションを簡素化できます。したがって、の署名は次のjsonArrayToList()ようになります。

public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Class<T> clazz); 

次に、コンストラクターを呼び出しますclazz.newInstance();

これは、クラスのタイプが事前にわかっている場合に機能します。

于 2013-02-25T22:28:19.943 に答える