You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jackson ObjectMapper解析无命名嵌套JSON数组时遇输入结束错误的解决方法

Fixing Jackson's "Unexpected end-of-input" Error for Nested Array JSON

Let's start with the obvious fix first—your test case's JSON string is invalid! You've got an extra opening bracket and a missing closing one, which is exactly why Jackson is throwing that "expected close marker for Array" error. Once we fix that, we'll go over a few solid ways to parse this array-heavy JSON properly.

First: Correct Your Test JSON String

Your target JSON from the API is a 2-level nested array (an outer array holding one K-line data array), but your KLINES string creates a 3-level array and doesn't close it off. Here's the corrected version that matches the API's format:

private static final String KLINES = "[\n" +
        "  [\n" +
        "    1499040000000,\n" +
        "    \"0.01634790\",\n" +
        "    \"0.80000000\",\n" +
        "    \"0.01575800\",\n" +
        "    \"0.01577100\",\n" +
        "    \"148976.11427815\",\n" +
        "    1499644799999,\n" +
        "    \"2434.19055334\",\n" +
        "    308,\n" +
        "    \"1756.87402397\",\n" +
        "    \"28.46694368\",\n" +
        "    \"17928899.62484339\"\n" +
        "  ]\n" +
        "]";

This removes the extra nested [ and adds the missing closing ], making the JSON valid.

Now: Parse the JSON Properly

Once your JSON is valid, you've got a few options depending on whether you want flexibility or type safety:

Option 1: Use JsonNode for Flexible Access

Your existing test code uses JsonNode, which works great once the JSON is fixed. You can grab elements by their index since each K-line is an ordered array:

@Test
public void readKlinesWithJsonNode() throws JsonProcessingException {
    ObjectMapper objectMapper = JSonHelper.createObjectMapper();
    JsonNode rootArray = objectMapper.readTree(KLINES);
    
    // Get the first (and only) K-line array from the root
    JsonNode klineData = rootArray.get(0);
    
    // Pull values by index (matches the comments in your API JSON)
    long openTime = klineData.get(0).asLong();
    String openPrice = klineData.get(1).asText();
    double highPrice = klineData.get(2).asDouble();
    // ... repeat for low, close, volume, etc.
}

Option 2: Map to a Custom Kline Class (Type-Safe)

For cleaner, type-safe code, create a custom class to represent the K-line data. Use Jackson's @JsonPropertyOrder to map the array indices to class fields:

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder({
    "openTime", "open", "high", "low", "close", "volume",
    "closeTime", "quoteAssetVolume", "numberOfTrades",
    "takerBuyBaseAssetVolume", "takerBuyQuoteAssetVolume", "ignore"
})
public class Kline {
    private long openTime;
    private double open;
    private double high;
    private double low;
    private double close;
    private double volume;
    private long closeTime;
    private double quoteAssetVolume;
    private int numberOfTrades;
    private double takerBuyBaseAssetVolume;
    private double takerBuyQuoteAssetVolume;
    private double ignore;

    // Add getters and setters for all fields (or use Lombok to skip boilerplate)
    public long getOpenTime() { return openTime; }
    public void setOpenTime(long openTime) { this.openTime = openTime; }
    public double getOpen() { return open; }
    public void setOpen(double open) { this.open = open; }
    // ... implement the rest of the getters/setters
}

Then parse the JSON into a List<Kline> using TypeReference:

import com.fasterxml.jackson.core.type.TypeReference;

@Test
public void readKlinesToCustomClass() throws JsonProcessingException {
    ObjectMapper objectMapper = JSonHelper.createObjectMapper();
    List<Kline> klines = objectMapper.readValue(KLINES, new TypeReference<List<Kline>>() {});
    
    // Access the first K-line
    Kline firstKline = klines.get(0);
    System.out.println("Open Time: " + firstKline.getOpenTime());
    System.out.println("Open Price: " + firstKline.getOpen());
}

Option 3: Quick and Dirty: Map to List<List<Object>>

If you don't want to create a custom class, you can parse directly into a nested list. Just be careful with type casting:

import com.fasterxml.jackson.core.type.TypeReference;

@Test
public void readKlinesToList() throws JsonProcessingException {
    ObjectMapper objectMapper = JSonHelper.createObjectMapper();
    List<List<Object>> klineList = objectMapper.readValue(KLINES, new TypeReference<List<List<Object>>>() {});
    
    List<Object> firstKline = klineList.get(0);
    long openTime = (long) firstKline.get(0);
    String openPrice = (String) firstKline.get(1);
    // ... cast other values to their appropriate types
}

Pro Tips

  • Validate JSON first: If you hit parsing errors, use a tool like JSONLint to check if the JSON is valid—truncated or malformed JSON is the #1 cause of "end-of-input" errors.
  • Handle API inconsistencies: If the external API sometimes returns truncated JSON (not just your test case), you can enable JsonParser.Feature.ALLOW_TRAILING_COMMA or write a custom deserializer to handle partial data, but first confirm the API is supposed to return valid JSON.
  • Use @JsonFormat if needed: For date/time fields (like open/close time), you can add @JsonFormat to the class fields to automatically convert timestamps to Instant or Date objects.

内容的提问来源于stack exchange,提问作者Stefan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 11:48:12