grails - 将Grails 1.3.7与EclipseLink 2.2.0 JPA Provi

我尝试将Grails 1.3.7与插件gorm-jpa 0.7.1结合使用,以使用EclipseLink 2.2.0作为持久性提供程序来启用JPA持久性。

当运行应用程序并单击带有JPA注释的实体的 Controller 时,我从EclipseLink的JPQLParser获得了“UnwantedTokenException”:

Executing action [list] of controller [model.PersonController] caused exception:
An exception occurred while creating a query in EntityManager:
Exception Description: Syntax error parsing the query [select person from model.Person as person ], line 1, column 24: syntax error at [.].
Internal Exception: UnwantedTokenException(found=., expected 80);
  at org.eclipse.persistence.internal.libraries.antlr.runtime.BaseRecognizer.recoverFromMismatchedToken(BaseRecognizer.java:587)
  [...]
  at org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.parse(JPQLParser.java:134)

看来EclipseLink的“model.Person”中的点有问题。

如何解决这个问题?

要重现此问题,请按如下所示设置grails项目:
grails create-app GrailsJPA
cd GrailsJPA
grails uninstall-plugin hibernate
grails install-plugin gorm-jpa
grails create-domain-class model.Person

修改“grails-app \ domain \ model \ Person.groovy”,如下所示:
package model

import javax.persistence.*;

@Entity
class Person {

    @Id
    @GeneratedValue
    long id;

    @Basic
    long version;

    @Basic
    String firstName

    @Basic
    String lastName

    static constraints = {
        firstName(nullable:true)
        lastName(nullable:true)
    }

}

生成 Controller 并查看已定义实体:
grails generate-controller model.Person
grails generate-view model.Person

修改“grails-app \ conf \ spring \ resources.groovy”,如下所示:
beans = {

    entityManagerFactory(org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean) {
        beanClassLoader = ref("classLoader")
        dataSource = ref("dataSource")
        loadTimeWeaver = new org.springframework.instrument.classloading.SimpleLoadTimeWeaver()
    }

    transactionManager(org.springframework.orm.jpa.JpaTransactionManager) {
        entityManagerFactory = entityManagerFactory
    }

}

创建文件“web-app \ WEB-INF \ classes \ META-INF \ persistence.xml”,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    <persistence-unit name="manager" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>model.Person</class>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables"/>
        </properties>
    </persistence-unit>
</persistence>

从http://www.eclipse.org/eclipselink/downloads/2.2.0下载EclipseLink 2.2.0安装程序ZIP,并从ZIP中的“eclipselink \ jlib \”中提取“eclipselink.jar”,以显示项目目录:
lib\eclipselink.jar

现在运行grails应用程序:
grails run-app

浏览到
http://localhost:8080/GrailsJPA

现在,单击 Controller “model.PersonController”以重现上述异常。

关于如何解决此问题的任何想法?

最佳答案

我设法通过以下方式使EclipseLink 2.3.0 JPA提供程序与不在软件包中的域类一起工作。

在下面的文章中,我将展示如何设置一个Grails应用程序,该应用程序使用EclipseLink作为JPA提供程序来持久化域类并在Tomcat 6 Web容器中运行该应用程序。

