在 Buildship 中:如何用构建的 jar 替换 Gradle 项目?

In Buildship: how can I substitute a Gradle project with a built jar?

我希望能够让 Eclipse 忽略一个 Gradle 项目,而是使用它的预构建版本。

背景

我有一个用 Scala 编写的项目 "parser",还有十几个用 Java 编写的项目。我的工具集中最弱的 link 是 Scala IDE。我使用这个插件来编辑和编译 Scala 代码,但不幸的是它在混合语言项目中严重破坏了 Java (JDT) 工具*。

使用 Maven (m2e) 我有一个我很满意的解决方法:

  1. 构建为 .jar 放入我的本地 .m2 存储库:

    cd parser; mvn install
    
  2. 在 Eclipse 中,关闭 "parser" 项目

"Like magic",m2e 只是选择了最新的 'installed' .jar 并用它代替关闭的项目。

一个很棒的答案是如何让 Gradle 做到这一点!

然而我所希望的是满足这些的任何解决方案...

要求

  1. 我可以在必要时(很少)打开项目 parser, 通过 Gradle 命令行编辑和构建更改。 完成后我会关闭它。
  2. 其他项目使用我本地 .m2 存储库中构建的 .jar。 (如果他们总是这样做就好了。)
  3. 更改不得影响其他不使用 Eclipse 的人
  4. (理想情况下)更改可以被其他 Eclipse 用户使用

方法

@lance-java 在 提出了一个类似的问题,其中包含一些一般性建议。我认为我可以排除这些想法:

lance-java 的第 4 个想法听起来很可行。释义...

问题

主要问题:我如何构建一个解决方案,才能真正起作用并避免任何重大陷阱?

请注意,项目本身有一些依赖项,具体而言:

dependencies {
  compile 'org.scala-lang:scala-library:2.12.4'
  compileOnly  'com.google.code.findbugs:jsr305:1.3.9'
  antlr 'org.antlr:antlr4:4.5.3'
}

所以一个子问题可能是:如何在不重复定义的情况下将它们拉入其他项目? (如果这不能自动工作。)

parser项目中

你应该使用 maven-publish plugin with the publishToMavenLocal 任务

apply plugin: 'maven-publish'

group = 'your.company'
version = '1.0.0'

publishing {    
    publications {
        mavenJava(MavenPublication) {
            from components.java

            pom.withXml {
                def root = asNode()
                root.appendNode('name', 'Your parser project name')
                root.appendNode('description', 'Your parser project description')
            }
        }
    }
}

每次修改时,如有必要,只需更改版本号,然后使用 gradle publishToMavenLocal

在其他 java 项目中使用 parser

只需使用 parser 作为常规依赖项:

repositories {
    mavenLocal()
    ...
}

compile 'your.company:parser:1.0.0'

如果我对你的情况的理解很好,应该可以解决问题。

所以解决方案有点复杂。添加 'maven-publish' 以创建库后,我执行以下操作以强制 Eclipse 使用预构建的库:

subprojects {
    // Additional configuration to manipulate the Eclipse classpaths
    configurations {
        parserSubstitution
    }
    dependencies {
        parserSubstitution module("com.example:parser:${project.version}")
    }

    apply plugin: 'eclipse'
    eclipse {
        classpath {
        plusConfigurations += [ configurations.pseLangSubstitution ]
        file {
            whenMerged { cp ->

                // Get Gradle to add the depedency upon
                // parser-xxx.jar via 'plusConfigurations' above.
                // Then this here if we have a dependency on Project(':parser')
                //  - If so, remove it (completing the project -> jar substitution).
                //  - If not, remove the .jar dependency: it wasn't needed.
                def usesParser = entries.removeAll {
                    it instanceof ProjectDependency && it.path.startsWith('/parser')
                }
                def parserJar =
                    cp.entries.find { it instanceof Library && it.path.contains('parser-') }
                if (usesParser) {
                    // This trick stops Buildship deleting it from the runtime classpath
                    parserJar ?. entryAttributes ?. remove("gradle_used_by_scope")
                } else {
                    cp.entries.remove { parserJar }
                }
            }
        }
    }

所以这个有两个部分:

  1. 使用'plusConfigurations'感觉有点迂回。我最终这样做是因为我看不到如何直接构造 class Library 类路径条目。然而,这很可能是正确实施 'transient dependencies' 所必需的。 (见题末。)
  2. Gradle 开发人员在 this discussion.

用法

解决方案如我所愿。每次修改这个库中的一些代码时,我都会在命令行上执行我的以下任务(除了构建解析器 jar 之外,它还会执行一些其他代码和资源生成步骤):

./gradlew generateEclipse

然后在 Eclipse 中按 "Gradle -> Refresh Gradle Projects"、Build.

的键盘快捷键

和谐又恢复了。 :-)

  • 导航到 parser 的(预构建)源。
  • 如果我需要编辑源代码,我可以打开 parser 项目并进行编辑。 Scala-IDE 在这方面仍然做得很好。
  • 当我完成后,我执行命令,关闭项目,我的 Java 工具很高兴。