如何在 Play Framework JSON Rest 上使用 java.time.LocalDate?

Posted

技术标签:

【中文标题】如何在 Play Framework JSON Rest 上使用 java.time.LocalDate?【英文标题】:How to use java.time.LocalDate on a Play Framework JSON Rest? 【发布时间】:2015-09-30 17:39:47 【问题描述】:

我正在尝试让 Play 序列化和反序列化 java 8 LocalDate。

据说在 Play 2.4 上可以开箱即用:

Play 2.4 现在需要 JDK 8。因此,Play 可以开箱即用地提供对 Java 8 数据类型的支持。例如,Play 的 JSON API 现在支持 Java 8 时间类型,包括 Instance、LocalDateTime 和 LocalDate。

但我无法让它工作。

这是我所拥有的: 我正在使用 Play 2.4.3,带有 PlayJava 和 PlayEbean 插件

型号

@Entity
public class Person extends Model 

    @Id
    public Long id;

    public String name;

    public LocalDate dayOfBirth;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
    public LocalDate anotherDate;

    @Formats.DateTime(pattern = "dd/MM/yyyy")
    public LocalDate andAnotherOne;

    public static Model.Finder<Long, Person> find = new Model.Finder<Long, Person>(Person.class);

控制器

public class PersonController extends Controller 

    public Result create() 
        Person person = Json.fromJson(request().body().asJson(), Person.class);

        person.save();

        return ok(Json.toJson(person));
    

    public Result all() 
        return ok(Json.toJson(Person.find.all()));
    

路线

POST        /person              @controllers.PersonController.create()

GET         /person              @controllers.PersonController.all()

我使用 REST 的 chrome 应用程序对其进行了测试,并得到了三种形式的错误:

"name":"Fred","dayOfBirth":"2015-09-30"
"name":"Fred","anotherDate":"30/09/2015"  
"name":"Fred","andAnotherOne":"30/09/2015"

错误

java.lang.RuntimeException:     com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate     value of type [simple type, class java.time.LocalDate] from String value     ('2015-09-30'); no single-String constructor/factory method
 at [Source: N/A; line: -1, column: -1] (through reference chain:     models.Person["dayOfBirth"])

我错过了什么?

更新:示例应用:https://github.com/fredferrao/LocalDateJSONTest

【问题讨论】:

【参考方案1】:

我发现了问题,Play正在注入一个自定义的ObjectMapper,我认为它没有注册jackson的Jdk8Module和JSR310Module。

我开了一个issue

我找到的解决方法是在 Global.java 上设置自己的 ObjectMapper

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
import play.Application;
import play.GlobalSettings;
import play.libs.Json;

/**
 * Criado por ferrao em 01/10/2015.
 */
public class Global extends GlobalSettings 
    public void onStart(Application app) 
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Jdk8Module());
        mapper.registerModule(new JSR310Module());
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        Json.setObjectMapper(mapper);
    

我从 play.libs.Json 源复制的 mapper.configure 部分

【讨论】:

我想我也有同样的问题。我也在使用 play 2.4,并且几乎从头开始我的项目。默认情况下,他们似乎不再拥有/使用 Global 对象。至少是不鼓励的。 playframework.com/documentation/2.4.x/GlobalSettings 知道没有它我如何设置 ObjectMapper 吗?还是我现在需要包含一个 GlobalSettings 对象来解决这个错误? 其实我错了。这是一个不同的错误: 引起:java.lang.IllegalStateException: Error(s) binding form: "dateOfBirth":["Invalid value"] at play.data.Form.get(Form.java:592) ~ [play-java_2.11-2.4.4.jar:2.4.4] 其实,除了我自己的问题,我最终还是要按照你的方式解决json问题。谢谢! 如何解决序列化问题,即在转换为 JSON 时,LocalDate 被格式化为数组 [2016, 8, 11],我希望它是 ISO 8061 格式,如 2016-08- 11. @Jaanus 只需将@JsonFormat(shape = STRING) 注释添加到LocalDate 字段。

以上是关于如何在 Play Framework JSON Rest 上使用 java.time.LocalDate?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过json暴露play framework 1.2.7中的内部错误消息id?

Play Framework 2.4.1:如何从 JsArray 中移除元素

如何在 Play Framework 模板中对列表进行排序?

Play Framework Secure Module:登录JSON响应接口

Scala Play Framework 2.6密封特征格式给Json

Scala + Play Framework + Slick - Json 作为模型字段