2015-12-24 35 views
0

我无法获得任何类型的转换或兼容性工作的新java.time。*类型。或者至少,LocalDate。playframework:persist java8 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然而冬眠,如果这是一个问题(再次)播放还是什么的?我不确定。

第一种方法:在球场上

@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)注释注释的。但是因为我没有找到关于成功使用Converters with Play的文档(在Google上没有任何匹配),所以我尝试了使用和不使用,没有任何成功。

下一页方法:

嗯,其实,只要我阅读,更新的java8类型现在应该因为Hibernate 5支持的东西....和我有在使用5.0.5,并列入在我的类路径中必要的库:

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

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

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

良好的措施,我加入了休眠特定注释

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

到我的领域。

这本来是丑陋的。但如果它有帮助,我会忍受它。它没有。同样的例外。使用该转换器导致了其他错误。这很有趣。

我正在使用Play 2.4和Hibernate 5.0.5。 有没有人设法实现这个目标?

+0

我想这在圣诞节前夕发布是一个坏主意。 – svaens

回答

1

好的,所以我终于明白了。我应该更仔细地看(缓慢地)在堆栈轨迹上。

事实上,我最终受到三个问题的影响。所有解决以三种不同的方式。但是,所有这些都与新的java.time类的“挂起”支持有关。公平起见,最近才引入了底层库的支持。

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

我调试在我的控制器的形式结合工作:

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

实现一个固定的我的第一个问题,窗体,然后结合工作。

问题二:持久性

我使用Hibernate进行对象的持久性。” 将hibernate-java8添加到我的类路径中可以实现新数据类型的持久性。这对于第二场比赛来说就是在你的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 

对于方便起见,我在这里发表了全班,对于那些谁仍在学习各地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); 
    } 
} 

自己的方式,我希望可以帮助一些人一些时间。