如何在Eclipse中可靠地设置编译后字节码增强生成器?

如何在Eclipse中可靠地设置编译后字节码增强生成器?,eclipse,gradle,bytecode-manipulation,buildship,byte-code-enhancement,Eclipse,Gradle,Bytecode Manipulation,Buildship,Byte Code Enhancement,我需要用一个额外的构建器来设置一个Eclipse项目,该构建器可以增强早期构建器(理想情况下是Eclipse自己的构建器)生成的Java字节码。我成功地让这个构建器运行并正确地增强了EclipseJavaBuilder输出,但几秒钟后,Eclipse重新运行了它的JavaBuilder并重置了字节码。它不会重新运行我的增强生成器 我的设置 作为“Gradle项目”导入Eclipse2019-12(使用Buildship) 手动(并使用Gradle自动)添加了一个定制的Antbuilder(最终

我需要用一个额外的构建器来设置一个Eclipse项目,该构建器可以增强早期构建器(理想情况下是Eclipse自己的构建器)生成的Java字节码。我成功地让这个构建器运行并正确地增强了EclipseJavaBuilder输出,但几秒钟后,Eclipse重新运行了它的JavaBuilder并重置了字节码。它不会重新运行我的增强生成器

我的设置

  • 作为“Gradle项目”导入Eclipse2019-12(使用Buildship)
  • 手动(并使用Gradle自动)添加了一个定制的Antbuilder(最终调用Gradle),以增强EclipseJavaBuilder在bin/main中就地生成的代码。此生成器设置为在手动生成和自动生成时运行,而不是在“清理”后或“清理”期间运行
  • 默认情况下,上面的结果是有三个构建器,从上到下:1。格雷德尔项目建设者,2。JavaBuilder和3。我的字节码增强生成器(是的,它列在最后)
我尝试过的备选方案

  • 将我的生成器设置为在“清理”之后/期间运行的一些组合也没有成功。真的,我不确定这些事件到底与什么有关
  • 让建设者在。。。而且也没有-没有帮助
  • 尝试使用Gradle脚本中的以下位删除Java Builder(不起作用-它会自行恢复):

  • 尝试手动禁用Java构建器,并让我的字节码增强构建器自己构建文件(使用Gradle)。这将存储以下文件
    org.eclipse.jdt.core.javabuilder.launch
    文件,其中包含以下内容。。。但重新启动后,将重新启用生成器:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
    <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
    <stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="org.eclipse.jdt.core.javabuilder"/>
    <mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
    <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
    </launchConfiguration>
    
    更新2:复制的最小示例

  • 创建一个文件夹-根据需要命名
  • 在该文件夹中创建包含以下内容的build.grade文件:

    buildscript {
        repositories {
            mavenCentral()
        }
    
        dependencies {
            classpath 'org.hibernate:hibernate-gradle-plugin:5.4.2.Final'
        }
    }
    
    plugins {
        id 'java'
        id 'eclipse'
    }
    
    apply plugin: 'org.hibernate.orm'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
    }
    
    hibernate {
        sourceSets = [ project.sourceSets.main ]
        enhance {
            enableLazyInitialization = true;
            enableDirtyTracking = true;
            enableAssociationManagement = false;
            enableExtendedEnhancement = false;
        }
    }
    
  • 在其中创建src/main/java/learner/TestEntity.java,如下所示:

    package learner;
    
    import javax.persistence.*;
    
    @Entity
    public class TestEntity {
        @Id
        @Column(name = "id", nullable = false, updatable = false)
        private Long id = null;
    
        @Column(name = "name", columnDefinition = "TEXT")
        private String name = null;
    
        public Long getId() {
            return id;
        }
    
        public void setId(final Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(final String name) {
            this.name = name;
        }
    }
    
  • 执行
    gradlecompilejava
    。在ASCII或十六进制查看器中打开生成的
    build/classes/java/main/learner/TestEntity.class
    二进制文件,观察其中的
    $$\u hibernate\u write\u name
    之类的内容

  • 将此项目作为Gradle项目导入Eclipse(比如2019-12)并构建它。打开生成的
    bin/main/learner/TestEntity.class
    ,不进行任何观察

  • 有几件事我不清楚/搞错了,无法找到相关文档来了解细节。下面是一个总结,总结了要做到这一点需要知道的内容(其中一些是我一开始就知道的,但不是全部):

  • Eclipse中的Gradle/Buildship集成试图利用Eclipse的内部编译器。这是Eclipse的设计,在开发过程中有自己的优势。。。以及在这种情况下的缺点-无法利用外部/生产构建器(本例中为Gradle模型)进行构建。因此,在Gradle中运行的任何字节码增强(插件或非插件)在Eclipse中都不会产生任何效果(除非它们执行特定于Eclipse的操作)。(我说对了)
  • 要在Eclipse中执行字节码增强(不是apt,也不是某些Eclipse插件可以做的),必须添加自定义构建器,并将它们放置在默认Java构建器之后(手动或自动)。(我也说对了)
  • 现成的Eclipse提供了两种构建器——“Ant”和“Program”。没有格拉德尔。“程序”类不是跨平台的,只有Ant是。Ant可以用来做事情,或者以跨平台的方式启动Gradle(Gradle的main()方法上的Java exec)。(我也说对了)
  • [我在这里错了]Eclipse提供了四个“事件”,可以将Ant构建器绑定到它们:在“清理”之后、手动构建、自动构建以及在“清理”期间。我不明白他们什么时候跑。例如,我认为“在清理过程中”会在清理过程中运行,在“清理”之后会运行,以允许自定义构建器在清理后自行运行。我认为,如果启用了“自动生成”或在“清除”对话框中选中了“立即生成”,则会出现自动生成情况并非如此。“清理”后实际上是指一个构建步骤,而不是清理,并且后面不会跟着“自动构建”步骤(该步骤仅在保存编辑并启用“自动构建”时运行。在构建器的*.launch文件中,这一点更为明显-在“清理”后“实际上称为
    full
    ,自动和手动生成称为
    Auto
    incremental
    。这意味着除了自动生成和手动生成外,必须将en enhancement builder设置为在“清理”后运行,并且在“清理”期间不应设置为在*上运行。”.我的错误是只将其设置为自动和手动生成运行
  • [我在这里也错了]我在增强生成器的“构建选项”选项卡中指定了相关资源的工作集。我将这些资源设置为源代码(要增强)和
    Build.gradle
    (包含增强程序)。由于这些在大多数构建中不会更改,Eclipse选择不运行构建器。现在显而易见的20-20愿景事实是,此构建器的相关资源是Java构建器的输出二进制文件(和
    build.gradle
    ),而不是Java源代码。然而,这并不是完全正确的选择(孤立地)在我们的例子中,无论是Eclipse还是Eclipse,最终都会进入一个无限循环——它认为增强器更改了二进制文件,并且,由于它设置为在二进制文件更改时运行,因此再次运行构建。我们根本无法设置相关资源,因为这似乎意味着“一切/任何事情”。增强器的制作方式必须确保不会触及已增强的文件[UPDATE]
    buildscript {
        repositories {
            mavenCentral()
        }
    
        dependencies {
            classpath 'org.hibernate:hibernate-gradle-plugin:5.4.2.Final'
        }
    }
    
    plugins {
        id 'java'
        id 'eclipse'
    }
    
    apply plugin: 'org.hibernate.orm'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
    }
    
    hibernate {
        sourceSets = [ project.sourceSets.main ]
        enhance {
            enableLazyInitialization = true;
            enableDirtyTracking = true;
            enableAssociationManagement = false;
            enableExtendedEnhancement = false;
        }
    }
    
    package learner;
    
    import javax.persistence.*;
    
    @Entity
    public class TestEntity {
        @Id
        @Column(name = "id", nullable = false, updatable = false)
        private Long id = null;
    
        @Column(name = "name", columnDefinition = "TEXT")
        private String name = null;
    
        public Long getId() {
            return id;
        }
    
        public void setId(final Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(final String name) {
            this.name = name;
        }
    }