Cannot deserialize Throwables with Jackson databind 2.9.4 using @JsonIdentityInfo
See original GitHub issueI have written a test case that reproduces this issue. Object mapper configuration:
`
private ObjectMapperAccess() {
this.objectMapper = new ObjectMapper();
/**
* Generic configuration
*/
this.objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
this.objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
/**
* Configure deserialization features
*/
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
/**
* Register mixins
*/
this.objectMapper.addMixIn(Throwable.class, ThrowablelMixin.class);
this.objectMapper.addMixIn(StackTraceElement.class, StackTraceElementMixin.class);
}`
Mixin definitions:
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class) public abstract class ThrowablelMixin {}
public abstract class StackTraceElementMixin { // With this property name and getter name will be the same. @JsonProperty("className") private String declaringClass; }
Test case that fails:
`
private void generateException() {
try {
Integer.parseInt("invalid_int");
} catch (NumberFormatException e) {
e.printStackTrace();
throw new RmiHttpRuntimeException("Could not parse", e);
}
}
/**
* Test mixin for StackTraceElement.
*/
@Test
public void testStackTraceElementAndThrowableMixin() throws IOException {
try {
generateException();
Assert.fail(String.format("%s did not occur.", NumberFormatException.class.getName()));
} catch (RmiHttpRuntimeException re) {
re.printStackTrace();
String json = objectMapper.writeValueAsString(re);
System.out.println(json);
RmiHttpRuntimeException pre = objectMapper.readValue(json, RmiHttpRuntimeException.class);
Assert.assertFalse(pre.getStackTrace()[0].getClassName().isEmpty());
//TODO figure out a way to de/serialize cause.
Assert.assertNotNull(pre.getCause().getStackTrace()[0].getClassName());
}
}`
Exception message and stacktrace of the above test case:
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class java.lang.Throwable]: missing type id property ‘@class’ (for POJO property ‘cause’) at [Source: (String)“{”@class":“com.netapp.oci.platform.http.RmiHttpRuntimeException”,“@id”:1,“detailMessage”:“Could not parse”,“cause”:{“@class”:“java.lang.NumberFormatException”,“@id”:2,“detailMessage”:“For input string: "invalid_int"”,“cause”:2,“stackTrace”:[{“methodName”:“forInputString”,“fileName”:“NumberFormatException.java”,“lineNumber”:65,“className”:“java.lang.NumberFormatException”},{“methodName”:“parseInt”,“fileName”:“Integer.java”,“lineNumber”:580,“className”:“java.lang.Integer”},{“methodName”:“parseIn”[truncated 6895 chars]; line: 1, column: 228]
at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:1638)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1217)
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:300)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:164)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:88)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1171)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:527)
at com.fasterxml.jackson.databind.deser.std.ThrowableDeserializer.deserializeFromObject(ThrowableDeserializer.java:103)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:130)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:97)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1171)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:527)
at com.fasterxml.jackson.databind.deser.std.ThrowableDeserializer.deserializeFromObject(ThrowableDeserializer.java:103)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:130)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:97)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1171)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
at com.netapp.oci.platform.http.jackson.TestObjectMapper.testStackTraceElementMixin(TestObjectMapper.java:116)
Issue Analytics
- State:
- Created 5 years ago
- Comments:8 (4 by maintainers)
Top GitHub Comments
It is not wrong. It is the default behavior of
Throwable
when nocause
is given.From
Throwable.java
:…
@sholavanalli I think the main question is that of why
@JsonIdentityInfo
is being used. Would it be possible to just eliminate it?