Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization of nested generic inheritance fails: can not specialize #2080

Closed
Felk opened this issue Jul 4, 2018 · 4 comments
Closed

Serialization of nested generic inheritance fails: can not specialize #2080

Felk opened this issue Jul 4, 2018 · 4 comments

Comments

@Felk
Copy link

Felk commented Jul 4, 2018

When trying to serialize an object, which itself has generic objects, under some circumstances the serialization fails. It's difficult to put the exact circumstances under which the error occurs into words, so I made a minimal testcase.


static final ObjectMapper MAPPER = new ObjectMapper();
static {
    MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}

public interface NestedValue<T extends Serializable> extends Serializable {}
public interface ValueHandler<T extends Serializable> {}
public class NestedValueHandler<T extends Serializable> implements ValueHandler<NestedValue<T>> {
    public final ValueHandler<T> handler;
    public NestedValueHandler(ValueHandler<T> handler) {
        this.handler = handler;
    }
}

@Test
public void testJacksonFail() throws JsonProcessingException {

    final ValueHandler<NestedValue<String>> obj1 = new NestedValueHandler<>(null);
    // works:
    MAPPER.writeValueAsString(obj1);

    final ValueHandler<NestedValue<NestedValue<String>>> obj2
            = new NestedValueHandler<>(new NestedValueHandler<>(null));
    // fails:
    MAPPER.writeValueAsString(obj2);
}

failure output:

com.fasterxml.jackson.databind.JsonMappingException: Failed to specialize base type <package>.JacksonTest$ValueHandler<java.io.Serializable> as <package>.JacksonTest$NestedValueHandler, problem: Type parameter #1/1 differs; can not specialize java.io.Serializable with <package>.JacksonTest$NestedValue<$1> (through reference chain: <package>.JacksonTest$NestedValueHandler["plugin"])

	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:391)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
	at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:727)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
	at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905)
	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219)
	at <package>.JacksonTest.testJacksonFail(JacksonTest.java:47)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.IllegalArgumentException: Failed to specialize base type <package>.JacksonTest$ValueHandler<java.io.Serializable> as <package>.JacksonTest$NestedValueHandler, problem: Type parameter #1/1 differs; can not specialize java.io.Serializable with <package>.JacksonTest$NestedValue<$1>
	at com.fasterxml.jackson.databind.type.TypeFactory._bindingsForSubtype(TypeFactory.java:431)
	at com.fasterxml.jackson.databind.type.TypeFactory.constructSpecializedType(TypeFactory.java:401)
	at com.fasterxml.jackson.databind.cfg.MapperConfig.constructSpecializedType(MapperConfig.java:297)
	at com.fasterxml.jackson.databind.DatabindContext.constructSpecializedType(DatabindContext.java:161)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._findAndAddDynamic(BeanPropertyWriter.java:893)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:705)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	... 28 more
@cowtowncoder
Copy link
Member

First of all, thank you for reporting the issue.

2.9.6 did relax some of the checks, which probably explains why some cases now work.
From what I remember this are did seem likely to have remaining challenges... type assignment compatibility handling is tricky, and one challenge is that whereas limits make sense on deserialization (where mis-assignments are problematic), they are not really that useful on serialization side. But unfortunately type handlers do not know the context (nor ideally should have to worry).

@Felk
Copy link
Author

Felk commented Mar 12, 2019

The above test fails on Jackson 2.9.7, but succeeds on 2.9.8.
Is this intentional and just not mentioned here, or did something unexpectedly change?

@cowtowncoder
Copy link
Member

@Felk there are always fixes in patch versions, but it is possible issues are sometimes duplicated. Looking at 2.9.8 release notes, I'd guess fix for #2155 may have fixed this problem. Do you that looks likely?

@Felk
Copy link
Author

Felk commented Mar 13, 2019

Yes. Not only does that exactly describe and solve my issue, it literally is the exact same issue affecting the exact same codebase, because it's reported by a coworker 😄

Thank you very much!

I'll close this issue, as it is resolved in 2.9.8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants