Я пытаюсь создать собственный класс десериализатора для моего класса значений. Но 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);
Затем я попытался создать новый ObjectMapper в своем UserDeserializer и удалить @JsonDeserialize из моего класса User и моих тестовых проходов.
@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, и решение легко доступно с вашей помощью/руководством.
Сердечные приветы
Просто иметь в виду, что неповторяющихся вершина StackTrace не имеет никакого отношения к диагностическому. –
Спасибо Марко. Я удалил ненужную часть stacktrace и оставил самый важный бит. – Gary
Вы проверили, что происходит в 'DeserializationContext.java: 754'? Вы должны иметь возможность отслеживать звонки и видеть, что заставляет его перезванивать в себя. –