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

Java项目中Play Framework Json.fromJson返回Scala对象引发类型转换异常的解决方法

解决Play框架中Json.fromJson解析Scala列表到Java List的ClassCastException问题

这个问题在Java+Play的项目里挺常见——Play框架默认会用Scala集合来解析JSON数组,当你直接把解析结果转成Map.class时,里面的列表其实是Scala的scala.collection.immutable.List(也就是报错里的$colon$colon),自然没法直接强转成java.util.List。下面给你几个实用的解决方案:

方案一:用JsonNode直接处理(快速解决)

不用转成Map,直接用Play的JsonNode来提取数据,它会自动帮你把Scala集合转换成Java的List:

final Result result = controller.emailFilterSave(Helpers.fakeRequest().bodyJson(Json.toJson(request)).build());
// 解析成JsonNode而不是Map
JsonNode responseNode = Json.parse(Helpers.contentAsString(result));

assertEquals(HTTP_BAD_REQUEST, result.status());
assertEquals("email", responseNode.get("field").asText());
// 直接提取成Java List<String>
List<String> errors = responseNode.get("errors").findValuesAsText();
assertEquals("Email address is not valid", errors.get(0));

findValuesAsText()方法会遍历JSON数组,把每个元素转成字符串并返回Java的List<String>,完美避开类型转换问题。

方案二:创建Java DTO类(类型安全推荐)

如果你的响应结构固定,最好定义一个对应的Java DTO类,让Play的Json库直接解析到这个类里,它会自动处理Scala到Java集合的映射:

首先创建一个错误响应的DTO:

import java.util.List;

public class ValidationErrorResponse {
    private String field;
    private List<String> errors;

    // 必须要有无参构造函数,Play Json解析需要
    public ValidationErrorResponse() {}

    // Getter和Setter方法
    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public List<String> getErrors() {
        return errors;
    }

    public void setErrors(List<String> errors) {
        this.errors = errors;
    }
}

然后修改测试代码,直接解析到DTO:

final Result result = controller.emailFilterSave(Helpers.fakeRequest().bodyJson(Json.toJson(request)).build());
ValidationErrorResponse response = Json.fromJson(Json.parse(Helpers.contentAsString(result)), ValidationErrorResponse.class);

assertEquals(HTTP_BAD_REQUEST, result.status());
assertEquals("email", response.getField());
assertEquals("Email address is not valid", response.getErrors().get(0));

这种方法不仅解决了类型转换问题,还让代码更具可读性和类型安全性,后期维护也更方便。

方案三:配置Jackson强制使用Java集合(底层配置)

如果上面的方案都不适用,你可以配置Play的Jackson解析器,强制它把JSON数组解析成Java集合:

在conf/application.conf中添加如下配置:

play.json.jackson.config = {
  com.fasterxml.jackson.databind.DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY = true
}

或者在代码中自定义ObjectMapper:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

// ...

final Result result = controller.emailFilterSave(Helpers.fakeRequest().bodyJson(Json.toJson(request)).build());
ObjectMapper mapper = new ObjectMapper();
// 强制使用Java数组/集合来解析JSON数组
mapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);

JsonNode responseNode = Json.parse(Helpers.contentAsString(result));
Map<String, Object> response = mapper.treeToValue(responseNode, Map.class);

assertEquals(HTTP_BAD_REQUEST, result.status());
assertEquals("email", response.get("field"));
assertEquals("Email address is not valid", ((List<String>)response.get("errors")).get(0));

这个配置会让Jackson默认用Java的集合类型来解析JSON数组,这样再转成Map时,里面的列表就是java.util.List了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 19:32:53