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注釋的其他功能。