我无法为新的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的转换器的文档(也没有关于google的任何点击),我尝试过使用和不使用,没有任何成功。
下一个方法:
嗯,实际上,据我所知,现在应该支持更新的java8类型,因为hibernate 5的东西....并且我已经使用了5.0.5,并且在我的课程中包含了必要的库路径:
"org.hibernate" % "hibernate-java8" % "5.0.5.Final",
https://hibernate.atlassian.net/browse/HHH-8844
根本没有帮助。相同的堆栈跟踪。
为了更好的衡量,我添加了特定于hibernate的注释
@Type(type="java.time.LocalDate")
到我的领域。
那会很难看。但是,如果它有帮助的话,我已经忍受了。它没有。同样的例外。使用转换器导致其他错误。这很有趣。
我正在使用Play 2.4,使用Hibernate 5.0.5。 有没有人设法实现这个目标?
答案 0 :(得分:1)
第一个问题:表单绑定未通过验证。
我在我的控制器中调试了表单绑定工作:
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
实现修复我的第一个问题,然后Form绑定起作用。
第二个问题:持久性
我&#39;米&#39;使用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);
第一次和第三次修复需要在应用程序启动时执行。对于游戏2.4,不推荐使用GlobalSettings对象,因此我不确定他们希望您如何进行这种初始化(某人?)。但幸运的是,它仍然有效。我当然没有Globals类(默认情况下不再创建),所以我创建了类并使用以下键将应用程序指向它(来自application.conf文件):
# Minimal global settings to fix form binding and json support of java.time.LocalDate
application.global=GlobalFixes
为了您的方便,我在这里发布全班,为那些仍在学习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);
}
}
我希望能帮助一些人一些时间。