将 PlayFramework + Ebean 与 Gradle 一起使用
Using PlayFramework + Ebean with Gradle
我正在尝试将 Play Gradle Plugin 用于 compile/package 一个使用 Ebean 的 Play 2.3.x 应用。
在编译和打包期间一切正常,但是当我 运行 应用程序时,我得到了众所周知的错误
Entity type class SomeEntity is not an enhanced entity bean.
Subclassing is not longer supported in Ebean
那我怎样才能在编译时让Gradle运行成为增强器呢?
我就是这样做的。我正在使用 play 2.4,但应该可以为您工作。
首先在你的build.gradle中添加一个配置如下-
configurations {
enhance
}
接下来添加对ebeanorm agent的依赖如下图:
dependencies {
enhance group: 'org.avaje.ebeanorm', name: 'avaje-ebeanorm-agent', version: '4.5.3'
}
确保您的 build.gradle 中具有所需的播放依赖项,如下所示:
dependencies {
play 'org.avaje:avaje-agentloader:2.1.2'
play "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.5.3"
}
编译任务执行后最后添加以下内容做增强:
model {
components {
play {
binaries.all{binary ->
tasks.withType(PlatformScalaCompile) {
doLast {
ant.taskdef(name: 'ebean', classname: 'com.avaje.ebean.enhance.ant.AntEnhanceTask', classpath: project.configurations.enhance.asPath)
ant.ebean(classSource: "${project.buildDir}/playBinary/classes", packages: 'models.package.name', transformArgs: 'debug=1')
}
}
}
}
}
@koolrich,我已经尝试了解决方案,当它没有编译时我继续前进,后来才发现唯一的问题是 dbmodels/* 预期路径,而我的路径不同。
最初关于增强功能的术语看起来很神奇且令人困惑,但以下内容帮助我理解了正在发生的事情:
https://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html
本质上,增强是添加更多的方法和属性来处理持久性。
我正在将 Play 2.5.2 (Java) 项目从 sbt 转换为 gradle 并遇到同样的问题,然后尝试使用@koolrich 给出的解决方案。但效果不佳。一切都很好,但它未能 return 关系对象的数据(它是 returning 关系对象的 null)。然后我对比了sbt生成的增强字节码和gradle,找出delta。然后找出播放如何增强字节码。三步玩增强字节码
- 它为尚未到位的字段生成 getter 和 setter,由 play-enhancements-plugins(play.core.enhancers.PropertiesEnhancer.generateAccessors)
完成
- 它重写了直接访问字段的 classes 以使用访问器代替,由 play-enhancements-plugins(play.core.enhancers.PropertiesEnhancer.rewriteAccess)
完成
- 如果使用 Ebean,Ebean 增强器将应用于通过 application.conf(ebean 增强插件)配置的 classes
示例:
Employee employee=Employee.find.byId(1);
Company company=employee.company;
After Step 1&2, this will be converted to
Company company=employee.getCompany();
With Employee#getCompany() being something like
@PropertiesEnhancer.GeneratedAccessor
public Company getCompany(){
return this.company;
}
After step 3, the getter will be modified to be something like
@PropertiesEnhancer.GeneratedAccessor
public Company getCompany(){
return _ebean_get_company();
}
protected Company _ebean_get_company() {
this._ebean_intercept.preGetter("company");
return this.company;
}
因此将 sbt 转换为 gradle,您必须执行这三个步骤,因为 gradle play 插件不支持这三个步骤。对于第 3 步,ebean 具有可以使用的增强 class(ant Task)(@koolrich 给出的解决方案),对于第 1 步和第 2 步,我编写了另一个增强 ant Task,它添加了访问器和重写访问。这是 gradle.build 文件的样子。
configurations {
enhance
playEnhance
}
dependencies {
enhance "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.9.1"
playEnhance 'com.typesafe.play:play-enhancer:1.1.0'
}
model {
components {
play {
binaries.all{binary ->
tasks.withType(PlatformScalaCompile) {
doLast {
ant.taskdef(name: "playenhancetask", classname:"com.xxx.gradlehelper.PlayGradleEnhancherTask", classpath:"${project.buildDir}/playBinary/classes/:${project.configurations.playEnhance.asPath}")
ant.playenhancetask(classSource: "${project.buildDir}/playBinary/classes", packages: 'com.xxx.xxx.*', classpath:"${project.configurations.play.asPath}")
ant.taskdef(name: 'ebean', classname: 'com.avaje.ebean.enhance.ant.AntEnhanceTask', classpath: project.configurations.enhance.asPath)
ant.ebean(classSource: "${project.buildDir}/playBinary/classes", packages: 'com.xxx.xxx.xxx.*', transformArgs: 'debug=1')
}
}
}
}
}
}
dependencies {
play 'org.avaje:avaje-agentloader:2.1.2'
play 'org.avaje.ebeanorm:avaje-ebeanorm:6.18.1'
play 'com.typesafe.play:play-ebean_2.11:3.0.0'
play 'com.typesafe.play:play-enhancer:1.1.0'
play "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.9.1"
play group: 'org.apache.ant', name: 'ant', version: '1.8.2'
}
这是我的蚂蚁任务PlayGradleEnhancherTask.java
package com.xxx.gradlehelper;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import play.core.enhancers.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class PlayGradleEnhancherTask extends Task {
String classpath;
String classSource;
String transformArgs;
String packages;
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
public void setClassSource(String source) {
this.classSource = source;
}
public void setTransformArgs(String transformArgs) {
this.transformArgs = transformArgs;
}
public void setPackages(String packages) {
this.packages = packages;
}
public void execute() {
if (packages == null) {
throw new BuildException("No message set.");
}
log("classSource: " + classSource + ", packages: " + packages + "\n classPath: "+ classpath);
String dir = packages.trim().replace('.', '/');
dir = dir.substring(0, dir.length() - 1);
String dirPath = classSource + "/" + dir;
File d = new File(dirPath);
if (!d.exists()) {
throw new RuntimeException("File not found " + dirPath + " currentDir:" + new File(".").getAbsolutePath());
}
Path path = Paths.get(dirPath);
List<File> fileNames = new ArrayList();
List<File> files = getFiles(fileNames, path);
//generate property accessor
generateAccessors(files);
//rewrite access
rewriteAccess(files);
}
private void rewriteAccess(List<File> files) {
for (File file: files) {
try{
PropertiesEnhancer.rewriteAccess(classSource+":"+classpath,file);
}catch (Exception e){
String fileName = file == null ? "null" : file.getName() +", e: "+ e.getMessage();
System.err.println("Could not enhance[rewriteAccess]:"+fileName);
}
}
}
private void generateAccessors(List<File> files) {
for (File file: files) {
try{
PropertiesEnhancer.generateAccessors(classSource+":"+classpath,file);
}catch (Exception e){
e.printStackTrace();
String fileName = file == null ? "null" : file.getName();
System.err.println("Could not enhance[generateAccessors]: "+fileName);
}
}
}
private List<File> getFiles(List<File> files, Path dir) {
try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path path : stream) {
if(path.toFile().isDirectory()) {
getFiles(files, path);
} else {
File file = path.toFile();
if(!file.getName().startsWith("Reverse")&& file.getName().endsWith(".class")) {
files.add(file);
}
}
}
} catch(IOException e) {
e.printStackTrace();
}
return files;
}
}
我正在尝试将 Play Gradle Plugin 用于 compile/package 一个使用 Ebean 的 Play 2.3.x 应用。
在编译和打包期间一切正常,但是当我 运行 应用程序时,我得到了众所周知的错误
Entity type class SomeEntity is not an enhanced entity bean.
Subclassing is not longer supported in Ebean
那我怎样才能在编译时让Gradle运行成为增强器呢?
我就是这样做的。我正在使用 play 2.4,但应该可以为您工作。
首先在你的build.gradle中添加一个配置如下-
configurations {
enhance
}
接下来添加对ebeanorm agent的依赖如下图:
dependencies {
enhance group: 'org.avaje.ebeanorm', name: 'avaje-ebeanorm-agent', version: '4.5.3'
}
确保您的 build.gradle 中具有所需的播放依赖项,如下所示:
dependencies {
play 'org.avaje:avaje-agentloader:2.1.2'
play "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.5.3"
}
编译任务执行后最后添加以下内容做增强:
model {
components {
play {
binaries.all{binary ->
tasks.withType(PlatformScalaCompile) {
doLast {
ant.taskdef(name: 'ebean', classname: 'com.avaje.ebean.enhance.ant.AntEnhanceTask', classpath: project.configurations.enhance.asPath)
ant.ebean(classSource: "${project.buildDir}/playBinary/classes", packages: 'models.package.name', transformArgs: 'debug=1')
}
}
}
}
}
@koolrich,我已经尝试了解决方案,当它没有编译时我继续前进,后来才发现唯一的问题是 dbmodels/* 预期路径,而我的路径不同。
最初关于增强功能的术语看起来很神奇且令人困惑,但以下内容帮助我理解了正在发生的事情: https://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html 本质上,增强是添加更多的方法和属性来处理持久性。
我正在将 Play 2.5.2 (Java) 项目从 sbt 转换为 gradle 并遇到同样的问题,然后尝试使用@koolrich 给出的解决方案。但效果不佳。一切都很好,但它未能 return 关系对象的数据(它是 returning 关系对象的 null)。然后我对比了sbt生成的增强字节码和gradle,找出delta。然后找出播放如何增强字节码。三步玩增强字节码
- 它为尚未到位的字段生成 getter 和 setter,由 play-enhancements-plugins(play.core.enhancers.PropertiesEnhancer.generateAccessors) 完成
- 它重写了直接访问字段的 classes 以使用访问器代替,由 play-enhancements-plugins(play.core.enhancers.PropertiesEnhancer.rewriteAccess) 完成
- 如果使用 Ebean,Ebean 增强器将应用于通过 application.conf(ebean 增强插件)配置的 classes
示例:
Employee employee=Employee.find.byId(1);
Company company=employee.company;
After Step 1&2, this will be converted to
Company company=employee.getCompany();
With Employee#getCompany() being something like
@PropertiesEnhancer.GeneratedAccessor
public Company getCompany(){
return this.company;
}
After step 3, the getter will be modified to be something like
@PropertiesEnhancer.GeneratedAccessor
public Company getCompany(){
return _ebean_get_company();
}
protected Company _ebean_get_company() {
this._ebean_intercept.preGetter("company");
return this.company;
}
因此将 sbt 转换为 gradle,您必须执行这三个步骤,因为 gradle play 插件不支持这三个步骤。对于第 3 步,ebean 具有可以使用的增强 class(ant Task)(@koolrich 给出的解决方案),对于第 1 步和第 2 步,我编写了另一个增强 ant Task,它添加了访问器和重写访问。这是 gradle.build 文件的样子。
configurations {
enhance
playEnhance
}
dependencies {
enhance "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.9.1"
playEnhance 'com.typesafe.play:play-enhancer:1.1.0'
}
model {
components {
play {
binaries.all{binary ->
tasks.withType(PlatformScalaCompile) {
doLast {
ant.taskdef(name: "playenhancetask", classname:"com.xxx.gradlehelper.PlayGradleEnhancherTask", classpath:"${project.buildDir}/playBinary/classes/:${project.configurations.playEnhance.asPath}")
ant.playenhancetask(classSource: "${project.buildDir}/playBinary/classes", packages: 'com.xxx.xxx.*', classpath:"${project.configurations.play.asPath}")
ant.taskdef(name: 'ebean', classname: 'com.avaje.ebean.enhance.ant.AntEnhanceTask', classpath: project.configurations.enhance.asPath)
ant.ebean(classSource: "${project.buildDir}/playBinary/classes", packages: 'com.xxx.xxx.xxx.*', transformArgs: 'debug=1')
}
}
}
}
}
}
dependencies {
play 'org.avaje:avaje-agentloader:2.1.2'
play 'org.avaje.ebeanorm:avaje-ebeanorm:6.18.1'
play 'com.typesafe.play:play-ebean_2.11:3.0.0'
play 'com.typesafe.play:play-enhancer:1.1.0'
play "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.9.1"
play group: 'org.apache.ant', name: 'ant', version: '1.8.2'
}
这是我的蚂蚁任务PlayGradleEnhancherTask.java
package com.xxx.gradlehelper;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import play.core.enhancers.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class PlayGradleEnhancherTask extends Task {
String classpath;
String classSource;
String transformArgs;
String packages;
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
public void setClassSource(String source) {
this.classSource = source;
}
public void setTransformArgs(String transformArgs) {
this.transformArgs = transformArgs;
}
public void setPackages(String packages) {
this.packages = packages;
}
public void execute() {
if (packages == null) {
throw new BuildException("No message set.");
}
log("classSource: " + classSource + ", packages: " + packages + "\n classPath: "+ classpath);
String dir = packages.trim().replace('.', '/');
dir = dir.substring(0, dir.length() - 1);
String dirPath = classSource + "/" + dir;
File d = new File(dirPath);
if (!d.exists()) {
throw new RuntimeException("File not found " + dirPath + " currentDir:" + new File(".").getAbsolutePath());
}
Path path = Paths.get(dirPath);
List<File> fileNames = new ArrayList();
List<File> files = getFiles(fileNames, path);
//generate property accessor
generateAccessors(files);
//rewrite access
rewriteAccess(files);
}
private void rewriteAccess(List<File> files) {
for (File file: files) {
try{
PropertiesEnhancer.rewriteAccess(classSource+":"+classpath,file);
}catch (Exception e){
String fileName = file == null ? "null" : file.getName() +", e: "+ e.getMessage();
System.err.println("Could not enhance[rewriteAccess]:"+fileName);
}
}
}
private void generateAccessors(List<File> files) {
for (File file: files) {
try{
PropertiesEnhancer.generateAccessors(classSource+":"+classpath,file);
}catch (Exception e){
e.printStackTrace();
String fileName = file == null ? "null" : file.getName();
System.err.println("Could not enhance[generateAccessors]: "+fileName);
}
}
}
private List<File> getFiles(List<File> files, Path dir) {
try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path path : stream) {
if(path.toFile().isDirectory()) {
getFiles(files, path);
} else {
File file = path.toFile();
if(!file.getName().startsWith("Reverse")&& file.getName().endsWith(".class")) {
files.add(file);
}
}
}
} catch(IOException e) {
e.printStackTrace();
}
return files;
}
}