有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在applied externalscript的buildscript块中定义的java访问类路径依赖项

我最初的目标是能够在使用apply from:导入build.gradle的脚本中使用buildscript中定义的类路径依赖项。但是,由于无法解析这些类,因此无法编译外部脚本。在研究这个问题之后,我发现需要复制逻辑,因此我想我应该将buildscript提取到一个单独的文件中。然后,我就可以在build.gradle内部和外部脚本内部应用它

我甚至没有成功地从build.gradle应用外部构建脚本文件,更不用说从外部脚本应用它了。我尝试了多种方法,但无论我尝试什么,似乎总是会遇到以下两个问题之一:要么无法使用来自gradle.properties的属性,要么找不到插件(即使已定义了类路径依赖关系)

当前我的gradle/buildscript.gradle文件如下所示:

buildscript {
    repositories {
        maven { url "http://some.url.com" }
    }

    dependencies {
        classpath "my.gradle.plugin:gradle-plugin:1.0.0"
        classpath "my.library:my-library:$libraryVersion"
    }
}

libraryVersion已在gradle.properties中定义。我的发言如下:

buildscript {
    apply from: "gradle/buildscript.gradle"
}

apply plugin: 'my.gradle.plugin.PluginClass'

当我这样做时,gradle抱怨说它找不到id为my.gradle.plugin.PluginClass的插件。我尝试删除引号,我还尝试使用插件的FQN(带引号和不带引号);这两种情况都导致gradle出错,并显示一条消息,指出它在根项目上找不到属性my

我还尝试:

buildscript {
    apply from: "gradle/buildscript.gradle", to: buildscript
}

apply plugin: 'my.gradle.PluginClass'

但这会导致另一个错误,gradle抱怨它无法在gradle/buildscript.gradle中解析libraryVersion。于是我试着这样做:

buildscript {
    ext.libraryVersion = "1.0.1"

    repositories {
        maven { url "http://some.url.com" }
    }

    dependencies {
        classpath "my.gradle.plugin:gradle-plugin:1.0.0"
        classpath "my.library:my-library:$libraryVersion"
    }
}

这会导致另一个错误,gradle说在buildscript上没有这样的属性ext。我理解这是因为实际上还没有“项目”可谈,因为buildscript是单独编译的。然后我将build.gradle中的buildscript块更改回:

buildscript {
    apply from: "gradle/buildscript.gradle"
}

现在我没有得到ext错误,但是我仍然得到一个错误,说它找不到具有指定id的插件

我不能在buildscript中硬编码libraryVersion,因为我需要它作为build.gradle中的编译时依赖项,而且我不想在两个地方维护它

这是非常令人困惑和沮丧的,因为以下buildscript块本身在build.gradle中工作良好:

buildscript {
    ext.libraryVersion = "1.0.1"

    repositories {
        maven { url "http://some.url.com" }
    }

    dependencies {
        classpath "my.gradle.plugin:gradle-plugin:1.0.0"
        classpath "my.library:my-library:$libraryVersion"
    }
}

apply plugin: 'my-plugin-id' //No need to use FQN

dependencies {
    compile "my.library:library-version:$libraryVersion"
}

我尝试拆分buildscript块的原因是因为我有一个文件other.gradle,其中包含一些使用my.library类的自定义任务:

import my.library.SomeThing

task customTask(type: DefaultTask) {
    //does something with SomeThing
}

但是当我离开buildscript中的build.gradle块并像这样应用另一个文件时:

buildscript {
    ext.libraryVersion = "1.0.1"

    repositories {
        maven { url "http://some.url.com" }
    }

    dependencies {
        classpath "my.gradle.plugin:gradle-plugin:1.0.0"
        classpath "my.library:my-library:$libraryVersion"
    }
}

apply plugin: 'my-plugin-id' //No need to use FQN

dependencies {
    compile "my.library:my-library:$libraryVersion"
}

apply from: 'gradle/other.gradle'

我从gradle那里得到一个错误,说它无法解析类my.library.SomeThing。我想我可以通过拥有一个公共的buildscript文件来解决这个问题并避免重复,然后我可以在build.gradleother.gradle中应用这个文件

我在buildSrc内创建了一个自定义插件,以按照我希望的方式配置项目,但最终以一种更复杂的方式失败,并得到相同的结果。根本原因是一样的:没有办法向外部脚本公开类路径依赖关系

是否有关于此类行为的全面文件?这一切都违反了“最不出人意料”的原则。我希望buildscript中使用的build.gradle块在我将其移动到另一个文件时“正常工作”

apply关于buildscript块的语义不清楚。此外,当buildscript出现在外部文件中时,它本身的语义也不清楚——行为上有明显的变化,特别是在插件和外部属性方面

处理这个问题的最好方法是什么


共 (1) 个答案

  1. # 1 楼答案

    这是一个有点咆哮,但也有一个解决办法。我能够在不使用单独的buildscript文件的情况下解决这个问题,但是解决方法非常粗糙。我认为这是一个主要的缺点,即不能跨外部脚本共享buildscript依赖关系

    问题在于没有语义一致性,因为行为似乎取决于您决定如何组织/模块化构建逻辑。如果这是一个已知的问题,它需要在文档中的某个地方特别指出-我能够找到这种令人惊讶的行为的唯一方法是从gradle自己的论坛或StackOverflow。我不认为期望在单个文件中使用构建逻辑的离散单元的构建是不合理的,当这些离散单元被分割到多个文件中时,也可以工作。只要语义一致,构建逻辑就不应该根据您决定如何组织文件而有所不同

    我知道可能存在技术限制,但仅仅因为将逻辑从一个文件移动到另一个文件而导致构建中断是抽象泄漏,因为现在我需要知道这样做的细节和复杂性,而不是人们应该合理地期望知道的。我甚至不介意它是否被明确和具体地调用,以及解决方案/变通方法,以弥合语义上的差异。然而,当前关于组织构建逻辑的文档没有提到这些警告;它只记录了快乐之路

    /咆哮

    这就是解决办法。我使用扩展保存了对类本身的引用:

    import my.library.SomeThing
    import my.library.SomeOtherThing
    
    buildscript {
        ext.libraryVersion = "1.0.1"
    
        repositories {
            maven { url "http://some.url.com" }
        }
    
        dependencies {
            classpath "my.gradle.plugin:gradle-plugin:1.0.0"
            classpath "my.library:my-library:$libraryVersion"
        }
    }
    
    apply plugin: 'my-plugin-id' //No need to use FQN
    
    ext.SomeThing = SomeThing
    ext.SomeOtherThing = SomeOtherThing
    
    dependencies {
        compile "my.library:my-library:$libraryVersion"
    }
    
    apply from: 'gradle/other.gradle'
    

    然后在other.gradle中:

    // Necessary; you can't just use ext.SomeThing in the task later because 
    // it is available at compile-time, but apparently not at runtime. Although
    // it does work if you use project.ext.SomeThing. However, I just found this
    // to be more convenient.
    def SomeThing = ext.SomeThing
    def SomeOtherThing = ext.SomeOtherThing
    
    task someTask(type: DefaultTask) {
        // You have to use def; you cannot use the actual type because
        // it is not available at compile-time. Also, since you only
        // have a class object, you cannot use "new" directly; you have to
        // create a new instance by calling newInstance() on the class object
        def someThing = SomeThing.newInstance(...)
    
        // If you are calling static methods you can invoke them directly
        // on the class object. Again, you have to use def if the return
        // type is something defined within my-library.
        def foo = SomeOtherThing.staticMethod(...)
    }