2012-10-26 141 views
1

我有以下問題。java jackson解析包含泛型類型對象的對象

我必須解析一個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); 
    } 

} 

回答

5

我同意eugen的答案,但只是想擴大一點。第一步是重構你的分析方法,所以它需要第二個參數。您不需要在方法中分配類型引用,而需要調用者傳入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>也應該工作,但我加倍檢查了一個項目,我使用傑克遜反序列化集合。基類集合絕對有效,所以我堅持這一點。

+0

好吧,我開始得到這個..我做了這個工作使用一個單一的對象,但我無法做它的列表。你能提供更多的信息嗎?感謝您迄今爲止的努力。 – DArkO

+0

查看更新 - 嘗試使用更一般的Collection類。 –

+0

好吧,我已經做到了。與此類似,但你證明了一點。非常感謝。唯一我討厭的是我必須發送.class,並且定義泛型參數,並且最終得到類似於新分析器(AlbumModel.class) – DArkO

0

由於您使用傑克遜,你可能需要創建一個自定義JsonDeserializer或JsonSerializer這取決於你交給的響應或請求。我已經用日期完成了這個,因爲在我的回覆中我想要一個標準視圖。我不是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; 
} 
2

你的T型將被「清除」在運行時,這樣做傑克遜不知道T的真實類型是什麼,並將其反序列化爲一個Map。您的解析方法需要第二個參數:Class<T> clazzTypeReference<T>java.lang.reflect.Type

編輯

上TypeReference的魔法小的解釋。當您執行新的XX(){}時,您正在創建一個匿名類,因此如果它是帶有類型變量(如果您願意,則進行參數化)的類,則新的X<List<Y>>() {},將能夠在運行時檢索List<Y>作爲java類型。這是非常相似,如果你已經完成:

abstract class MyGenericClass<T> {} 
class MySpecializedClass extends MyGenericClass<List<Y>> {} 
+0

它的工作原理,非常感謝你 –