使用 JsonTypeInfo 反序列化序列化的 jackson 对象会导致 MissmatchedInputException

Deserializing a serialized jackson object with JsonTypeInfo leads to MissmatchedInputException

我正在尝试将一些 JSON 类型为信息的数据反序列化为包装对象。不幸的是,我一直收到神秘的 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.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.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=10=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.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

这是我对 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;
}

以下 JUnit4 测试产生异常:

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);
    }
    
}

我不确定我的模型中是否遗漏了什么。任何帮助将不胜感激。

原来应该用ObjectMapper.readValue,因为ObjectMapper.convertValue不支持多态类型

感谢cowtowncoder for the quick answer on here