将 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;
    }
}