2

次の問題があります。

ジェネリック型フィールドを含むオブジェクトに json リクエストを解析する必要があります。

編集

通常のクラス型を使用していくつかのテストを行いました (そのため、ジェネリックに置き換える前に動作させます)。単一の要素の解析がうまく機能するようになりました。

問題は、そのクラスからリスト オブジェクトを解析する必要がある場合です。

したがって、T が AlbumModel だけでなくリスト型であることをジャクソンに何らかの方法で通知する必要があります。

これが私が試したことです。

 @Override
    public ListResponseModel<AlbumModel> parse(String responseBody) throws Exception {
    JavaType type = mapper.getTypeFactory().constructParametricType(ResponseModel.class,
        AlbumModel.class);
    return mapper.readValue(responseBody,
        mapper.getTypeFactory().constructParametricType(ResponseModel.class, type));
    }

しかし、上記のコードは機能しません。このようなものの解決策は何ですか?

ListResponseModel の私のジェネリック型は次のように定義されています。List<T> data

次のように成功しました:

public class BaseResponseModel<T> {

    @JsonProperty("data")
    private T data;

    @JsonProperty("paginations")
    private PaginationModel pagination;
}

これまでのところ、次のコードがありますが、常にハッシュに解析されます。

public class ResponseParser extends BaseJacksonMapperResponseParser<ResponseModel<AlbumModel>> {

    public static final String TAG = ResponseParser.class.getSimpleName();

    @Override
    public ResponseModel<AlbumModel> parse(String responseBody) throws Exception {
        return mapper.readValue(responseBody,
                mapper.getTypeFactory().constructParametricType(ResponseModel.class, AlbumModel.class));
    }
}

public abstract class BaseJacksonMapperResponseParser<T> implements HttpResponseParser<T> {

    public static final String TAG = BaseJacksonMapperResponseParser.class.getSimpleName();

    public static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.disable(Feature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.enable(Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
    }

}
4

3 に答える 3

6

私はeugenの答えに同意しますが、それを少し拡張したかっただけです。最初のステップは、解析メソッドをリファクタリングして、2番目の引数を取るようにすることです。メソッドで型参照を割り当てる代わりに、呼び出し元にTypeReferenceインスタンスを渡す必要があります。

public BaseResponseModel<T> parse(String responseBody, TypeReference<T> ref) throws Exception {
    return mapper.readValue(responseBody, ref);
}

残念ながら、あなたのスニペットは解析を呼び出すコードを示していません-それで私は何かを作ります:

BaseResponseParser<Collection<Person>> parser = new BaseResponseParser<Collection<Person>>();
BaseResponseModel<Collection<Person>> result = parser.parse(jsonText, new TypeReference<Collection<Person>>(){});

この場合、TypeReferenceインスタンスをコンパイルすると、期待する実際の具象クラスへの型参照であることに注意してください。

実行時にクラスを渡すのと同じことを行うことができますが、TypeReferenceは、タイプTがジェネリックコレクションである場合でも機能するため、少し強力です。TypeReferenceの実装には、通常は消去される型情報を保持できる魔法があります。

[アップデート]

を使用するように更新されましたCollection<Person>。注-私が知る限り、動作するList<Whatever>はずですが、コレクションを逆シリアル化するためにjacksonを使用していたプロジェクトを再確認しました。基本クラスのコレクションは間違いなく機能したので、私はそれにとどまりました。

于 2012-10-26T15:29:40.973 に答える
2

タイプ T は実行時に「消去」されるため、Jackson は T の実際のタイプを認識せず、それを Map に逆シリアル化します。Class<T> clazzorTypeReference<T>またはになる parse メソッドの 2 番目のパラメーターが必要ですjava.lang.reflect.Type

編集

TypeReference の魔法に関する簡単な説明。new XX() {}を実行すると、匿名クラスが作成されるため、それが typevariables (必要に応じてパラメーター化された) を持つクラスである場合、 newは実行時に Java Type としてX<List<Y>>() {},取得できます。List<Y>あなたがしたかのように非常に似ています:

abstract class MyGenericClass<T> {}
class MySpecializedClass extends MyGenericClass<List<Y>> {}
于 2012-10-26T14:27:12.163 に答える
0

Jackson を使用しているため、応答または要求のどちらを処理しているかに応じて、おそらくカスタム JsonDeserializer または JsonSerializer を作成する必要があります。私の応答では標準ビューが必要なので、これを Dates で行いました。ただし、一般的なフィールドで機能することを100%確信しているわけではありません。これが私がやっていることの例です:

public class DateSerializer extends JsonSerializer<Date> {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZ");

    @Override
    public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        String dateString = dateFormat.format(value);
        jgen.writeString(dateString);
    }

}

次に、次のようにクラスに追加します。

@JsonSerialize(using = DateSerializer.class)
public Date getModifiedDate() {
    return modifiedDate;
}
于 2012-10-26T14:14:21.563 に答える