Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,21 @@
import org.javahelpers.simple.builders.core.enums.OptionState;

/**
* Annotation to mark classes for builder generation.
* Annotation to mark classes and records for builder generation.
*
* <p>Triggers generation of a fluent builder class with support for various patterns and helper
* methods. Can be used standalone or combined with {@link Options} for fine-grained control.
* <p>Place this annotation directly on a class or record to trigger generation of a fluent builder
* class with support for various patterns and helper methods. Can be used standalone or combined
* with {@link Options} for fine-grained control.
*
* <p><b>When to use {@code @SimpleBuilder} vs {@link Template}:</b>
*
* <ul>
* <li>Use {@code @SimpleBuilder} directly on a class/record for one-off builder generation.
* <li>Use {@link Template} on a <b>custom annotation declaration</b> to create a reusable
* configuration preset that can be applied to many classes. {@code @SimpleBuilder.Template}
* cannot be placed on a class or record directly; it is only valid on annotation types
* ({@link ElementType#ANNOTATION_TYPE}).
* </ul>
*
* <p>Available configuration options:
*
Expand All @@ -54,6 +65,14 @@
*
* <p>Use {@link Template} to create reusable configuration presets.
*
* <p>This annotation is {@link Inherited}: a subclass of an annotated type is treated as if it also
* carried {@code @SimpleBuilder} for the purpose of triggering builder generation, unless it is
* explicitly excluded via {@link Ignore4BuilderGeneration}. The {@link Template} meta-annotation is
* {@link Inherited} as well, so custom template annotations that are themselves {@code @Inherited}
* propagate to subclasses in the same way. Note that configuration options declared on the parent's
* {@code @SimpleBuilder(options = ...)} or template are not yet applied to inherited subclass
* builders; subclasses currently use default options (see issue #248).
*
* <p>Related annotations:
*
* <ul>
Expand All @@ -70,6 +89,7 @@
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
@Inherited
public @interface SimpleBuilder {

/**
Expand Down Expand Up @@ -693,10 +713,24 @@
/**
* Meta-annotation for creating custom SimpleBuilder annotation templates.
*
* <p>This allows you to create custom annotations that pre-configure SimpleBuilder options. The
* custom annotation itself will be treated as @SimpleBuilder by the processor and will
* <p>This meta-annotation is placed on a <b>custom annotation declaration</b> (i.e., an
* {@code @interface}) to pre-configure SimpleBuilder options. The custom annotation can then be
* applied to classes and records just like {@link SimpleBuilder}, and the processor will
* automatically apply the configured options.
*
* <p>This annotation can <b>only</b> be placed on annotation types ({@link
* ElementType#ANNOTATION_TYPE}); it cannot be used directly on a class or record. Use {@link
* SimpleBuilder} for direct one-off annotation of classes, or use this meta-annotation to define
* a reusable custom annotation for a shared configuration across many classes.
*
* <p>This meta-annotation is {@link Inherited}. Note that this only controls inheritance of the
* {@code @SimpleBuilder.Template} meta-annotation itself; for a custom template annotation to
* propagate to unannotated subclasses, the custom annotation must additionally be declared with
* {@code @Inherited}. Without {@code @Inherited} on the custom annotation, only the exact type
* carrying it gets a builder. As with {@link SimpleBuilder}, configuration options declared on the
* template are not yet applied to inherited subclass builders; subclasses currently use default
* options (see issue #248).
*
* <p>Example:
*
* <pre>{@code
Expand All @@ -716,6 +750,23 @@
* }
* }</pre>
*
* <p>To make the template propagate to subclasses, add {@code @Inherited} to the custom
* annotation:
*
* <pre>{@code
* @SimpleBuilder.Template(options = @SimpleBuilder.Options(...))
* @Inherited
* @Retention(RetentionPolicy.CLASS)
* @Target(ElementType.TYPE)
* public @interface FullFeaturedBuilder {}
*
* @FullFeaturedBuilder
* public class ParentDto { ... }
*
* // ChildDto also gets a builder, because @FullFeaturedBuilder is @Inherited.
* public class ChildDto extends ParentDto { ... }
* }</pre>
*
* <p>Related annotations:
*
* <ul>
Expand Down
29 changes: 28 additions & 1 deletion docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ public class PersonDto {

## Template Annotations

`@SimpleBuilder.Template` is a **meta-annotation**: it is placed on a custom annotation declaration (`@interface`), not directly on a class or record. Use it to create reusable configuration presets that can be applied to many classes with a single custom annotation. For one-off builder generation, use `@SimpleBuilder` directly on the class.

| Need | Use |
|------|-----|
| Generate a builder for a single class/record | `@SimpleBuilder` on the class/record |
| Share the same configuration across many classes | `@SimpleBuilder.Template` on a custom `@interface`, then the custom annotation on each class |

Create reusable configuration presets with custom template annotations:

```java
Expand Down Expand Up @@ -118,9 +125,27 @@ public class PersonDto {
}
```

To make a template annotation propagate to unannotated subclasses, add `@Inherited` to it. `@SimpleBuilder` itself is `@Inherited`, and `@SimpleBuilder.Template` is `@Inherited` as well, but the custom annotation must also declare `@Inherited` for the processor to pick up subclasses:

```java
@SimpleBuilder.Template(options = @SimpleBuilder.Options(...))
@Inherited
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MinimalBuilder {}

@MinimalBuilder
public class ParentDto { ... }

// ChildDto also gets a builder, because @MinimalBuilder is @Inherited.
public class ChildDto extends ParentDto { ... }
```

> **Note:** Inherited subclasses currently get a builder with **default options**, not the options declared on the parent's `@SimpleBuilder(options = ...)` or template. Options inheritance is tracked separately (see #248).

## Excluding Types from Builder Generation

You can opt a whole DTO out of builder generation with `@Ignore4BuilderGeneration`. This is useful when a class inherits `@SimpleBuilder` or an `@SimpleBuilder.Template` annotation from a parent and you do not want a builder for that specific subclass.
You can opt a whole DTO out of builder generation with `@Ignore4BuilderGeneration`. This is useful when a class inherits `@SimpleBuilder` (which is itself `@Inherited`) or an `@SimpleBuilder.Template`-based annotation from a parent and you do not want a builder for that specific subclass.

```java
import org.javahelpers.simple.builders.core.annotations.Ignore4BuilderGeneration;
Expand Down Expand Up @@ -1132,6 +1157,8 @@ Or in compiler options:
2. **Verify options parameter**: Template must specify `options = @SimpleBuilder.Options(...)`
3. **Retention and Target**: Add `@Retention(RetentionPolicy.CLASS)` and `@Target(ElementType.TYPE)`
4. **Don't combine**: Don't use `@SimpleBuilder` when using a template annotation
5. **Subclasses not getting a builder**: Add `@Inherited` to the custom template annotation so it propagates to unannotated subclasses (see [Template Annotations](#template-annotations) above). Without `@Inherited`, only the exact type carrying the annotation gets a builder.
6. **Subclass builder has wrong options**: Inherited subclass builders currently use default options, not the parent's `@SimpleBuilder.Options` or template options. This is a known limitation (see #248).

### Builder Not Generated - Access Modifier Errors

Expand Down
Loading
Loading