2015-09-03 25 views
0

我想爲我的值類構建一個自定義的反序列化器類。但ObjectMapper .readValue被多次調用,直到拋出StackOverflowException。以下僅是一個例子:ObjectMapper readValue被調用多次,直到引發StackOverflowException

@JsonDeserialize(using = UserDeserializer.class) 
@Getter 
public class User { 
    private String name; 
} 

public class UserDeserializer extends StdDeserializer<User> { 
    public UserDeserializer() { 
     super(User.class); 
    } 

    @Override 
    public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     return ctxt.readValue(p, User.class); 
    } 
} 

public class UserDeserializerTest { 
    @Test 
    public void whenUserIsDeserializedFromJsonThenNameShouldEqualBob() { 
     String = "{ \"name\" : \"bob\" }"; 
     ObjectMapper mapper = new ObjectMapper(); 
     User user = mapper.readValue(json, User.class); 
     assertThat(user.getName).isEqualTo("bob"); 
    } 
} 

Maven依賴:

<dependencies> 
    <dependency> 
     <groupId>com.fasterxml.jackson.core</groupId> 
     <artifactId>jackson-databind</artifactId> 
     <version>2.6.1</version> 
    </dependency> 
    <dependency> 
     <groupId>org.assertj</groupId> 
     <artifactId>assertj-core</artifactId> 
     <version>1.7.1</version> 
    </dependency> 
    <dependency> 
     <groupId>org.projectlombok</groupId> 
     <artifactId>lombok</artifactId> 
     <version>1.16.2</version> 
    </dependency> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>4.12</version> 
     <scope>test</scope> 
    </dependency> 
</dependencies> 

以下StackOverflowException拋出:

Exception in thread "main" java.lang.StackOverflowError 
... 

// The following lines are repeated. 

    at com.fasterxml.jackson.databind.DeserializationContext.readValue(DeserializationContext.java:754) 
    at com.fasterxml.jackson.databind.DeserializationContext.readValue(DeserializationContext.java:746) 
    at example.UserDeserializer.deserialize(UserDeserializer.java:25) 
    at example.UserDeserializer.deserialize(UserDeserializer.java:15) 

Process finished with exit code 1 

我試圖註冊經由模塊的解串器和去除@ JsonAnnotation仍然會拋出相同的異常:

SimpleModule module = new SimpleModule("User Simple Module"); 
module.addDeserializer(User.class, new UserDeserializer()); 
ObjectMapper mapper = new ObjectMapper(); 
mapper.addModule(module); 
mapper.readValue(json, User.class); 

然後我試着在我的UserDeserializer中創建一個新的ObjectMapper,並從我的User類中刪除@JsonDeserialize,並通過了測試。

@Override 
public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
    return new ObjectMapper().readValue(p, User.class); 
} 

雖然做上述工作,我想在使用@JsonDeserialize註釋,而不是註冊一個全球性的自定義對象映射每個階級基礎註冊的解串器。我有這樣想的理由。

我試過其它代碼的組合,例如:

// Add the 'as' keyword to the annotation 
@JsonDeserialise(using = UserDeserialize.class, as = User.class) 

// Locally assigning a mapper from the JsonParser inside the UserDeserializer class 
ObjectMapper mapper = (ObjectMapper) p.getCodec(); 
mapper.readValue(p, User.class); 

// Constructing a new JSON Parser inside the deserializer 
ObjectMapper mapper = (ObjectMapper) p.getCodec(); 
JsonFactory factory = mapper.getFactory(); 
JsonParser parser = factory.createParser(p.getText()); 
return (User) parser.readValueAs(handledType()); 

// Reading the Json into a Tree 
ObjectMapper mapper = (ObjectMapper) p.getCodec(); 
ObjectNode root = (ObjectNode) p.readValueAsTree(); 
return mapper.readValue(root.traverse(), User.class); 

但讀JSON成樹拋出:

Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalStateException: No ObjectCodec defined for parser, needed for deserialization 
    at example.User.main(User.java:46) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 
Caused by: java.lang.IllegalStateException: No ObjectCodec defined for parser, needed for deserialization 
    at com.fasterxml.jackson.core.JsonParser._codec(JsonParser.java:1565) 
    at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1559) 
    at example.UserDeserializer.deserialize(UserDeserializer.java:37) 
    at example.UserDeserializer.deserialize(UserDeserializer.java:17) 
    at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3674) 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1996) 
    at example.UserDeserializer.deserialize(UserDeserializer.java:38) 
    at example.UserDeserializer.deserialize(UserDeserializer.java:17) 
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702) 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2714) 
    at example.User.main(User.java:36) 
    ... 5 more 

我也試圖實現ContextualDeserializer我UserDeserializer內,但仍然得到與之前相同的StackOverflowException:

private UserDeserializer(Class<?> vc) { 
    super(vc); 
} 

public JsonDeserializer<User> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { 
    return new UserDeserializer(ctxt.getContextualType().getRawClass()); 
} 

@Override 
public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
    return (User) new ObjectMapper().readValue(p, handledType()); 
} 

我希望這只是PEBKAC錯誤的一個不好的例子,並且您的幫助/指導可隨時獲得解決方案。

親切的問候

+0

只需記住,堆棧跟蹤的非重複上面是風馬牛不相及的診斷。 –

+0

感謝Marko。我已經刪除了堆棧跟蹤的無關部分,並留下了最重要的一點。 – Gary

+0

你是否檢查過'DeserializationContext.java:754'?您應該能夠跟蹤通話並查看是什麼使其回調到自身。 –

回答

1

我KDM同意,試試這個解串器:

public class UserDeserializer extends JsonDeserializer<User> { 

    @Override 
    public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     JsonNode node = p.readValueAsTree(); 
     User user = new User(); 
     user.setName(node.get("name").asText()); 
     return user; 
    } 
} 
+0

@Marko - 在第754行,它分配了[email protected](_valueClass =「class example.User」,然後在解串器上調用deserialize方法,然後ctxt.readValue(p,User.class)回到第754行,明顯以惡性循環結束 – Gary

+0

@KDM - 你對無限循環是正確的,但我不想在反序列化器中構造具體的類,最終我試圖去尋找一個通用的反序列化器任何對象都可以從JSON重建。我希望ObjectMapper的魔力可以幫助我,而不是試圖通過Reflection來解析整個對象。我有自定義註釋,我將註釋我的值類,並且解串器應該在構建階段對它們進行不同的處理。 – Gary

+0

@KDM - 在構建對象的第一個循環中,我的註釋將被DeserializationProblemHandler忽略,以表示它們將在稍後處理。一旦反序列化的第一階段發生,然後使用Reflection來幫助檢測註釋並構建專門的類以添加到實現合同接口的值類中。 – Gary