开始于

  • 创建一个新的grails项目
  • 卸载默认的休眠插件
  • 安装gorm-jpa插件,该插件可在JPA
  • 之上启用类似于gorm的行为
  • 创建一个新的域类“Person”进行测试
    grails create-app GrailsJPA
    cd GrailsJPA
    grails uninstall-plugin hibernate
    grails install-plugin gorm-jpa
    grails create-domain-class Person
    

  • 提示:不要将域类放在包中。 EclipseLink在处理例如“model.Person”,因为名称中包含点号,但例如“人员”(与以上职位相比)。

    编辑“grails-app \ domain \ Person.groovy”,如下所示:
    import javax.persistence.*;
    
    @Entity
    class Person {
    
        @Id
        @GeneratedValue
        long id;
    
        @Basic
        long version;
    
        @Basic
        String firstName
    
        @Basic
        String lastName
    
        static constraints = {
            firstName(nullable:true)
            lastName(nullable:true)
        }
    
    }
    

    为定义的实体生成一个 Controller 和一个 View :
    grails generate-controller Person
    grails generate-view Person
    

    现在,我们需要稍微修改生成的 Controller ,以便所有修改实体的操作(保存,编辑,更新,删除)都封装在事务中(与错误GPGORMJPA-6相比)。这是通过将整个 Action 封装到“Person.withTransaction”块中来完成的。

    如下编辑“grails-app \ controllers \ PersonController.groovy”:
    [...]
    def save = {
        Person.withTransaction {
        [...original code stays in this block...]
        }
    }
    [...]
    def edit = {
        Person.withTransaction {
            [...original code stays in this block...]           }
        }
    }
    def update = {
        Person.withTransaction {
            [...original code stays in this block...]
        }
    }
    def delete = {
        Person.withTransaction {
            [...original code stays in this block...]
        }
    }
    [...]
    

    现在,我们定义一个持久性单元“manager”,该单元指定一组要管理持久性的类(类“Person”),以及用于这些类的JPA提供程序(在我们的示例中为EclipseLink)。

    创建文件“web-app \ WEB-INF \ classes \ META-INF \ persistence.xml”,如下所示:
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
        <persistence-unit name="manager" transaction-type="RESOURCE_LOCAL">
            <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
            <class>Person</class>
            <properties>
                <property name="eclipselink.ddl-generation" value="create-tables"/>
            </properties>
        </persistence-unit>
    </persistence>
    

    请注意:如果清除了项目的“目标”目录,则该文件将被删除,例如当“grails clean”被显式调用时。因此,最好在“目标”目录之外进行文件备份。

    要使EclipseLink可用于grails项目,请下载EclipseLink 2.3.0安装程序ZIP并将ZIP中的“eclipselink \ jlib \”中的“eclipselink.jar”解压缩到grails项目的“lib”文件夹中:
    lib\eclipselink.jar
    

    现在,我们需要确保在启动Web应用程序时创建了一个“entityManagerFactory”和“transactionManager” bean。 Bean将为管理所有持久性的JPA提供程序提供所需的访问权限。

    修改“grails-app \ conf \ spring \ resources.groovy”,如下所示:
    beans = {
    
        entityManagerFactory(org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean) {
            dataSource = ref("dataSource")
            beanClassLoader = ref("classLoader")
            loadTimeWeaver = new org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver()
        }
    
        transactionManager(org.springframework.orm.jpa.JpaTransactionManager) {
            entityManagerFactory = entityManagerFactory
        }
    
    }
    

    请注意,我们在上面的声明中指定了特殊的loadTimeWeaver,它使JPA持久性提供程序可以在运行时动态地挂接到Java字节码中。使用EclipseLink时,这是必不可少的。如果仅使用org.springframework.instrument.classloading.SimpleLoadTimeWeaver进行测试,则可以启动Web应用程序,但是在访问JPA实体时,您将遇到诸如“0不是已知的实体类型”之类的异常,因为持久性提供程序无法在运行时加入实体类的管理。

    使用InstrumentationLoadTimeWeaver有点麻烦,因为只有在以下情况下才能使用
  • 使用“spring-agent” java代理和
  • 启动执行Web应用服务器的Java虚拟机
  • 我们的Web应用是由Tomcat服务器使用名为“TomcatInstrumentableClassLoader”的特殊类加载器加载的

  • 为此,请首先下载spring-agent-2.5.6.SEC02.jar和spring-instrument-tomcat-3.0.5.RELEASE.jar。

    假设您已在目录%CATALINA_HOME%中安装了Tomcat服务器。
  • 将下载的jar文件“spring-agent-2.5.6.SEC02.jar”和“spring-instrument-tomcat-3.0.5.RELEASE.jar”复制到%CATALINA_HOME%\ lib

  • 现在,我们修改“%CATALINA_HOME%\ bin \ catalina.bat”,例如Tomcat的启动和停止脚本,以确保执行Tomcat的JVM与“spring-agent” java代理一起运行。

    在所有回显之后,将以下内容添加到“执行请求的命令”部分的“%CATALINA_HOME%\ bin \ catalina.bat”中:
    if exist "%CATALINA_HOME%\lib\spring-agent-2.5.6.SEC02.jar" set JAVA_OPTS=%JAVA_OPTS% -javaagent:%CATALINA_HOME%\lib\spring-agent-2.5.6.SEC02.jar
    

    启动Tomcat后,脚本现在将检查lib目录中是否包含“spring-agent-2.5.6.SEC02.jar”,如果是这种情况,它将作为Java代理将其添加到JAVA_OPTS中。启动Tomcat时用作JVM的命令行参数。

    要为我们的Web应用程序启用“TomcatInstrumentableClassLoader”作为类加载器,我们将文件“web-app \ META-INF \ context.xml”添加到grails项目中,其内容如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
        <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
    </Context>
    

    请注意,“context.xml”中的标签区分大小写。因此,请勿尝试将更改为(或类似的东西)-这将失败!

    在打包和部署Web应用程序之前,我们先定义要用于持久性的数据源。为了进行测试,我们只定义一个HSQLDB内存数据库。

    修改“grails-app \ conf \ DataSource.groovy”,如下所示:
    [...]
    development {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:hsqldb:mem:testDB"
        }
    }
    test {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:hsqldb:mem:testDb"
        }
    }
    production {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:hsqldb:mem:testDB"
        }
    }
    [...]
    

    现在,我们准备使用以下方法为我们的Web应用程序创建WAR存档:
    grails war
    

    WAR将放置在我们项目的“目标”目录中。

    在“%CATALINA_HOME%\ webapps”中
  • 创建目录“GrailsJPA”
  • 将创建的WAR存档的所有内容提取到该目录

  • 请注意:请勿将WAR放在“%CATALINA_HOME%\ webapps”中,并希望将其部署在Tomcat启动时。这将失败!

    现在使用脚本启动Tomcat服务器
    "%CATALINA_HOME%\bin\startup.bat"
    

    Tomcat启动并运行后,使用浏览器浏览到
    http://localhost:8080/GrailsJPA
    

    现在单击 Controller “PersonController”以使用EclipseLink JPA提供程序通过JPA创建,更新,列出和删除Person实体。

    但是,使用包内部的域类仍然会失败,但上面的文章中提到了异常(exception)。此问题仍未解决。

    下载链接
  • Grails 1.3.7
    http://grails.org/Download
    
  • EclipseLink 2.3.0
    http://www.eclipse.org/eclipselink/downloads/2.3.0
    
  • Tomcat 6
    http://tomcat.apache.org/download-60.cgi
    
  • spring-instrument-tomcat-3.0.5.RELEASE.jar
    http://mvnrepository.com/artifact/org.springframework/spring-instrument-tomcat
    
  • spring-agent-2.5.6.SEC02.jar
    http://mvnrepository.com/artifact/org.springframework/spring-agent
    
  • 关于grails - 将Grails 1.3.7与EclipseLink 2.2.0 JPA Provider一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7272058/

    相关文章:

    grails - 在Grails的Jasper中将集合用作参数

    grails - 在Grails 1.1.1中安装Ivy插件:找不到Ivy zip文件

    hibernate - hibernate 缓存问题

    grails - 在选项卡中,我有两个域

    hibernate - Grails GORM映射尝试访问不存在的字段 “class”

    grails - 在对象已经与该类持久化之后修改该类

    grails - 为什么Save无法在Grails中使用模拟域?

    jakarta-ee - 将Grails应用程序作为一个war文件部署在另一个Java EE Web

    grails - 同一页上有多个表和可排序列的问题

    grails - 使用类为M:M关系建模时,Grails 2.0在Bootstrap中服务于不同的行