Search code examples
jacksonjackson-databind

Deserializing a serialized jackson object with JsonTypeInfo leads to MissmatchedInputException


I am trying to deserialize some JSON data with type info as a wrapper object. Unfortunately I keep getting a cryptic MismatchedInputException:

java.lang.IllegalArgumentException: Unexpected token (VALUE_STRING), expected START_OBJECT: need JSON Object to contain As.WRAPPER_OBJECT type information for class com.cumulocity.connectivity.provider.kite.model.error.ClientException
 at [Source: UNKNOWN; line: -1, column: -1]

    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4234)
    at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4165)
    at my.jackson.test.ClientExceptionTest.serializeDeserializeTest(ClientExceptionTest.java:23)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    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:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_STRING), expected START_OBJECT: need JSON Object to contain As.WRAPPER_OBJECT type information for class com.cumulocity.connectivity.provider.kite.model.error.ClientException
 at [Source: UNKNOWN; line: -1, column: -1]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
    at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1650)
    at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1400)
    at com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer._deserialize(AsWrapperTypeDeserializer.java:100)
    at com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer.deserializeTypedFromObject(AsWrapperTypeDeserializer.java:52)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209)
    at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4229)
    ... 24 more

Here is how I modelled the ClientException class:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(
        include = As.WRAPPER_OBJECT,
        use = Id.NAME
)
public class ClientException {
    private String exceptionCategory;
    private String exceptionId;
    private String text;
}

The following JUnit4 test produces the exception:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import static org.junit.Assert.*;

@Slf4j
public class ClientExceptionTest {

    @Test
    public void serializeDeserializeTest() throws JsonProcessingException {
        ClientException clientException = new ClientException();
        clientException.setExceptionId("someId");
        clientException.setExceptionCategory("someCat");
        clientException.setText("someText");

        ObjectMapper mapper = new ObjectMapper();
        String clientExceptionString = mapper.writeValueAsString(clientException);
        ClientException actual = mapper.convertValue(clientExceptionString, ClientException.class);
        assertEquals(clientException, actual);
    }
    
}

I am not sure if I'm missing something in my model. Any help would be appreciated.


Solution

  • It turns out that ObjectMapper.readValue should be used, because ObjectMapper.convertValue does not support polymorphic typing.

    Thanks to cowtowncoder for the quick answer on here.