在Gradle中定义嵌套扩展容器

时间:2015-03-11 23:10:36

标签: gradle

我正在实现我的第一个Gradle插件,我需要定义嵌套扩展对象。用户指南尚未涵盖此内容。在过去一年左右的时间里,有几个问题存在,但我无法从我所读过的内容中找到解决方案。

我相信我希望用户能够这样做:

yang {
  yangFilesRootDir      "src/main/resources/yang"
  inspectDependencies   true

  generators {
      generator { // line 25
          generatorClassName "org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl"
          outputDir "build/gen1"
      }
      generator {
          generatorClassName "org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl"
          outputDir "build/gen2"
      }
  }
}

我对此的第一次随机刺伤看起来像这样,我确定这还没有结束:

public void apply(Project project) {
    project.plugins.apply(JavaPlugin)
    YangExtension       yang    = project.extensions.create(YANG_EXT, YangExtension)
    project.yang.extensions.generators  = 
        project.container(CodeGeneratorsContainer) {
            println it
        }

以下是我的扩展类:

class YangExtension {
    CodeGeneratorsContainer     generators
    String                      yangFilesRootDir
    String[]                    excludeFiles
    boolean                     inspectDependencies
    String                      yangFilesConfiguration
    String                      generatorsConfiguration
}

public class CodeGeneratorsContainer {
    Collection<CodeGenerator>   generators
}

class CodeGenerator {
    String  generatorClassName
    File    outputBaseDir
    Map     additionalConfiguration
}

当我立即运行时,它失败并显示以下内容:

Caused by: java.lang.NullPointerException: Cannot get property 'name' on null object
at org.gradle.api.internal.DynamicPropertyNamer.determineName(DynamicPropertyNamer.groovy:36)
at org.gradle.api.internal.DefaultNamedDomainObjectCollection.add(DefaultNamedDomainObjectCollection.java:70)
at org.gradle.api.internal.AbstractNamedDomainObjectContainer.create(AbstractNamedDomainObjectContainer.java:58)
at org.gradle.api.internal.AbstractNamedDomainObjectContainer.create(AbstractNamedDomainObjectContainer.java:52)
at org.gradle.api.internal.NamedDomainObjectContainerConfigureDelegate._configure(NamedDomainObjectContainerConfigureDelegate.java:39)
at org.gradle.api.internal.ConfigureDelegate.invokeMethod(ConfigureDelegate.java:73)
at build_2a353qtggi869feteaqu2qgc3$_run_closure1_closure3.doCall(....\workspace2\YangUsingProject\build.gradle:25)

如果重要的话,我在构建脚本中标记了第25行。

更新

集成解决方案后,这是所需设置的摘要。

&#34; build.gradle&#34;中的示例结构文件:

yang {
    yangFilesRootDir        "src/main/resources/yang"
    //excludeFiles          "target.yang"
    inspectDependencies true

    generator {
        generatorClassName  = "org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl"
        outputDir           = "build/gen1"
    }
    generator {
        generatorClassName  = "org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl"
        outputDir               = "build/gen2"
    }
}

插件&#34;申请&#34;方法:

public void apply(Project project) {
    project.plugins.apply(JavaPlugin)
    YangExtension       yang    = project.extensions.create(YANG_EXT, YangExtension, project)
    YangGenerateTask    task    = project.task(YANG_GENERATE_TASK, type: YangGenerateTask)
    project.afterEvaluate {
        task.init(project, yang)
    }
}

扩展类:

class YangExtension {
    private Project project

    Collection<CodeGenerator>   generators
    String                      yangFilesRootDir
    String[]                    excludeFiles
    boolean                     inspectDependencies
    String                      yangFilesConfiguration
    String                      generatorsConfiguration

    YangExtension(Project project) {
        this.project    = project
    }

    CodeGenerator generator(Closure closure) {
        def generator = project.configure(new CodeGenerator(), closure)
        generators.add(generator)
        return generator
    }
}

最后,CodeGenerator POGO:

class CodeGenerator {
    String  generatorClassName
    String  outputDir
    Map     additionalConfiguration
}

1 个答案:

答案 0 :(得分:16)

错误是由Project.container()尝试创建NamedDomainObjectContainer引起的。此特殊类型的集合要求集合类型指定name属性。一个常见的例子是sourceSets,其中每个项目都有一个唯一的名称(main,test等)。然后DSL看起来像:

generators {
   codeGenerator { 
      generatorClassName "org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl"
      outputDir "build/gen1"
   }
   docGenerator {
      generatorClassName "org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl"
      outputDir "build/gen2"
   }
}

如果给每个生成器命名是没有意义的,那么最好的办法就是在扩展上定义一个配置Generator对象的新实例的方法。这里的问题是,因为正在实例化生成器,如果没有Gradle会做的所有花哨的装饰(例如setter方法)。如果您需要功能,则必须在Generator类上手动定义这些方法。

<强>更新

为了利用Project.container()并创建一个NamedDomainObjectContainer,容器类型必须具有一个名为name的属性和一个公共构造函数,该构造函数的名称带有String参数。这个属性的值是我最初配置对象时使用的任何名称。例如:

sourceSets {
    integTest {
        srcDir 'src/integTest'
    }
}

上面的代码创建配置一个新的SourceSet,名称为&#34; integTest&#34;并将其添加到容器中。你可以利用你的&#34;生成器&#34;只需添加该属性即可。您还需要修改扩展类以创建generators类型的NamedDomainObjectContainer<CodeGenerator>属性,并且不需要额外的CodeGeneratorsContainer类。

class YangExtension {
    NamedDomainObjectContainer<CodeGenerator>  generators
    String                      yangFilesRootDir
    String[]                    excludeFiles
    boolean                     inspectDependencies
    String                      yangFilesConfiguration
    String                      generatorsConfiguration

    YangExtension(Project project) {
        this.generators = project.container(CodeGenerator)
    }
}

class CodeGenerator {
    String  generatorClassName
    File    outputBaseDir
    Map     additionalConfiguration
    private String name

    CodeGenerator(String name) {
        this.name = name
    }

    String getName() {
        return this.name
    }
}

更新2:

如果在DSL中使用命名对象没有意义,您只需在扩展程序上提供一个配置新CodeGenerator的方法并将其添加到集合中。

class YangExtension {
    Collection<CodeGenerator> generators = new ArrayList<>()
    private Project project

    YangExtension(Project project) {
        this.project = project
    }

    CodeGenerator generator(Closure closure) {
        def generator = project.configure(new CodeGenerator(), closure)
        generators.add(generator)
        return generator
    }
}

您的新DSL将没有generators块。它看起来就像这样:

yang {
    generator { 
        generatorClassName = "org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl"
        outputDir = "build/gen1"
    }
    generator {
        generatorClassName = "org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl"
        outputDir = "build/gen2"
    }
}
相关问题