{"id":16323830,"url":"https://github.com/skinny85/jilt","last_synced_at":"2025-04-07T09:19:40.755Z","repository":{"id":17302303,"uuid":"81646368","full_name":"skinny85/jilt","owner":"skinny85","description":"Java annotation processor library for auto-generating Builder (including Staged Builder) pattern classes","archived":false,"fork":false,"pushed_at":"2024-09-22T18:25:55.000Z","size":447,"stargazers_count":230,"open_issues_count":0,"forks_count":13,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-10-11T22:55:53.374Z","etag":null,"topics":["builder","java","java-annotation-processor","type-safety"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skinny85.png","metadata":{"files":{"readme":"Readme.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-11T10:39:08.000Z","updated_at":"2024-09-24T12:05:44.000Z","dependencies_parsed_at":"2024-06-29T17:36:19.732Z","dependency_job_id":"fec0cb5b-8390-4447-b6ef-9299f573b790","html_url":"https://github.com/skinny85/jilt","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skinny85%2Fjilt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skinny85%2Fjilt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skinny85%2Fjilt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skinny85%2Fjilt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skinny85","download_url":"https://codeload.github.com/skinny85/jilt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247622983,"owners_count":20968575,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["builder","java","java-annotation-processor","type-safety"],"created_at":"2024-10-10T22:55:46.868Z","updated_at":"2025-04-07T09:19:40.747Z","avatar_url":"https://github.com/skinny85.png","language":"Java","funding_links":[],"categories":["\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[],"readme":"# Jilt [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![See on Maven Central](https://maven-badges.herokuapp.com/maven-central/cc.jilt/jilt/badge.svg?style=flat\u0026version=1.8)](https://search.maven.org/artifact/cc.jilt/jilt/1.8/jar) [![Build Status](https://github.com/skinny85/jilt/actions/workflows/build.yaml/badge.svg)](https://github.com/skinny85/jilt/actions/workflows/build.yaml)\n\nJilt is a [Java annotation processor](https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html)\nused for automatically generating classes that implement the\n[Builder design pattern](https://en.wikipedia.org/wiki/Builder_pattern#Java).\n\nJilt's \"killer features\" compared to other tools in this same space are:\n* Support for the Staged (sometimes also called Type-Safe, or\n    Step, or Telescopic) variant of the Builder pattern.\n    For more information on the Staged Builder pattern, check out my\n    [blog article on the subject](http://endoflineblog.com/type-safe-builder-pattern-in-java-and-the-jilt-library).\n* The capability to generate Builders for any class,\n    and without requiring any modifications to the target classes'\n    source code.\n* Seamless interoperability with other annotation processors, most\n    noticeably [Lombok](https://projectlombok.org/).\n\nJilt is purely a code generator - it does not add any overhead,\nnor any runtime dependencies, to your code.\n\n#### Example\n\nGiven this class:\n\n```java\nimport org.jilt.Builder;\n\n@Builder\npublic final class Person {\n    public final String name;\n    public final boolean isAdult;\n\n    public Person(String name, boolean isAdult) {\n        this.name = name;\n        this.isAdult = isAdult;\n    }\n}\n```\n\n...Jilt will generate the following Builder code:\n\n```java\npublic class PersonBuilder {\n    public static PersonBuilder person() {\n        return new PersonBuilder();\n    }\n\n    private String name;\n    private boolean isAdult;\n\n    public PersonBuilder name(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public PersonBuilder isAdult(boolean isAdult) {\n        this.isAdult = isAdult;\n        return this;\n    }\n\n    public Person build() {\n        return new Person(name, isAdult);\n    }\n}\n```\n\nJilt also works with [Java 14+ Records](https://docs.oracle.com/en/java/javase/17/language/records.html):\n\n```java\nimport org.jilt.Builder;\n\n@Builder\npublic record Person(String name, boolean isAdult) {\n}\n```\n\nCheck out the [documentation below](#customizing-the-generated-code) for ways to customize what Jilt generates.\n\n#### Getting Jilt\n\nJilt is available from the [Maven Central](https://search.maven.org/search?q=g:cc.jilt) repository.\n\nExample Maven settings:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecc.jilt\u003c/groupId\u003e\n        \u003cartifactId\u003ejilt\u003c/artifactId\u003e\n        \u003cversion\u003e1.8\u003c/version\u003e\n        \u003cscope\u003eprovided\u003c/scope\u003e \u003c!-- Jilt is not needed at runtime --\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nExample Gradle settings:\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    // ...\n    compileOnly 'cc.jilt:jilt:1.8' // Jilt is not needed at runtime\n    annotationProcessor 'cc.jilt:jilt:1.8' // you might also need this dependency in newer Gradle versions\n}\n```\n\nIf you're not using dependency managers, you can\n[download the JAR directly](https://repo1.maven.org/maven2/cc/jilt/jilt/1.8/jilt-1.8.jar)\n(it's distributed as a self-contained JAR, you don't need any additional dependencies for it)\nand add it to your classpath.\n\n#### Customizing the generated code\n\n##### @Builder on classes\n\nWhen you place the `@Builder` annotation on the class itself,\nthe resulting Builder will have as properties all instance fields of that class\n(you can mark a field with the `@Builder.Ignore` annotation to exclude it from being added to the Builder),\nand will build the instance of that class assuming it has a constructor taking\nall of those properties as arguments, in the same order they were declared in the class.\nThis allows you to easily use Jilt with [Lombok](https://projectlombok.org/);\nfor instance, the above example could have been rewritten as:\n\n```java\nimport org.jilt.Builder;\nimport lombok.Data;\n\n@Builder\n@Data\npublic final class Person {\n    private final String name;\n    private final boolean isAdult;\n}\n```\n\n##### @Builder on constructors\n\nYou can also place the annotation on a constructor;\nin that case, the Builder properties will be the constructor parameters,\nand the instance will be created by calling the constructor.\nSo, this code will produce the same Builder as the above example:\n\n```java\nimport org.jilt.Builder;\n\npublic final class Person {\n    public final String name;\n    public final boolean isAdult;\n    private int thisFieldWillBeIgnoredByTheBuilder;\n\n    @Builder\n    public Person(String name, boolean isAdult) {\n        this.name = name;\n        this.isAdult = isAdult;\n    }\n}\n```\n\n##### @Builder on static methods\n\nFinally, you can also place the `@Builder` annotation on a (static) method.\nIn that case, the built class will be the return type of the method,\nand the Builder properties will be the method parameters,\nin the same order as they were declared in the method.\nThe instance will be created by making a call to the annotated method.\n\nThis is the most flexible way of generating Builders in Jilt -\nyou have full control of the code constructing the final instance,\nwhich allows you to do things like:\n\n* Generate Builders for classes without modifying their source code,\n    or for classes that you don't control (from libraries, for example).\n* Generate Builders for classes with non-standard ways to construct them\n    (for example, those that use setters instead of constructor parameters).\n* Customize the construction behavior - for example, add validations, or\n    default property values.\n\nHere is an example illustrating the possibilities:\n\n```java\nimport org.jilt.Builder;\n\nimport java.util.Date;\n\npublic abstract class DateFactory {\n    @Builder(packageName = \"com.example\")\n    public static Date make(int month, int day, int year) {\n        // validation\n        if (month \u003c 1 || month \u003e 12)\n            throw new IllegalArgumentException(\"month must be between 1 and 12\");\n\n        // default value\n        if (day == 0)\n            day = 1;\n\n        // non-standard construction\n        return new Date(year + 1900, month - 1, day);\n    }\n}\n```\n\nAnd you can use the generated Builder like so:\n\n```java\nimport com.example.DateBuilder;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.Date;\n\npublic class DateFactoryTest {\n    @Test\n    public void use_date_builder() {\n        Date date = DateBuilder.date()\n            .month(12)\n            .year(23)\n            .build();\n\n        Assert.assertEquals(11, date.getMonth());\n        Assert.assertEquals(1, date.getDay());\n        Assert.assertEquals(1923, date.getYear());\n    }\n}\n```\n\n##### Staged Builders\n\nAll Builders shown so far were \"regular\" Builders.\nUsing the `@Builder`'s `style` attribute, you can instead generate a\nStaged (also called Type-Safe, or Step, or Telescopic) Builder by setting\n`style` to `BuilderStyle.STAGED`.\n\nA Staged Builder generates interfaces for each property of the Builder,\nand enforces that they have to be initialized before constructing the final instance.\nThe order of construction will be exactly as the order of the properties in the Builder.\n\nFor a longer and more in-depth introduction to the Staged Builder pattern variant, check out my\n[blog article on the subject](http://endoflineblog.com/type-safe-builder-pattern-in-java-and-the-jilt-library).\n\nSo, this slightly modified code from above:\n\n```java\nimport org.jilt.Builder;\nimport org.jilt.BuilderStyle;\n\n@Builder(style = BuilderStyle.STAGED)\npublic final class Person {\n    public final String name;\n    public final boolean isAdult;\n\n    public Person(String name, boolean isAdult) {\n        this.name = name;\n        this.isAdult = isAdult;\n    }\n}\n```\n\n...generates a Builder that can be only used as follows:\n\n```java\nPerson person = PersonBuilder.person()\n    .name(\"John Doe\") // this has to be 'name' for the code to compile\n    .isAdult(true) // this has to be 'isAdult' for the code to compile\n    .build(); // this has to be 'build' for the code to compile\n```\n\n##### Optional properties\n\nWhen using Staged Builders, there are often properties that don't have to be provided\nin order to construct a valid instance of the target class -\nthe property could be optional, it could have some default, etc.\n\nWhen using the `STAGED` Builder style, you can mark a field or constructor/static method parameter\n(depending on where you placed the `@Builder` annotation) optional by annotating it with the\n`@Opt` annotation. All optional Builder properties will be grouped into a single interface\n(the same containing the `build` method), which means the client can (but doesn't have to)\nprovide them, after all the required properties have been set.\nIf a value for an optional property is not set, Jilt will construct the instance with\nthe zero-value for that property's type (`0` for `int` and other numeric types,`null` for reference types, etc.)\nas the value of the property.\n\nFor example, a Builder for this class:\n\n```java\nimport org.jilt.Builder;\nimport org.jilt.BuilderStyle;\nimport org.jilt.Opt;\n\npublic final class User {\n    public final String email, username, firstName, lastName, displayName;\n\n    @Builder(style = BuilderStyle.STAGED)\n    public User(String email, @Opt String username, String firstName,\n            String lastName, @Opt String displayName) {\n        this.email = email;\n        this.username = username == null ? email : username;\n        this.firstName = firstName;\n        this.lastName = lastName;\n        this.displayName = displayName == null\n            ? firstName + \" \" + lastName\n            : displayName;\n    }\n}\n```\n\n...can be used as follows:\n\n```java\nUser user = UserBuilder.user()\n    .email(\"jd@example.com\") // this has to be 'email' to compile\n    .firstName(\"John\") // this is not 'username', because that is an optional property\n    .lastName(\"Doe\") // this has to be 'lastName' to compile\n    .displayName(\"Johnny D\") // this could be 'username', or skipped\n    .build();\n```\n\nIn addition to the `@Opt` annotation,\na property will always be considered optional if the field or parameter it was generated from is annotated with a `@Nullable` annotation.\nAll types of `@Nullable` annotations are supported,\nincluding `javax.annotation.Nullable` from [JSR-305](https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305),\n`org.jetbrains.annotations.Nullable` from [JetBrains annotations](https://mvnrepository.com/artifact/org.jetbrains/annotations),\nand others.\n\n##### 'Staged, but preserving order' Builder style\n\nThe Staged Builder style has one downside:\nwhen evolving your API, you cannot change a required property to be optional\n(with the small exception of the last required property)\nwithout breaking existing code that uses the Builder generated when the property was required -\neven though, purely from an API perspective, that should not be a breaking change for the clients of your class.\n\nFor example, if we take the above `User` class, but with `username` being required,\nthe client code using that Builder looks something like this:\n\n```java\nUser user = UserBuilder.user()\n    .email(\"jd@example.com\")\n    .username(\"johnnyd\") // username() has to be called here, as it's not optional\n    .firstName(\"John\")\n    .lastName(\"Doe\")\n    .build();\n```\n\nHowever, if we then change `username` to be optional by annotating it with `@Opt`,\nthe above code will stop compiling,\nbecause the `username()` call can no longer happen after the call to `email()`,\nbut must instead be moved to after the call to `lastName()`.\n\nFor this reason, there is one more Builder style - `STAGED_PRESERVING_ORDER`.\nIt's very similar to `STAGED` - it only differs in the treatment of optional properties.\nInstead of bunching them all together at the end of the build process like `STAGED`,\nthis style retains the original order of the properties, but allows you to 'skip' setting\nthose that are optional, bypassing them and moving to the next required property.\nThis means that changing a required property to optional maintains backwards-compatibility\nwith any existing code that used the previously generated Builder.\n\nFor example, for the same code as the above `STAGED` example:\n\n```java\nimport org.jilt.Builder;\nimport org.jilt.BuilderStyle;\nimport org.jilt.Opt;\n\npublic final class User {\n    public final String email, username, firstName, lastName, displayName;\n\n    @Builder(style = BuilderStyle.STAGED_PRESERVING_ORDER)\n    public User(String email, @Opt String username, String firstName,\n            String lastName, @Opt String displayName) {\n        this.email = email;\n        this.username = username == null ? email : username;\n        this.firstName = firstName;\n        this.lastName = lastName;\n        this.displayName = displayName == null\n            ? firstName + \" \" + lastName\n            : displayName;\n    }\n}\n```\n\n...the generated Builder can be used like this:\n\n```java\nUser user = UserBuilder.user()\n    .email(\"jd@example.com\") // this has to be 'email' to compile - required property\n    .username(\"johnnyd\") // this will always be where username is set, regardless whether it's required or optional\n    .firstName(\"John\") // this has to be 'firstName' to compile - required property\n    .lastName(\"Doe\") // this has to be 'lastName' to compile - required property\n    .displayName(\"Johnny D\") // this will always be where displayName is set, regardless whether it's required or optional\n    .build();\n```\n\nNote that this style works best if either the class being built has a small number of properties,\nor if there is a natural order to those properties, like in the `User` example above.\nThe reason why is that there is only a single spot where a given optional property can be set\n(for example, `username()` above can only be called right after calling `email()`),\nwhich might make it difficult to find if the class has a large amount of properties without an obvious order to them.\nThis is different from the `STAGED` style,\nwhere all optional properties can be set right before calling `build()`,\nand they can be set in any order, which makes them more easily discoverable.\n\n##### Other @Builder attributes\n\nIn addition to`style`, the `@Builder` annotation has a bunch of attributes that allow you to control\npractically all aspects of the generated Builder (all of them are optional):\n\n* `className` allows you to change the generated Builder's name.\n    The default name is `\u003cBuiltClass\u003eBuilder`.\n* `packageName` allows you to change the package the generated Builder will reside in.\n    The default is for the Builder to be in the same package that the built class is in.\n* `setterPrefix` allows you to add a prefix to the names of the generated setter methods.\n    The default is to not have any prefix (the setter names will be the same as the property names).\n* `factoryMethod` allows you to change the name of the generated static factory method for\n    constructing Builder instances. The default is for the name to be equal to the un-capitalized\n    name of the built class (for example, `person` when building a `Person` class).\n* `buildMethod` allows you to change the name of the final method invoked on the Builder to\n    obtain an instance of the built class. The default name of that method is `build`.\n* `toBuilder` allows you to set the name of the static method in the Builder class that creates a new instance of it,\n    initialized with values from the provided instance of the built class.\n    This is useful for easily creating copies of the built class with only a few properties changed,\n    while still keeping the original class immutable.\n    The default value of this attribute is the empty string,\n    which means this method will not be generated.\n\n##### Functional Builder style\n\nIn addition to the Staged and 'Staged preserving order',\nthere is one more Builder style, called Functional.\nIt's inspired by a [blog article](https://glaforge.dev/posts/2024/01/16/java-functional-builder-approach)\nfrom [Guillaume Laforge](https://twitter.com/glaforge),\ncreator of the [Groovy programming language](https://www.groovy-lang.org).\n\nFunctional Builders can be thought of as a way to implement named parameters,\na language feature that Java doesn't have.\nInstead of a separate Builder instance that methods are called on,\nJilt generates a static factory method on the Builder class that returns an instance of the built class.\nArguments of that method are interfaces generated by Jilt that have a single `accept`\nmethod that take an instance of the Builder,\nand set one of the properties that will be used when creating the instance of the target class.\nEach required property will have its own interface,\nwhile optional properties all share the same interface.\n\nInstances of those interfaces are obtained by calling other static methods of the Builder class,\nwith the same name as the name of the interface, which is the same as the name of the required property\n(just uppercased in the case of the interface name).\nFor optional properties, since they share the same interface, the static methods are nested in one more class,\ncalled `Optional`, to make them more discoverable.\nYou pass the value of a given property to those static methods.\n\nFor an example, if we take the `User` class from above:\n\n```java\npackage example;\n\npublic final class User {\n    public final String email, username, firstName, lastName, displayName;\n\n    @Builder(style = BuilderStyle.FUNCTIONAL, toBuilder = \"copy\")\n    public User(String email, @Opt String username, String firstName,\n            String lastName, @Opt String displayName) {\n        this.email = email;\n        this.username = username == null ? email : username;\n        this.firstName = firstName;\n        this.lastName = lastName;\n        this.displayName = displayName == null\n            ? firstName + \" \" + lastName\n            : displayName;\n    }\n}\n```\n\nThe generated Functional Builder can be used like so:\n\n```java\nUser user = UserBuilder.user(\n    UserBuilder.email(\"jd@example.com\"), // this is required\n    UserBuilder.firstName(\"John\"), // this is required\n    UserBuilder.lastName(\"Doe\"), // this is required\n    UserBuilder.Optional.displayName(\"Johnny D\") // this is optional\n);\n```\n\nIf we use Java's [static imports](https://docs.oracle.com/javase/7/docs/technotes/guides/language/static-import.html)\nfeature, it becomes much more concise:\n\n```java\nimport static example.UserBuilder.Optional.username;\nimport static example.UserBuilder.email;\nimport static example.UserBuilder.firstName;\nimport static example.UserBuilder.lastName;\nimport static example.UserBuilder.user;\n\nUser user = user(\n    email(\"jd@example.com\"), // this is required\n    firstName(\"John\"), // this is required\n    lastName(\"Doe\"), // this is required\n    username(\"johnnyd\") // this is optional\n);\n```\n\nThe Functional `toBuilder()` method works similarly,\nbut the difference is that all properties are now considered optional,\nsince we assume the required properties will be initialized from the passed target class instance:\n\n```java\nimport static example.UserBuilder.Optional.displayName;\nimport static example.UserBuilder.email;\nimport static example.UserBuilder.firstName;\nimport static example.UserBuilder.lastName;\n\nUser user = UserBuilder.user(\n    email(\"jd@example.com\"),\n    firstName(\"John\"),\n    lastName(\"Doe\")\n);\nUser copy = UserBuilder.copy(user,\n    lastName(\"Johnson\"), // a single required property is allowed here\n    displayName(\"Johnny J\") // optional properties are also allowed here\n);\n```\n\nYou can also define a `toBuilder` instance method on your target class,\nthat delegates to the static method on the Builder class:\n\n```java\npublic final class User {\n    // ...\n\n    public User copy(UserBuilders.Setter... setters) {\n        return UserBuilder.copy(this, setters);\n    }\n}\n```\n\n##### @BuilderInterfaces annotation\n\nWhen generating a Staged or Functional Builder\n(so, when the `@Builder.style` attribute is set to anything other than `BuilderStyle.CLASSIC`,\nwhich is the default),\nyou can also place the `@BuilderInterfaces` annotation on the same element `@Builder` is on\n(so, a class, constructor, or static method).\nThis annotation is used to customize the interfaces generated to ensure the type-safety of the resulting Builder.\nIt has the following attributes (all of them are optional):\n\n* `outerName` allows you to change the name of the outer interface that the per-property interfaces\n  will be generated inside of (this is in order not to pollute the global namespace).\n  The default name is `\u003cBuilderClass\u003es` (the name of the Builder class with an \"s\" at the end) -\n  so, if we're building a `Person` class, the default name will be `PersonBuilders`.\n* `packageName` allows you to change the package the generated interfaces will reside in.\n  The default is for the interfaces to reside in the same package as the one the Builder will be generated in.\n* `innerNames` allows you to set the pattern that will be used for naming the per-property generated interfaces.\n  The character `*` in the pattern will be substituted with the (capitalized) name of the property.\n  The default name for the interfaces is simply the (capitalized) name of its corresponding property -\n  so, the same as the pattern `\"*\"`.\n* `lastInnerName` allows you to change the name of the final interface -\n  the one containing the `build` method,\n  which is invoked to obtain an instance of the target class.\n  The default name for that interface is `Optionals` for `BuilderStyle.STAGED` Builders,\n  and `Build` for `BuilderStyle.STAGED_PRESERVING_ORDER` ones.\n\n##### Meta-annotations\n\nUnder certain circumstances, you might want to re-use the same Builder configuration for multiple classes.\nFor example, you might decide that every value class in your project should use a Staged Builder,\nwith \"set\" as the prefix for setter methods, \"create\" as the name of the `build` method,\nand \"B_\" as the prefix of the per-property interface names used for the Builder stages.\nIn such situations, instead of repeating the same annotations in multiple places,\nyou can instead define your own annotation,\nand annotate it with `@Builder` and `@BuilderInterfaces`:\n\n```java\nimport org.jilt.Builder;\nimport org.jilt.BuilderInterfaces;\nimport org.jilt.BuilderStyle;\n\n@Builder(style = BuilderStyle.STAGED, setterPrefix = \"set\", buildMethod = \"create\")\n@BuilderInterfaces(innerNames = \"B_*\")\npublic @interface MyBuilder {\n}\n```\n\nAnd then, you can place this `MyBuilder` so-called _meta-annotation_ wherever `@Builder`\ncan be placed (so, a class, constructor, or static method),\nand the effect will be as if that element was annotated with the same `@Builder`\nand `@BuilderInterfaces` values as `@MyBuilder` is annotated with,\nthus avoiding any duplication in your code:\n\n```java\n@MyBuilder // uses @Builder and @BuilderInterfaces values from @MyBuilder\npublic final class MyValueClass {\n    // ...\n}\n```\n\nIf you want to change the name of the generated Builder class with a meta-annotation,\nyou typically need that name to depend on the name of the class being built,\nnot just be a constant string\n(since that's likely to cause conflicts if the meta-annotation is used more than once).\nBecause of that, similarly to `@BuilderInterfaces.innerName`,\n`@Builder.className` allows using the `*` character as a placeholder for the name of the built class,\nso you could define the meta-annotation like this:\n\n```java\nimport org.jilt.Builder;\n\n@Builder(className = \"*JiltBuilder\")\npublic @interface MyBuilder {\n}\n```\n\n**Note**: since Jilt is implemented as a Java annotation processor,\nthat means it shares the limitations common to all annotation processors.\nThe restriction that is most relevant to meta-annotation support is that only files from a single source set\n(the one that is currently being compiled) are passed to the processor. \nThis means that you can't, for example, define the meta-annotation in your main source set,\nand then use it in your tests, or package the meta-annotation in a library,\nand then depend on that library from your main project that uses Jilt --\nin both of those cases, the meta annotation won't be passed to Jilt during compilation,\nand so `@Builder` on the meta-annotation won't be recognized.\nIn order for meta-annotations to work correctly,\nthey have to be defined and used in the same source set.\n\n##### Supporting classes with private constructors\n\nIn some cases, you might want to force customers of a class to only be able to instantiate it through its Builder,\nand not through its constructor.\nWhen writing the Builder code by hand,\nyou would achieve this by making the constructor of the class private,\nand making Builder nested inside the main class.\n\nUnfortunately, annotation processors cannot modify hand-written classes,\nonly create new ones\n(yes, Lombok manages to sidestep this limitation,\nbut it does it in a way that is\n[considered a hack](https://notatube.blogspot.com/2010/11/project-lombok-trick-explained.html)),\nso Jilt cannot generate the Builder inside the main class.\n\nBecause of this, if you place `@Builder` on a private constructor or static factory method,\nJilt changes the generation behavior: the Builder class becomes abstract,\nthe fields are `protected` instead of `private`, and the `build` method becomes abstract too.\nWith this, you can extend the Builder class in a nested class of the main class and override the `build()`\nmethod to call the private constructor,\nusing the fields of the parent class as values of the properties.\nYou can also provide a static factory method in your class that returns the Builder instance,\nconventionally called just `builder()`,\nwhich allows you to make the nested class private as well.\n\nFor example, if we wanted to make the constructor of the above `User` class private,\nit would look something like this:\n\n```java\npublic final class User {\n    public final String email, username, firstName, lastName, displayName;\n\n    @Builder(style = BuilderStyle.STAGED, toBuilder = \"toBuilder\")\n    private User(String email, @Opt String username, String firstName,\n            String lastName, @Opt String displayName) {\n        this.email = email;\n        this.username = username == null ? email : username;\n        this.firstName = firstName;\n        this.lastName = lastName;\n        this.displayName = displayName == null\n            ? firstName + \" \" + lastName\n            : displayName;\n    }\n\n    private static class InnerBuilder extends UserBuilder {\n        @Override\n        public User build() {\n            return new User(email, username, firstName, lastName, displayName);\n        }\n    }\n\n    public static UserBuilders.Email builder() {\n        return new InnerBuilder();\n    }\n\n    public UserBuilder toBuilder() {\n        return UserBuilder.toBuilder(new InnerBuilder(), this);\n    }\n}\n```\n\nWith the above code, the only way to create an instance of `User`\nwould be to use the `User.builder()` static method,\nand then instantiate it through the (Staged in this case) Builder.\n\n#### Working in an IDE\n\nAnnotation processors can be a little tricky to get working correctly in an IDE.\nHere are some tips for the most popular ones:\n\n##### Intellij IDEA\n\nMake sure to enable annotation processing\n(`File` -\u003e `Settings` -\u003e `Build, Execution, Deployment` -\u003e `Compiler` -\u003e `Annotation Processors`,\ncheck the box that says `Enable annotation processing`).\nNow, the code should run fine at this point, but you might still get errors in the IDE\nbecause it can't find the sources for the generated Builder classes. In that case,\nit might be a good idea to change the radio button labelled `Store generated sources relative to`\nin that same menu screen from `Module output directory` (the default) to `Module content root`.\nIf you do that, make sure to mark the directories with the generated code as source directories\n(right click on them in the file tree -\u003e `Mark directory as` -\u003e `Sources Root` or `Test Sources Root`,\nthe names of the directories are `generated` and `generated_tests` by default).\n\n##### Eclipse\n\nEclipse is a lot more cumbersome. Right click on the project -\u003e `Properties` -\u003e `Java Compiler`\n(expand the submenus) -\u003e `Annotation Processing`, tick the `Enable project-specific settings` checkbox,\nand then `Enable annotation processing`.\nThen, go to the `Factory Path` submenu, tick the `Enable project-specific settings` checkbox there,\nand add the Jilt JAR to the Factory path.\nMake sure that the `Generated source directory` is marked as a Source Folder.\n\n#### License\n\nJilt is open-source software, released under the Apache Version 2.0 License.\nSee the [License file](License.txt) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskinny85%2Fjilt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskinny85%2Fjilt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskinny85%2Fjilt/lists"}