Skip to content

Commit

Permalink
Add documentation for the new optional semantics.
Browse files Browse the repository at this point in the history
  • Loading branch information
skinny85 committed Jan 24, 2024
1 parent 52dd5a7 commit a28daa1
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 15 deletions.
24 changes: 17 additions & 7 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import org.jilt.Builder;
public final class Person {
public final String name;
public final boolean isAdult;

public Person(String name, boolean isAdult) {
this.name = name;
this.isAdult = isAdult;
Expand All @@ -52,12 +52,12 @@ public class PersonBuilder {
this.name = name;
return this;
}

public PersonBuilder isAdult(boolean isAdult) {
this.isAdult = isAdult;
return this;
}

public Person build() {
return new Person(name, isAdult);
}
Expand Down Expand Up @@ -192,7 +192,7 @@ public abstract class DateFactory {
}
```

And you can use the Builder like so:
And you can use the generated Builder like so:

```java
import com.example.DateBuilder;
Expand Down Expand Up @@ -259,8 +259,8 @@ Person person = PersonBuilder.person()

##### Optional properties

When using Staged Builders, there are often properties that the client can,
but doesn't have to, provide in order to construct a valid instance of the target class -
When using Staged Builders, there are often properties that don't have to be provided
in order to construct a valid instance of the target class -
the property could be optional, it could have some default, etc.

When using the `STAGED` Builder style, you can mark a field or constructor/static method parameter
Expand Down Expand Up @@ -307,13 +307,23 @@ User user = UserBuilder.user()
.build();
```

In addition to the `@Opt` annotation,
a property will always be considered optional if:

* The field or parameter it represents is annotated with a `@Nullable` annotation.
All types of `@Nullable` annotations are supported,
including `javax.annotation.Nullable` from [JSR-305](https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305),
`org.jetbrains.annotations.Nullable` from [JetBrains annotations](https://mvnrepository.com/artifact/org.jetbrains/annotations),
and others.
* The field or parameter is of the type `java.util.Optional` introduced in [Java 8](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html).

##### 'Staged, but preserving order' Builder style

The Staged Builder style has one downside:
when evolving your API, you cannot change a required property to be optional
(with the small exception of the last required property)
without breaking existing code that uses the Builder generated when the property was required -
even though, purely from an API perspective, that should not be a breaking change for the clients of your classes.
even though, purely from an API perspective, that should not be a breaking change for the clients of your class.

For example, if we take the above `User` class, but with `username` being required,
the client code using that Builder looks something like this:
Expand Down
29 changes: 21 additions & 8 deletions src/main/java/org/jilt/Opt.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,30 @@

/**
* Marking a field or constructor/static method parameter with this annotation
* means the Builder property extracted from that field or parameter will be optional.
* means the Builder property generated from that field or parameter will be optional.
* <p>
* Builder clients are not required to provide values for optional properties
* before building an instance of the target class. If not provided, the generated Builder
* will pass default 0-values in place of the skipped optional properties
* Consumers of that generated Builder are not required to provide values for optional properties
* before creating an instance of the target class.
* If not provided, the generated Builder will pass the default zero-value
* (<code>0</code> for <code>int</code>s, <code>null</code> for reference types etc.)
* when constructing an instance of the target class.
* for the given optional property when constructing an instance of the target class.
* <p>
* How exactly does the API for skipping optional properties look like for the clients depends on the
* {@link Builder#style} of the generated Builder - see the {@link BuilderStyle} enum values
* documentation for details.
* In addition to using this annotation,
* a property will also be considered optional if:
* <ul>
* <li>
* The field or parameter it represents is annotated with a {@code @Nullable} annotation.
* All types of {@code Nullable} annotations are supported,
* including {@code javax.annotation.Nullable}, {@code org.jetbrains.annotations.Nullable},
* and others.
* </li>
* <li>
* The field or parameter is of type {@code java.util.Optional}.
* </li>
* </ul>
* How exactly does the API for skipping optional properties look like for the consumers of the generated Builder class
* depends on the choice of the {@link Builder#style} attribute used -
* see the {@link BuilderStyle} enum values documentation for details.
*
* @since 1.0
* @see Builder
Expand Down

0 comments on commit a28daa1

Please sign in to comment.