【问题标题】:How would I parse this JSON, looks like an array but no "[]"s我将如何解析这个 JSON,看起来像一个数组但没有“[]”
【发布时间】:2016-09-13 04:25:13
【问题描述】:

我正在使用带有 RestTemplate 的 Springboot 来解析 JSON。我正在查看的所有资源都处理数组,但我知道数组需要括号([])。

我这里有 JSON (https://rsbuddy.com/exchange/summary.json)

(链接断开时的简短示例)

    {"2": {"overall_average": 216, "sp": 5, "members": true, "buy_average": 215,
 "sell_average": 215, "name": "Cannonball", "id": 2}, "6": {"overall_average":
 173518, "sp": 187500, "members": true, "buy_average": 190176, "sell_average": 
189343, "name": "Cannon base", "id": 6}, ... , 

"12287": {"overall_average": 0,
     "sp": 5200, "members": false, "buy_average": 3234, "sell_average": 3234, 
    "name": "Mithril platebody (t)", "id": 12287}}

感觉应该是一个数组,因为它是一个列表,但是它没有括号,不能用下面的代码解析:

public List<ItemSummaryContainer> consumeItems() {

        ResponseEntity<List<ItemSummaryContainer>> itemSummaryResponse =
                restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<List<ItemSummaryContainer>>() {

                });

        return itemSummaryResponse.getBody();
    }

ItemSummaryContainer 类

@JsonIgnoreProperties(ignoreUnknown = true)
public class ItemSummaryContainer {

    private int id;
    private ItemSummary itemSummary;


    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public ItemSummary getItemSummary() {
        return itemSummary;
    }
    public void setItemSummary(ItemSummary itemSummary) {
        this.itemSummary = itemSummary;
    }   
}

ItemSummary 类

@JsonIgnoreProperties(ignoreUnknown = true)
public class ItemSummary {

    private Integer id;
    private String name;
    private Integer members;

    public ItemSummary() {

    }
    public ItemSummary(Integer id, String name, Integer members) {
        super();
        this.id = id;
        this.name = name;
        this.members = members;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getMembers() {
        return members;
    }
    public void setMembers(int members) {
        this.members = members;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ItemSummary other = (ItemSummary) obj;
        if (id != other.id)
            return false;
        if (members != other.members)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }   
}

堆栈跟踪

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:801) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:782) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:769) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at com.tjwhalen.game.Application.main(Application.java:50) [classes/:na]
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@55f8669d; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@55f8669d; line: 1, column: 1]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:228) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:213) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:884) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:868) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:622) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:526) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at com.tjwhalen.game.service.dao.ItemSummaryURLConsumer.consumeItems(ItemSummaryURLConsumer.java:25) ~[classes/:na]
    at com.tjwhalen.game.service.impl.ItemSummaryRestServiceImpl.getItems(ItemSummaryRestServiceImpl.java:25) ~[classes/:na]
    at com.tjwhalen.game.loader.LoadItems.load(LoadItems.java:38) ~[classes/:na]
    at com.tjwhalen.game.loader.LoaderRunner.execute(LoaderRunner.java:26) ~[classes/:na]
    at com.tjwhalen.game.Application$AppConfig.run(Application.java:78) ~[classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    ... 6 common frames omitted
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@55f8669d; line: 1, column: 1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:261) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.DeserializationContext.reportMappingException(DeserializationContext.java:1233) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1121) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1074) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:328) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:249) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2913) ~[jackson-databind-2.8.1.jar:2.8.1]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:225) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    ... 19 common frames omitted

请提供建议,或提出任何需要的澄清问题,

谢谢

【问题讨论】:

  • 您应该在问题中包含一个示例 JSON,而不是链接到实际文件。按照目前的情况,如果链接失效,未来的访问者将完全无法理解该问题。
  • 谢谢你的提示,我今天回家后会这样做,它真的很长,所以我在想像 {"2":{...}, "6":{ 之类的东西。 ..}, ..},所以我可以显示大量样本但不粘贴整个内容,还是应该粘贴整个内容?
  • 只是其中的一个代表部分就可以了,足以理解这个问题。 2 个条目,然后是一些你认为就可以的点。 :-)

