Cannot use property annotations on StackTraceElement to configure deserialization (original) (raw)
I am working on Apache Log4j 2.0 (in beta) with Jackson 2.3.2 and I must override the stock deserializer to read JSON StackTraceElements that look like this:
{"class":"package.SomeClass","method":"someMethod","file":"SomeClass.java","line":123}
Simple enough I thought, mix-ins are perfect for this, a non-intrusive design pattern:
@JsonIgnoreProperties("nativeMethod") abstract class StackTraceElementMixIn { @JsonCreator StackTraceElementMixIn(@JsonProperty("class") String declaringClass, @JsonProperty("method") String methodName, @JsonProperty("file") String fileName, @JsonProperty("line") int lineNumber) { // empty }
@JsonProperty("class")
abstract String getClassName();
@JsonProperty("file")
abstract String getFileName();
@JsonProperty("line")
abstract String getLineNumber();
@JsonProperty("method")
abstract String getMethodName();}
and:
public class Log4jObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
public Log4jObjectMapper() {
registerModule(new Log4jModule());
}}
and:
public class Log4jModule extends SimpleModule {
public Log4jModule() {
super(Log4jModule.class.getName(), new Version(2, 0, 0, null, null, null));
}
@Override
public void setupModule(SetupContext context) {
context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class);
}}
It does not work. Jackson uses its own deserializer com.fasterxml.jackson.databind.deser.std.StackTraceElementDeserializer.
But... serialization works fine! As a test, I used the mix-in above to produce the same JSON text I listed above.
Surely, serialization and deserialization should behave the same with regard to mix-ins?
As a workaround, I made a copy of StackTraceElementDeserializer and changed the Java package and class name and JSON attribute names in the code, then I did this in my domain class:
@JsonProperty("Location")
@JsonDeserialize(using=MyStackTraceElementDeserializer.class)
private StackTraceElement location;and it still does not work! The UnrecognizedPropertyException is the same:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "class" (class java.lang.StackTraceElement), not marked as ignorable
at [Source: java.io.StringReader@32b427c1; line: 1, column: 11] (through reference chain: java.lang.StackTraceElement["class"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:671)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:771)
at com.fasterxml.jackson.databind.deser.std.StackTraceElementDeserializer.deserialize(StackTraceElementDeserializer.java:47)
at com.fasterxml.jackson.databind.deser.std.StackTraceElementDeserializer.deserialize(StackTraceElementDeserializer.java:11)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2993)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2098)
at org.apache.logging.log4j.core.jackson.StackTraceElementMixInTest.testObjectMapper(StackTraceElementMixInTest.java:31)
Test:
import org.junit.Assert; import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
public class StackTraceElementMixInTest {
@Test
public void testObjectMapper() throws Exception {
ObjectMapper objectMapper = new Log4jObjectMapper();
StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123);
final String s = objectMapper.writeValueAsString(expected);
StackTraceElement actual = objectMapper.readValue(s, StackTraceElement.class);
Assert.assertEquals(expected, actual);
}Help!
Thank you,
Gary