|
| 1 | +[[building-objects]] |
| 2 | +=== Building API objects |
| 3 | + |
| 4 | +[discrete] |
| 5 | +==== Builder objects |
| 6 | + |
| 7 | +All data types in the {java-client} are immutable. Object creation uses the |
| 8 | +https://www.informit.com/articles/article.aspx?p=1216151&seqNum=2[builder pattern] |
| 9 | +that was popularized in *Effective Java* in 2008. |
| 10 | + |
| 11 | +["source","java"] |
| 12 | +-------------------------------------------------- |
| 13 | +ElasticsearchClient client = ... |
| 14 | +include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[builders] |
| 15 | +-------------------------------------------------- |
| 16 | + |
| 17 | +Note that a builder should not be reused after its `build()` method has been |
| 18 | +called. |
| 19 | + |
| 20 | +[discrete] |
| 21 | +==== Builder lambda expressions |
| 22 | + |
| 23 | +Although this works nicely, having to instantiate builder classes and call the |
| 24 | +`build()` method is a bit verbose. So every property setter in the {java-client} also |
| 25 | +accepts a lambda expression that takes a newly created builder as a parameter |
| 26 | +and returns a populated builder. The snippet above can also be written as: |
| 27 | + |
| 28 | +["source","java"] |
| 29 | +-------------------------------------------------- |
| 30 | +ElasticsearchClient client = ... |
| 31 | +include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[builder-lambdas] |
| 32 | +-------------------------------------------------- |
| 33 | + |
| 34 | +This approach allows for much more concise code, and also avoids importing |
| 35 | +classes (and even remembering their names) since types are inferred from the |
| 36 | +method parameter signature. |
| 37 | + |
| 38 | +Note in the above example that builder variables are only used to start a chain |
| 39 | +of property setters. The names of these variables are therefore unimportant and |
| 40 | +can be shortened to improve readability: |
| 41 | + |
| 42 | +["source","java"] |
| 43 | +-------------------------------------------------- |
| 44 | +ElasticsearchClient client = ... |
| 45 | +include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[builder-lambdas-short] |
| 46 | +-------------------------------------------------- |
| 47 | + |
| 48 | +Builder lambdas become particularly useful with complex nested queries like the |
| 49 | +one below, taken from the |
| 50 | +{ref}/query-dsl-intervals-query.html[intervals query API documentation]. |
| 51 | + |
| 52 | +This example also highlights a useful naming convention for builder parameters in |
| 53 | +deeply nested structures. For lambda expressions with a single argument, Kotlin |
| 54 | +provides the implicit `it` parameter and Scala allows use of `_`. This can be approximated |
| 55 | +in Java by using an underscore or a single letter prefix followed by a number representing the depth |
| 56 | +level (i.e. `_0`, `_1`, or `b0`, `b1` and so on). Not only does this remove the need to create |
| 57 | +throw-away variable names, but it also improves code readability. Correct indentation |
| 58 | +also allows the structure of the query to stand out. |
| 59 | + |
| 60 | +["source","java"] |
| 61 | +-------------------------------------------------- |
| 62 | +ElasticsearchClient client = ... |
| 63 | +include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[builder-intervals] |
| 64 | +-------------------------------------------------- |
| 65 | +<1> Search results will be mapped to `SomeApplicationData` instances to |
| 66 | +be readily available to the application. |
| 67 | + |
| 68 | +{doc-tests-blurb} |
0 commit comments