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

JSON解析失败:如何定义适配单层/嵌套列表的响应Case类?

Handling Mixed Single/Nested List JSON Responses in Scala Case Classes

Got it, let's break down your problem first: your API returns inconsistent JSON structures for the same field—sometimes it's a nested list like [[x,y], [a,b]] (multiple data pairs), other times it's a flat list like [x,y] (just one pair). Your current case class is rigidly typed to one of these structures, so when the API switches to the other format, the parser throws an exception.

Here's how to fix this, using two popular Scala JSON libraries (Play JSON and Circe) since you mentioned case classes. I'll assume your data pairs are made of two values (like strings, adjust the types to match your actual data):


First, Define Your Core Case Classes

Let's start with the end goal: we want to normalize both JSON formats into a single ApiResponse case class that holds a list of DataPair instances:

// Replace String with your actual data types (Int, Double, etc.)
case class DataPair(first: String, second: String)
case class ApiResponse(data: List[DataPair])

Solution 1: Using Play JSON

Play JSON lets you define custom Reads instances to handle edge cases like this. The idea is to first try parsing the nested list format, and if that fails, fall back to parsing the flat list format:

import play.api.libs.json._

// Basic helper to convert a 2-element list to a DataPair (with validation)
def listToDataPair(list: List[String]): JsResult[DataPair] = {
  if (list.length == 2) JsSuccess(DataPair(list(0), list(1)))
  else JsError("Data pair must be a list of exactly two elements")
}

// Custom Reads for ApiResponse that handles both formats
implicit val apiResponseReads: Reads[ApiResponse] = Reads { json =>
  // First attempt: parse as nested list (multiple pairs)
  json.validate[List[List[String]]].flatMap { nestedPairs =>
    // Convert each nested list to a DataPair, collect valid results
    JsResult.traverse(nestedPairs)(listToDataPair).map(ApiResponse(_))
  }
  // If nested parsing fails, try parsing as a single flat list (one pair)
  .recoverWith { _ =>
    json.validate[List[String]].flatMap { singlePair =>
      listToDataPair(singlePair).map(pair => ApiResponse(List(pair)))
    }
  }
}

Testing It

  • For nested JSON: {"data": [["x", "y"], ["a", "b"]]} → parses to ApiResponse(List(DataPair("x","y"), DataPair("a","b")))
  • For flat JSON: {"data": ["x", "y"]} → parses to ApiResponse(List(DataPair("x","y")))

Solution 2: Using Circe

If you're using Circe (another popular Scala JSON library), the approach is similar—define a custom Decoder that handles both formats:

import io.circe._
import io.circe.generic.semiauto._

// Basic helper to convert a 2-element list to a DataPair (with validation)
def listToDataPair(list: List[String]): Decoder.Result[DataPair] = {
  if (list.length == 2) Right(DataPair(list(0), list(1)))
  else Left(DecodingFailure("Data pair must be a list of exactly two elements", Nil))
}

// Custom Decoder for ApiResponse
implicit val apiResponseDecoder: Decoder[ApiResponse] = Decoder.instance { c =>
  // Try nested list first
  c.as[List[List[String]]].flatMap { nestedPairs =>
    nestedPairs.traverse(listToDataPair).map(ApiResponse(_))
  }
  // Fall back to flat list if nested parsing fails
  .orElse {
    c.as[List[String]].flatMap { singlePair =>
      listToDataPair(singlePair).map(pair => ApiResponse(List(pair)))
    }
  }
}

// Optional: Encoder if you need to serialize back to JSON
implicit val apiResponseEncoder: Encoder[ApiResponse] = deriveEncoder[ApiResponse]

Why Your Original Code Failed

Chances are your original case class was typed to either List[List[T]] or List[T]—when the API returned the opposite format, the parser couldn't map the JSON structure to your case class, hence the Exception in thread "main" error. The custom parsers above normalize both formats into the same List[DataPair] field, so your application code doesn't have to handle the inconsistency.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:16:25