Groovy 使用Builder AST 转换为流式API

  • 2019 年 10 月 4 日
  • 笔记

从Groovy 2.3开始,我们可以使用@Builder AST转换轻松地为我们的类创建一个流畅的API。 我们可以将注释应用于我们的类,结果类文件将具有支持流畅API的所有必要方法。 我们可以自定义如何使用不同的注释参数生成流畅的API。 在Groovy代码中,我们已经可以使用with方法 有一个简洁的方法来设置属性值或使用 命名的构造函数参数。 但是如果我们的类需要从Java中使用,那么为Java开发人员提供一个流畅的API来为我们的Groovy类做很好。

在下面的示例中,我们将@Builder注释应用于具有一些属性的简单类Message。 我们将所有内容保留为默认设置,然后生成的Message类文件将有一个新的builder方法,该方法返回一个内部帮助器类,我们可以使用它来设置我们的属性。 对于每个属性,它们是一个带有属性名称的新方法,因此我们可以设置一个值。 最后,我们的类包含一个build,它将返回一个具有正确属性值的Message类的新实例。

import groovy.transform.builder.Builder    @Builder  class Message {      String from, to, subject, body  }    def message = Message          .builder()  // New internal helper class.          .from('[email protected]')  // Method per property.          .to('[email protected]')          .subject('Sample mail')          .body('Groovy rocks!')          .build()  // Create instance of Message    assert message.body == 'Groovy rocks!'  assert message.from == '[email protected]'  assert message.subject == 'Sample mail'  assert message.to == '[email protected]'  //If we want to change the names of the builder and build methods we can  //use the annotation parameters builderMethodName andbuildMethodName:    import groovy.transform.builder.Builder    @Builder(builderMethodName = 'initiator', buildMethodName = 'create')  class Message {      String from, to, subject, body  }    def message = Message.initiator()          .from('[email protected]')          .body('Groovy rocks!')          .create()    assert message.body == 'Groovy rocks!'  assert message.from == '[email protected]'  //We see that for each property a corresponding method is generated. We  //can also customize the prefix for the generated method name with the  //annotation parameter prefix. In the following sample we define the  //prefix assign for the method names:    import groovy.transform.builder.Builder    @Builder(prefix = 'assign')  class Message {      String from, to, subject, body  }    def message = Message.builder()          .assignFrom('[email protected]')          .assignBody('Groovy rocks!')          .build()    assert message.body == 'Groovy rocks!'  assert message.from == '[email protected]'  //Finally we can also include and exclude properties to need to be  //included or excluded from our fluent API. We use the annotation //parametersincludes and excludes to define the names of the properties.  //This can be a list or a comma separated list of names.    import groovy.transform.builder.Builder    @Builder(excludes = 'body' /* or includes = 'from,to,subject' */)  class Message {      String from, to, subject, body  }    def message = Message.builder()          .from('[email protected]')          .to('[email protected]')          .subject('Groovy 2.3 is released')          .build()    assert message.from == '[email protected]'  assert message.subject == 'Groovy 2.3 is released'    try {      message = Message.builder().body('Groovy rocks!').build()  } catch (MissingMethodException e) {      assert e.message.readLines().first() ==              'No signature of method: static Message.body() is applicable for argument types: (java.lang.String) values: [Groovy rocks!]'  }

@Builder AST转换还检查@Canonical AST转换是否应用于类。 对于生成的构建器代码,还包括或排除在@Canonical转换中定义的任何包含或排除的属性。

我们可以使用builderStrategy注释参数定义SimpleStrategy策略。 然后生成的类将没有单独的内部帮助器构建器类和构建方法。 默认的prefix设置为set,但如果我们想要,我们可以更改:

import groovy.transform.builder.Builder  import groovy.transform.builder.SimpleStrategy    @Builder(builderStrategy = SimpleStrategy, prefix = 'assign')  class Message {      String from, to, subject, body  }    def message = new Message()          .assignFrom('[email protected]')  // Method per property.          .assignTo('[email protected]')          .assignSubject('Sample mail')          .assignBody('Groovy rocks!')    assert message.body == 'Groovy rocks!'  assert message.from == '[email protected]'  assert message.subject == 'Sample mail'  assert message.to == '[email protected]'

我们将在未来的博客文章中看到@ Builder注释的其他功能。