【问题标题】:Unexpected token (END_OBJECT), expected FIELD_NAME: missing property '@type' that is to contain type id意外令牌 (END_OBJECT),预期 FIELD_NAME:缺少包含类型 ID 的属性“@type”
【发布时间】:2017-01-06 01:01:48
【问题描述】:

我正在尝试编写使用Jackson 序列化/反序列化对象到/来自File 的代码。

对象本质上是多态的。我的界面看起来像

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
        @JsonSubTypes.Type(RemoteDataSource.class),
        @JsonSubTypes.Type(FileDataSource.class)
})
public interface DataSource {
}

和实现为

public class FileDataSource implements DataSource {
    private String path;
    private String delimiter;
    private String fileNamePattern;

    @JsonCreator
    public FileDataSource(@JsonProperty("path") String path,
                          @JsonProperty("delimiter") String delimiter,
                          @JsonProperty("fileNamePattern") String fileNamePattern) {
        this.path = path;
        this.delimiter = delimiter;
        this.fileNamePattern = fileNamePattern;
    }
 ...
}

public class RemoteDataSource implements DataSource {
    private String host;
    private int port;
    private String userName;
    private String password;

    @JsonCreator
    public RemoteDataSource(@JsonProperty("host") String host,
                            @JsonProperty("port") int port,
                            @JsonProperty("userName") String userName,
                            @JsonProperty("password") String password) {
        this.host = host;
        this.port = port;
        this.userName = userName;
        this.password = password;
    }

   ...
}

WorkflowConfig 中使用它们

public class WorkflowConfig {
    private String name;
    private DataSource dataSource;

    @JsonCreator
    public WorkflowConfig(@JsonProperty("name") String name,
                          @JsonProperty("dataSource") DataSource dataSource) {
        this.name = name;
        this.dataSource = dataSource;
    }
  ...
}

然后我编写看起来像

的测试
 @Test
    public void testSerializeAndSerializeFileDataSourceFromFile() throws Exception {
        File fileDataSource = temporaryFolder.newFile("fileDataSource.json");

        DataSource dataSource = new FileDataSource("/tmp/", ",", ".*");
        WorkflowConfig config = new WorkflowConfig("fileWorkflowConfig", dataSource);

        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(fileDataSource, config);

        assertTrue(fileDataSource.length() > 0);

        DataSource readDataSource = mapper.readValue(fileDataSource, DataSource.class);
        assertNotNull(readDataSource);
    }

它失败了

com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property '@type' that is to contain type id  (for class com.datasources.DataSource)
 at [Source: /var/folders/g3/wtbqfj7d5fsbkz1gm74kqy380000gn/T/junit5577276768876379004/fileDataSource.json; line: 1, column: 123]

    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:261)
    at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1340)
    at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1196)
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:157)
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:105)
    at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:142)
    at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:42)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2731)
    at com.workflow.WorkflowConfigTest.testSerializeAndSerializeFileDataSourceFromFile(WorkflowConfigTest.java:55)
    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.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    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:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    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 com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

序列化后,文件上的数据看起来像

{"name":"fileWorkflowConfig","dataSource":{"@type":"FileDataSource","path":"/tmp/","delimiter":",","fileNamePattern":".*"}}

我相信Jackson 需要@type 信息来构造正确的对象。

但从应用程序的角度来看,我不需要这些信息,所以我使用了

@JsonIgnoreProperties(ignoreUnknown = true) 

但是我相信我犯了错误,我现在该怎么办?

完整的代码库位于GitHub。你可以在那里看到失败的测试

【问题讨论】:

    标签: java json serialization java-8 jackson


    【解决方案1】:

    测试有错误,你在序列化WorkflowConfig却试图直接反序列化DataSource。

    测试反序列化应该是:

            WorkflowConfig workflowConfig= mapper.readValue(fileDataSource, WorkflowConfig.class);
            assertNotNull(workflowConfig);
            assertNotNull(workflowConfig.getDataSource());  
    

    【讨论】:

    • 感谢您的帮助。这就是问题
    猜你喜欢
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    • 2018-09-20
    • 2011-09-20
    • 2011-11-22
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多