如何将具有嵌套对象的复杂 json 文件映射到 java 对象?

Posted

技术标签:

【中文标题】如何将具有嵌套对象的复杂 json 文件映射到 java 对象?【英文标题】:How would I map a complex json file with nested objects to java objects? 【发布时间】:2019-07-06 09:19:05 【问题描述】:

我有一个由多个嵌套对象和对象数组组成的复杂 Json 文件。第一个对象是一个“OptionChain”,它有一个名为“Result”的对象。 “结果”有嵌套对象:“报价”和“选项”。最后,“Options”嵌套了名为“Call”和“Put”的对象数组。

我将所有类变量都用@JSonProperty 注释并使用Spring BootJackson 来处理对象映射。我是使用 Jackson 和对象映射的新手。

当我运行程序时,我得到这个错误:

Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "optionChain" (class com.thompson.OptionsImpliedMovement.data.OptionChain), not marked as ignorable (one known property: "result"])
 at [Source: (String)""optionChain":"result":["underlyingSymbol":"KO","expirationDates":[1550188800,1550793600,1551398400,1552003200,1552608000,1553212800,1553817600,1555545600,1558051200,1561075200,1565913600,1579219200,1610668800],"strikes":[37.0,38.0,40.5,41.5,42.5,43.5,44.5,45.5,46.5,47.5,48.5,49.5,50.5,51.0,51.5,52.0,53.0,53.5,54.0],"hasMiniOptions":false,"quote":"language":"en-US","region":"US","quoteType":"EQUITY","quoteSourceName":"Nasdaq Real Time Price","currency":"USD","exchangeDataDelayedBy":0,"earnin"[truncated 10817 chars]; line: 1, column: 17] (through reference chain: com.thompson.OptionsImpliedMovement.data.OptionChain["optionChain"])

这是主类 pom.xml 和我的两个 java 类:

主要:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.thompson.OptionsImpliedMovement.data.OptionChain;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

@SpringBootApplication
public class OptionsImpliedMovementApplication implements CommandLineRunner 

    public static void main(String[] args) 
        SpringApplication.run(OptionsImpliedMovementApplication.class, args);
    

    @Override
    public void run(String... args) throws Exception 
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        String resourceURL = "https://query2.finance.yahoo.com/v7/finance/options/ko";
        HttpEntity<String> entity = new HttpEntity<>(headers);
        ResponseEntity<String> response = restTemplate.exchange(resourceURL, HttpMethod.GET,entity, String.class);

        String rawJson = response.getBody();

        ObjectMapper objectMapper = new ObjectMapper();

        OptionChain optionChain = objectMapper.readValue(rawJson, OptionChain.class);

    

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.thompson</groupId>
    <artifactId>OptionsImpliedMovement</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>OptionsImpliedMovement</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

期权链:

import com.fasterxml.jackson.annotation.JsonProperty;

public class OptionChain 
    @JsonProperty("result")
    public Result result;

    

结果:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty; 

public class Result  

    @JsonProperty("underlyingSymbol")
    public String symbol;
    @JsonProperty("expirationDates")
    public long[] expirationDates;
    @JsonProperty("strikes")
    public double[] strikes;
    @JsonProperty("hasMiniOptions")
    public boolean hasMiniOptions;
    @JsonProperty("quote")
    public Quote quote;
    @JsonProperty("options")
    public Options option;

这是 Json 文件层次结构的截图: Hierarchy of Json

最后附上完整的 Json 文件: Full Json File

提前感谢您的帮助!

【问题讨论】:

【参考方案1】:

在我看来,您正在解组 "optionChain": ... 的 JSON,但您直接将其转换为 OptionChain。相反,您需要定义一个具有单个 OptionChain 成员的类,因为您正在解组包含此 optionChain 字段的外部对象(围绕整个响应的 是您尝试解组的对象)。

所以,例如:

public class OptionChainResponse 

   @JsonProperty("optionChain")
   private OptionChain optionChain;

   // getter/setter

然后:

OptionChainResponse optionChainResponse = objectMapper.readValue(rawJson, OptionChainResponse.class);
// do some validation or checking maybe
OptionChain optionChain = optionChainResponse.getOptionChain();

【讨论】:

以上是关于如何将具有嵌套对象的复杂 json 文件映射到 java 对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何设置映射输入的嵌套 JSON 数组对象的状态

如何将带有嵌套数组的 JSON 对象映射到打字稿模型中?

jOOQ & PostgreSQL:将从复杂 jsonb 中提取的嵌套 json 对象映射到自定义类型

如何将复杂的 Python 对象映射到 pandas 数据框?

RestKit:将嵌套数组映射到对象

无法将当前 JSON 数组(例如 [1,2,3])反序列化为具有复杂和嵌套对象的类型