2012-07-25 33 views
11

我曾經錯誤地發佈過這個問題。我正在這裏發佈的問題正確...Jackson - Deserialize通用類變量

我得到一個json字符串作爲HTTP響應。我知道它的結構。它如下:

public class Json<T> { 
    public Hits<T> hits; 
} 
public class Hits<T> { 
    public int found; 
    public int start; 
    public ArrayList<Hit<T>> hit; 
} 
public class Hit<T> { 
    public String id; 
    public Class<T> data; 
} 

「data」字段可以屬於任何類別。我只會在運行時才知道它。我將把它作爲參數。這就是我的反序列化。

public <T> void deSerialize(Class<T> clazz) { 
    ObjectMapper mapper = new ObjectMapper(); 
    mapper.readValue(jsonString, new TypeReference<Json<T>>() {}); 
} 

但我得到一個錯誤 -

不能從java.lang.Class中訪問私有java.lang.class.Class()。無法設置訪問權限。不能使java.lang.Class構造函數可訪問

+0

爲什麼複製該問題(請參閱http://stackoverflow.com/questions/11664894/jackson-deserialize-using-generic-class/11681540)? – StaxMan 2012-07-27 19:25:20

+0

請參閱http://stackoverflow.com/questions/17400850/is-jackson-really-unable-to-deserialize-json-into-a-generic-type – lisak 2013-07-01 12:51:48

回答

1

您是序列化和反序列化Class對象爲JSON嗎?也許在Hit中保持它爲String並創建額外的啓動Class.forName的getter,例如

public class Hit { 
    public String id; 
    public String data; 
    public Class<?> getDataClass() throws Exception { 
     return Class.forName(data); 
    } 
} 
+0

我已經完全編輯了這個問題,你能否回答它? – gnjago 2012-07-27 05:40:30

+1

你得到的錯誤說:「我想instatinate新的類對象,但我不能執行'新的類()',因爲構造函數是私人的」。更何況這是沒有意義的。請添加一個JSON字符串示例。那麼提出解決方案會容易得多。我很確定類型Class的序列化/反序列化屬性是一個錯誤的路徑。 – 2012-07-27 10:33:02

0

反序列化泛型類變量

...

我怎麼告訴它傑克遜? gson會做得更好嗎?

The Gson user guide includes a section正是我所瞭解的你正試圖完成的事情,儘管這個記錄的例子可能仍然不完整。

In a blog post, I covered in more detail the solution using Gson 1.7.1.下面是相關的代碼示例。

使用Jackson(1.8.2)的類似(但更多參與)解決方案也在同一博客文章中進行了演示和描述。 (不同的方法和示例使用幾百行代碼的,所以我他們在這裏省略了重新發布。)

public class GsonInstanceCreatorForParameterizedTypeDemo 
{ 
public static void main(String[] args) 
{ 
    Id<String> id1 = new Id<String>(String.class, 42); 

    Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, 
    new IdInstanceCreator()).create(); 
    String json1 = gson.toJson(id1); 
    System.out.println(json1); 
    // actual output: {"classOfId":{},"value":42} 
    // This contradicts what the Gson docs say happens. 
    // With custom serialization, as described in a 
    // previous Gson user guide section, 
    // intended output may be 
    // {"value":42} 

    // input: {"value":42} 
    String json2 = "{\"value\":42}"; 

    Type idOfStringType=new TypeToken<Id<String>>(){}.getType(); 
    Id<String> id1Copy = gson.fromJson(json2, idOfStringType); 
    System.out.println(id1Copy); 
    // output: classOfId=class java.lang.String, value=42 

    Type idOfGsonType = new TypeToken<Id<Gson>>() {}.getType(); 
    Id<Gson> idOfGson = gson.fromJson(json2, idOfGsonType); 
    System.out.println(idOfGson); 
    // output: classOfId=class com.google.gson.Gson, value=42 
} 
} 

class Id<T> 
{ 
private final Class<T> classOfId; 
private final long value; 

public Id(Class<T> classOfId, long value) 
{ 
    this.classOfId = classOfId; 
    this.value = value; 
} 

@Override 
public String toString() 
{ 
    return "classOfId=" + classOfId + ", value=" + value; 
} 
} 

class IdInstanceCreator implements InstanceCreator<Id<?>> 
{ 
@SuppressWarnings({ "unchecked", "rawtypes" }) 
public Id<?> createInstance(Type type) 
{ 
    Type[] typeParameters = 
    ((ParameterizedType) type).getActualTypeArguments(); 
    Type idType = typeParameters[0]; 
    return new Id((Class<?>) idType, 0L); 
} 
} 
10

您將需要建立JavaType明確,如果泛型類型只有動態可用:

// do NOT create new ObjectMapper per each request! 
final ObjectMapper mapper = new ObjectMapper(); 

public Json<T> void deSerialize(Class<T> clazz, InputStream json) { 
    return mapper.readValue(json, 
     mapper.getTypeFactory().constructParametricType(Json.class, clazz)); 
} 
+0

這不符合我的經驗,它可能是一個錯誤,雖然:https://github.com/FasterXML/jackson-databind/issues/254 – lisak 2013-07-01 08:03:48

+0

引用的錯誤還有其他問題 - 通用類型解析如圖所示以上將起作用,但不涉及其他可能的問題。 – StaxMan 2013-07-02 18:07:37

+0

是的,我的歉意,它已在這裏解決http://stackoverflow.com/questions/17400850/is-jackson-really-unable-to-deserialize-json-into-a-generic-type – lisak 2013-07-02 21:23:18

2

樣品一般反序列化接口:

public interface Deserializable<T> { 
    static final ObjectMapper mapper = new ObjectMapper(); 

    @SuppressWarnings("unchecked") 
    default T deserialize(String rawJson) throws IOException { 
     return mapper.readValue(rawJson, (Class<T>) this.getClass()); 
    } 
} 
0
需要被反序列化必須包含有關PARAMET類型的信息

JSON字符串呃T
您必須將Jackson註釋放在每個可作爲參數T傳遞到類Json的類上,以便Jackson可以從JSON字符串讀取/寫入關於參數類型T的類型信息。

讓我們假設T可以是任何擴展抽象類Result的類。

public class Json<T extends Result> { 
    public Hits<T> hits; 
} 

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 
@JsonSubTypes({ 
     @JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"), 
     @JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")}) 
public abstract class Result { 

} 

public class ImageResult extends Result { 

} 

public class NewsResult extends Result { 

} 

一旦每個可以作爲參數被T傳遞的類(或它們的公用超類型)的被註釋,傑克遜將包括有關JSON參數T信息。這樣的JSON可以在編譯時不知道參數T的情況下進行反序列化。
這個Jackson documentation link談論多態反序列化,但是也可以用來指代這個問題。