gpt4 book ai didi

java - playframework:在 Play 中使用 hibernate 持久保留 java8 java.time 类型 LocalDate

转载 作者:行者123 更新时间:2023-12-01 10:40:25 25 4
gpt4 key购买 nike

我无法为新的 java.time.* 类型进行任何类型的转换或兼容性。或者至少是 LocalDate。

我看到了异常:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[IllegalStateException: Error(s) binding form: {"dateOfBirth":["Invalid value"]}]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:265) ~[play_2.11-2.4.4.jar:2.4.4]

Caused by: 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]
at controllers.Application.addPatient(Application.java:49) ~[classes/:na]

我发现了几种方法,原则上应该可以在 JPA hibernate 中工作,但是,如果这是 Play 的问题(再次)还是什么?我不知道。

第一种方法:

提供您自己的自定义转换器:

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date>
{
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}

@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

然后在现场需要使用这个:

@Convert(converter = LocalDateAttributeConverter.class)
public LocalDate dateOfBirth;

http://www.thoughts-on-java.org/persist-localdate-localdatetime-jpa/

当然,据我了解,原则上我不应该需要 @Convert 注解,因为转换器本身是用 @Converter(autoApply = true) 注解进行注解的。但由于我找不到有关在 Play 中成功使用转换器的文档(也没有在谷歌上找到任何点击),所以我尝试过使用和不使用转换器,但都没有成功。

下一个方法:

嗯,实际上,据我所知,自 hibernate 5 以来,现在应该支持较新的 java8 类型......并且我已经使用了 5.0.5,并在我的类路径中包含了必要的库:

"org.hibernate" % "hibernate-java8" % "5.0.5.Final", 

https://hibernate.atlassian.net/browse/HHH-8844

这根本没有帮助。相同的堆栈跟踪。

为了更好地衡量,我添加了 hibernate 特定注释

@Type(type="java.time.LocalDate")

到我的领域。

那会很丑陋。但如果它有帮助的话,我会忍受它。事实并非如此。同样的异常(exception)。将其与转换器一起使用会导致其他错误。这很有趣。

我正在使用 Play 2.4 和 Hibernate 5.0.5。有人成功实现这一目标吗?

最佳答案

好吧,我终于明白了。我应该更仔细地(慢慢地)查看堆栈跟踪。

事实上我最终受到了三个问题的影响。所有这些都以三种不同的方式解决。然而,所有这些都与较新的 java.time 类的“待定”支持有关。公平地说,底层库的支持最近才被引入。

第一个问题:表单绑定(bind)验证失败。

我在 Controller 中调试了表单绑定(bind)工作:

    Form<Patient> form = Form.form(Patient.class);
form = form.bindFromRequest();
System.out.println(form.toString());
Patient patient = form.get();

虽然堆栈跟踪是在调用 form.get() 时引起的,但实际上错误已经在调用 form.bindFromRequest() 时发生。错误正在 Form.errors 映射中注册,该映射来自 org.springframework.validation.DataBinder。

进一步谷歌搜索,我发现了这个:

https://groups.google.com/forum/#!topic/play-framework/Wl_ip56111c

实现它解决了我的第一个问题,然后表单绑定(bind)就起作用了。

第二个问题:持久性

我正在使用 Hibernate 来持久化对象。将 hibernate-java8 添加到我的类路径中可以实现新数据类型的持久性。对于 Play 2,此内容将放入您的 build.sbt 文件中。

libraryDependencies ++= Seq(
javaJdbc,
cache,
javaWs,
javaJpa,
"org.hibernate" % "hibernate-entitymanager" % "5.0.5.Final",
"org.hibernate" % "hibernate-java8" % "5.0.5.Final",
)

https://hibernate.atlassian.net/browse/HHH-8844

第三个问题:Json支持

我无法将模型实例化呈现为 Json 对象。它应该受到支持,但不知何故,在游戏中,它没有设置。

我发现这篇文章向我展示了如何解决这个问题:

    // http://stackoverflow.com/questions/32872474/how-to-use-java-time-localdate-on-a-play-framework-json-rest/32891177#comment56814598_32891177
// https://groups.google.com/forum/?hl=en.#!searchin/play-framework/java.time.localdate/play-framework/Dv-IpvBqWgo/l6NTp3e0BQAJ

为了您的方便,我在此处发布的修复:

    ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
mapper.registerModule(new JSR310Module());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Json.setObjectMapper(mapper);

第一个和第三个修复需要在应用程序启动时执行。对于 play 2.4,GlobalSettings 对象已被弃用,所以我不确定他们如何期望你进行这种初始化(某人?)。然而,幸运的是它仍然有效。我当然没有 Globals 类(默认情况下不再创建),因此我创建了该类并使用以下键将我的应用程序指向它(从 application.conf 文件):

# Minimal global settings to fix form binding and json support of java.time.LocalDate
application.global=GlobalFixes

为了您的方便,我将整个类(class)发布在这里,供那些仍在学习 Playframework 的人使用

import play.*;
import play.data.format.Formatters;
import play.libs.Json;

import java.time.LocalDate;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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 java.text.ParseException;

/**
* Fixes for play application. TODO remove this once Play has fixed support for LocalDate
* @author Sean van Buggenum
*
*/
public class GlobalFixes extends GlobalSettings
{ // One can see from the javadoc of java.time.LocalDate that the toString guarantees this format, regardless of locale!
private static final Pattern datePattern = Pattern.compile("(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)");

public void onStart(Application app)
{
//https://groups.google.com/forum/#!topic/play-framework/Wl_ip56111c
Formatters.register(LocalDate.class, new Formatters.SimpleFormatter<LocalDate>()
{
@Override
public LocalDate parse(String input, Locale l) throws ParseException
{
Matcher m = datePattern.matcher(input);
if (!m.matches())
throw new ParseException("No valid Input for date text: " + input, 0);
return LocalDate.of(Integer.valueOf(m.group(1)), Integer.valueOf(m.group(2)), Integer.valueOf(m.group(3)));
}

@Override
public String print(LocalDate localTime, Locale l)
{
return localTime.toString();
}
});

// Add Json's java 8 support
// http://stackoverflow.com/questions/32872474/how-to-use-java-time-localdate-on-a-play-framework-json-rest/32891177#comment56814598_32891177
// https://groups.google.com/forum/?hl=en.#!searchin/play-framework/java.time.localdate/play-framework/Dv-IpvBqWgo/l6NTp3e0BQAJ
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
mapper.registerModule(new JSR310Module());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Json.setObjectMapper(mapper);
}
}

我希望这能帮助一些人。

关于java - playframework:在 Play 中使用 hibernate 持久保留 java8 java.time 类型 LocalDate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34454991/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com