IntelliJ IDEA plugin that adds a Builder action to the Generate menu (Alt+Insert) which generates an inner builder class as described in Effective Java by Joshua Bloch.
Works with IntelliJ IDEA and Android Studio 2019 and later.
The Builder pattern is recommended when:
- Classes have many constructor parameters (4+)
- Many parameters are optional
- You want immutable objects with readable construction code
- You need to validate parameters before object creation
Instead of telescoping constructors or JavaBeans setters, you get:
JavaBean bean = JavaBean.newBuilder()
.foo("required")
.bar("optional")
.qux(42)
.build();Java Records (introduced in Java 16) are great for simple data carriers, but they don't replace the Builder pattern:
- No built-in builder support - Records don't generate builders automatically
- Public constructors only - You can't force clients to use a builder with records
- Limited validation - Compact constructors help, but builders offer more control over construction order
- Named parameters - Builders let you name each value; record constructors require positional arguments
Use Records when: You have simple, immutable data containers with few fields. Use Builder pattern when: You have many fields, optional parameters, complex validation, or need a fluent API.
You can even combine both - create a Builder for a Record when construction is complex:
public record Person(String firstName, String lastName, int age, String email) {
public static Builder builder() {
return new Builder();
}
public static final class Builder {
// ... generated by InnerBuilder
}
}Given a class with fields:
public class JavaBean {
private final String foo;
private String bar;
private int qux;
private Double x, y;
}The plugin generates:
public class JavaBean {
private final String foo;
private String bar;
private int qux;
private Double x, y;
private JavaBean(Builder builder) {
foo = builder.foo;
bar = builder.bar;
qux = builder.qux;
x = builder.x;
y = builder.y;
}
public static Builder newBuilder() {
return new Builder();
}
public static final class Builder {
private String foo;
private String bar;
private int qux;
private Double x;
private Double y;
private Builder() {
}
public Builder foo(String val) {
foo = val;
return this;
}
public Builder bar(String val) {
bar = val;
return this;
}
public Builder qux(int val) {
qux = val;
return this;
}
public Builder x(Double val) {
x = val;
return this;
}
public Builder y(Double val) {
y = val;
return this;
}
public JavaBean build() {
return new JavaBean(this);
}
}
}- Open Settings/Preferences → Plugins
- Select Marketplace tab
- Search for
innerbuilder - Click Install and restart IDE
- Download
innerbuilder.jarfrom releases - Open Settings/Preferences → Plugins
- Click ⚙️ → Install Plugin from Disk...
- Select the downloaded JAR file
- Restart IDE
- Place cursor inside a class
- Press
Shift+Alt+BorAlt+Insert(Generate menu) - Select Builder...
- Choose fields to include
- Configure options (see below)
- Click OK
When generating a builder for a class that already has one, the plugin will:
- ✅ Add missing fields to the Builder
- ✅ Add missing builder methods
- ✅ Update the private constructor
- ❌ Never remove existing fields or methods (safe for customizations)
| Option | Description | Example |
|---|---|---|
| Generate builder methods for final fields | Include final fields in builder (requires constructor params) | Builder(String foo) |
| Generate static builder method | Add static factory method to create Builder | MyClass.newBuilder() |
| Static builder naming | Choose naming convention for static method | newBuilder(), builder(), newMyClass(), newMyClassBuilder() |
| Builder method location | Place static method in parent class or Builder | Inside parent class / Inside Builder |
| Generate builder copy constructor | Add constructor/method to copy from existing instance | newBuilder(existingObject) |
| Use 'with...' notation | Prefix builder methods with 'with' | withName(String name) |
| Use 'set...' notation | Prefix builder methods with 'set' | setName(String name) |
| Add JSR-305 @Nonnull annotation | Add nullability annotations | @Nonnull public Builder withName(@Nonnull String name) |
| Add PMD suppression | Suppress PMD.AvoidFieldNameMatchingMethodName | @SuppressWarnings("PMD...") |
| Add Javadoc | Generate documentation for builder | /** Sets the name... */ |
| Use field names in setter | Use field name as parameter name | withName(String name) vs withName(String val) |
All options are remembered between invocations. Settings are stored per-project in IntelliJ's PropertiesComponent.
The plugin fully supports Android Studio, including:
- Field name prefixes (e.g.,
mFieldName→fieldName()method) - Code style settings are respected
- Works with Kotlin classes containing Java interop
When "Generate builder copy constructor" is enabled:
- Public fields: Accessed directly (
copy.fieldName) - Private fields with getter: Uses getter (
copy.getFieldName()) - Private fields without getter: Accessed directly (assumes same package)
// With static builder method enabled
public static Builder newBuilder(MyClass copy) {
Builder builder = new Builder();
builder.publicField = copy.publicField;
builder.privateField = copy.getPrivateField();
return builder;
}
// Without static builder method
public Builder(MyClass copy) {
this.publicField = copy.publicField;
this.privateField = copy.getPrivateField();
}| Action | Windows/Linux | macOS |
|---|---|---|
| Generate Builder | Shift+Alt+B |
⇧⌥B |
| Generate Menu | Alt+Insert |
⌘N |
| IDE | Minimum Version |
|---|---|
| IntelliJ IDEA Community | 2019.1 |
| IntelliJ IDEA Ultimate | 2019.1 |
| Android Studio | 3.4 |
- JDK 11 or later
- Maven 3.6+
# Download IntelliJ IDEA Community Edition for compilation
./prepare-build.sh
# Build the plugin
mvn package
# Output: target/innerbuilder.jarmvn test- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Licensed under the Apache License, Version 2.0.
Copyright 2013-2025 Mathias Bogaert
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- ⭐ Star the project if you find it useful
- 🐛 Report issues
- 📝 Rate on JetBrains Marketplace
- Inspired by Effective Java by Joshua Bloch
- Thanks to all contributors