标签: json spring jackson resttemplate


【解决方案1】:

您尝试解析的 JSON 完全有效。它不是一个数组,但它仍然有效:

{
  "2": {
    "overall_average": 211,
    "buy_average": 208,
    "members": true,
    "id": 2,
    "name": "Cannonball",
    "sell_average": 210,
    "sp": 5
  },
  "6": {
    "overall_average": 0,
    "buy_average": 0,
    "members": true,
    "id": 6,
    "name": "Cannon base",
    "sell_average": 0,
    "sp": 187500
  },
  "12289": {
    "overall_average": 9999,
    "buy_average": 0,
    "members": false,
    "id": 12289,
    "name": "Mithril platelegs (t)",
    "sell_average": 9999,
    "sp": 2600
  },
  ...
}

ItemSummary 类可以定义如下:

@JsonIgnoreProperties(ignoreUnknown = true)
public class ItemSummary {

    private String id;
    private String name;
    private boolean members;

    // Getters and setters omitted
}

整个 JSON 可以解析为Map&lt;String, ItemSummary&gt;。请参阅下面的详细信息。

将 JSON 解析为 Map&lt;String, ItemSummary&gt;

使用 Spring REST 模板,使用:

RestTemplate restTemplate = new RestTemplate(); 
ResponseEntity<Map<String, ItemSummary>> response = 
        restTemplate.exchange(
            "https://rsbuddy.com/exchange/summary.json", 
            HttpMethod.GET, 
            null, 
            new ParameterizedTypeReference<Map<String, ItemSummary>>() {});

Map<String, ItemSummary> map = response.getBody();

使用杰克逊的ObjectMapper,您可以:

ObjectMapper mapper = new ObjectMapper();
Map<String, ItemSummary> map = 
    mapper.readValue(new URL("https://rsbuddy.com/exchange/summary.json"),
                     new TypeReference<Map<String, ItemSummary>>() {});

Map&lt;String, ItemSummary&gt; 包装到一个类中

如果您需要围绕Map&lt;String, ItemSummary&gt; 的包装类,请将其定义如下:

@JsonIgnoreProperties(ignoreUnknown = true)
public class ItemSummaryContainer {

    private Map<String, ItemSummary> items;

    @JsonCreator
    public ItemSummaryContainer(Map<String, ItemSummary> items) {
        this.items = items;
    }

    // Getters and setters omitted
}

使用 Spring REST 模板,使用:

RestTemplate restTemplate = new RestTemplate(); 
ResponseEntity<ItemSummaryContainer> response = 
    restTemplate.exchange(
        "https://rsbuddy.com/exchange/summary.json", 
        HttpMethod.GET, 
        null, 
        new ParameterizedTypeReference<ItemSummaryContainer>() {});

ItemSummaryContainer container = response.getBody();

如果使用 Jackson 的 ObjectMapper,您将拥有:

ObjectMapper mapper = new ObjectMapper();
ItemSummaryContainer container = 
    mapper.readValue(new URL("https://rsbuddy.com/exchange/summary.json"),
                     ItemSummaryContainer.class);

【讨论】:

  • 谢谢大家!这是我第一个使用 JSON 的项目,所以我对它真的很陌生,没想到将它映射到地图上,很好的例子!
  • @TylerWhalen 我很高兴知道我的回答很有用:)
【解决方案2】:

JSON 和 JAVA 类不匹配。

你的范围是什么? JSON 还是 Java ?修复其中任何一个,并根据 Json 更改 Java 类,反之亦然。

你的 JSON:

{
"2" : {
    "members" : true,
    "sell_average" : 207,
    "id" : 2,
    "buy_average" : 206,
    "sp" : 5,
    "name" : "Cannonball",
    "overall_average" : 209
},
"6" : {
    "members
.....

据此,它期待您的描述中的Java object,而不是LIST

当您无法更改 JSON 输入时,将您的 java 类匹配为

@JsonIgnoreProperties(ignoreUnknown = true)
public class ItemSummaryContainer {

    private Map<Integer,  ItemSummary> items;
    // getter and setter
}

如果是另一边,请更改您的 JSON。

【讨论】:

    猜你喜欢
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2018-11-13
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多