diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 5dff7aff..2f7e1ae4 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -53,6 +53,27 @@ jobs: - name: Build with Maven run: mvn -B install -Pmetrics --file pom.xml + - name: Check for uncommitted generated source changes + if: github.event_name == 'pull_request' + run: | + echo "Checking for uncommitted generated source changes..." + + # Check if there are any changes in generated-sources directories + if git diff --name-only HEAD | grep -E "target/generated-sources/"; then + echo "❌ ERROR: Found uncommitted generated source changes!" + echo "" + echo "The following generated files have changed:" + git diff --name-only HEAD | grep -E "target/generated-sources/" | sed 's/^/ /' + echo "" + echo "Please commit these changes to the repository:" + echo " git add target/generated-sources/" + echo " git commit -m \"Update generated sources\"" + echo "" + exit 1 + else + echo "✅ No uncommitted generated source changes found" + fi + - name: SonarCloud Analysis # Skip for Dependabot PRs (no access to secrets) if: github.actor != 'dependabot[bot]' diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 00000000..6dbe5dc8 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,3 @@ +# Include generated sources (they're ignored by main .gitignore) +!/target/generated-sources/ +!/target/generated-test-sources/ diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/BookDtoBuilder.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/BookDtoBuilder.java new file mode 100644 index 00000000..322928bc --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/BookDtoBuilder.java @@ -0,0 +1,516 @@ +package org.javahelpers.simple.builders.example; + +import static org.javahelpers.simple.builders.core.util.TrackedValue.changedValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.initialValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.unsetValue; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.javahelpers.simple.builders.core.util.BuilderToStringStyle; +import org.javahelpers.simple.builders.core.util.TrackedValue; + +/** + * Builder for {@code org.javahelpers.simple.builders.example.BookDto}. + *

+ * This builder provides a fluent API for creating instances of org.javahelpers.simple.builders.example.BookDto with + * method chaining and validation. Use the static {@code create()} method + * to obtain a new builder instance, configure the desired properties using + * the setter methods, and then call {@code build()} to create the final DTO. + */ +public class BookDtoBuilder { + /** + * Tracked value for title: the book title to set. + */ + private TrackedValue title = unsetValue(); + + /** + * Tracked value for author: the book author to set. + */ + private TrackedValue author = unsetValue(); + + /** + * Tracked value for isbn: the ISBN to set. + */ + private TrackedValue isbn = unsetValue(); + + /** + * Tracked value for pages: the page count to set. + */ + private TrackedValue pages = unsetValue(); + + /** + * Tracked value for price: the book price to set. + */ + private TrackedValue price = unsetValue(); + + /** + * Tracked value for exactPrice: the exact book price to set. + */ + private TrackedValue exactPrice = unsetValue(); + + /** + * Tracked value for available: true if available, false otherwise. + */ + private TrackedValue available = unsetValue(); + + /** + * Tracked value for rating: the book rating to set. + */ + private TrackedValue rating = unsetValue(); + + /** + * Tracked value for edition: the edition number to set. + */ + private TrackedValue edition = unsetValue(); + + /** + * Tracked value for salesCount: the sales count to set. + */ + private TrackedValue salesCount = unsetValue(); + + /** + * Tracked value for discount: the discount percentage to set. + */ + private TrackedValue discount = unsetValue(); + + /** + * Tracked value for category: the category code to set. + */ + private TrackedValue category = unsetValue(); + + /** + * Tracked value for publishDate: the publication date to set. + */ + private TrackedValue publishDate = unsetValue(); + + /** + * Tracked value for lastUpdated: the last update timestamp to set. + */ + private TrackedValue lastUpdated = unsetValue(); + + /** + * Tracked value for subtitle: an Optional containing the subtitle to set. + */ + private TrackedValue> subtitle = unsetValue(); + + /** + * Tracked value for tags: the list of tags to set. + */ + private TrackedValue> tags = unsetValue(); + + /** + * Tracked value for genres: the set of genres to set. + */ + private TrackedValue> genres = unsetValue(); + + /** + * Tracked value for metadata: the metadata map to set. + */ + private TrackedValue> metadata = unsetValue(); + + /** + * Tracked value for publisher: the publisher to set. + */ + private TrackedValue publisher = unsetValue(); + + /** + * Empty constructor of builder for {@code org.javahelpers.simple.builders.example.BookDto}. + */ + public BookDtoBuilder() { + } + + /** + * Initialisation of builder for {@code org.javahelpers.simple.builders.example.BookDto} by a instance. + * + * @param instance object instance for initialisiation + */ + public BookDtoBuilder(BookDto instance) { + this.title = initialValue(instance.getTitle()); + this.author = initialValue(instance.getAuthor()); + this.isbn = initialValue(instance.getIsbn()); + this.pages = initialValue(instance.getPages()); + if (this.pages.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'pages' is marked as non-null but source object has null value"); + } + this.price = initialValue(instance.getPrice()); + if (this.price.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'price' is marked as non-null but source object has null value"); + } + this.exactPrice = initialValue(instance.getExactPrice()); + this.available = initialValue(instance.isAvailable()); + if (this.available.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'available' is marked as non-null but source object has null value"); + } + this.rating = initialValue(instance.getRating()); + if (this.rating.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'rating' is marked as non-null but source object has null value"); + } + this.edition = initialValue(instance.getEdition()); + if (this.edition.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'edition' is marked as non-null but source object has null value"); + } + this.salesCount = initialValue(instance.getSalesCount()); + if (this.salesCount.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'salesCount' is marked as non-null but source object has null value"); + } + this.discount = initialValue(instance.getDiscount()); + if (this.discount.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'discount' is marked as non-null but source object has null value"); + } + this.category = initialValue(instance.getCategory()); + if (this.category.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'category' is marked as non-null but source object has null value"); + } + this.publishDate = initialValue(instance.getPublishDate()); + this.lastUpdated = initialValue(instance.getLastUpdated()); + this.subtitle = initialValue(instance.getSubtitle()); + this.tags = initialValue(instance.getTags()); + this.genres = initialValue(instance.getGenres()); + this.metadata = initialValue(instance.getMetadata()); + this.publisher = initialValue(instance.getPublisher()); + } + + /** + * Creating a new builder for {@code org.javahelpers.simple.builders.example.BookDto}. + * + * @return builder for {@code org.javahelpers.simple.builders.example.BookDto} + */ + public static BookDtoBuilder create() { + return new BookDtoBuilder(); + } + + /** + * Sets the value for author. + * + * @param author the book author to set + * @return current instance of builder + */ + public BookDtoBuilder author(String author) { + this.author = changedValue(author); + return this; + } + + /** + * Sets the value for available. + * + * @param available true if available, false otherwise + * @return current instance of builder + */ + public BookDtoBuilder available(boolean available) { + this.available = changedValue(available); + return this; + } + + /** + * Sets the value for category. + * + * @param category the category code to set + * @return current instance of builder + */ + public BookDtoBuilder category(char category) { + this.category = changedValue(category); + return this; + } + + /** + * Sets the value for discount. + * + * @param discount the discount percentage to set + * @return current instance of builder + */ + public BookDtoBuilder discount(float discount) { + this.discount = changedValue(discount); + return this; + } + + /** + * Sets the value for edition. + * + * @param edition the edition number to set + * @return current instance of builder + */ + public BookDtoBuilder edition(short edition) { + this.edition = changedValue(edition); + return this; + } + + /** + * Sets the value for exactPrice. + * + * @param exactPrice the exact book price to set + * @return current instance of builder + */ + public BookDtoBuilder exactPrice(BigDecimal exactPrice) { + this.exactPrice = changedValue(exactPrice); + return this; + } + + /** + * Sets the value for genres. + * + * @param genres the set of genres to set + * @return current instance of builder + */ + public BookDtoBuilder genres(Set genres) { + this.genres = changedValue(genres); + return this; + } + + /** + * Sets the value for isbn. + * + * @param isbn the ISBN to set + * @return current instance of builder + */ + public BookDtoBuilder isbn(String isbn) { + this.isbn = changedValue(isbn); + return this; + } + + /** + * Sets the value for lastUpdated. + * + * @param lastUpdated the last update timestamp to set + * @return current instance of builder + */ + public BookDtoBuilder lastUpdated(LocalDateTime lastUpdated) { + this.lastUpdated = changedValue(lastUpdated); + return this; + } + + /** + * Sets the value for metadata. + * + * @param metadata the metadata map to set + * @return current instance of builder + */ + public BookDtoBuilder metadata(Map metadata) { + this.metadata = changedValue(metadata); + return this; + } + + /** + * Sets the value for pages. + * + * @param pages the page count to set + * @return current instance of builder + */ + public BookDtoBuilder pages(int pages) { + this.pages = changedValue(pages); + return this; + } + + /** + * Sets the value for price. + * + * @param price the book price to set + * @return current instance of builder + */ + public BookDtoBuilder price(double price) { + this.price = changedValue(price); + return this; + } + + /** + * Sets the value for publishDate. + * + * @param publishDate the publication date to set + * @return current instance of builder + */ + public BookDtoBuilder publishDate(LocalDate publishDate) { + this.publishDate = changedValue(publishDate); + return this; + } + + /** + * Sets the value for publisher. + * + * @param publisher the publisher to set + * @return current instance of builder + */ + public BookDtoBuilder publisher(PersonDto publisher) { + this.publisher = changedValue(publisher); + return this; + } + + /** + * Sets the value for rating. + * + * @param rating the book rating to set + * @return current instance of builder + */ + public BookDtoBuilder rating(byte rating) { + this.rating = changedValue(rating); + return this; + } + + /** + * Sets the value for salesCount. + * + * @param salesCount the sales count to set + * @return current instance of builder + */ + public BookDtoBuilder salesCount(long salesCount) { + this.salesCount = changedValue(salesCount); + return this; + } + + /** + * Sets the value for subtitle. + * + * @param subtitle an Optional containing the subtitle to set + * @return current instance of builder + */ + public BookDtoBuilder subtitle(Optional subtitle) { + this.subtitle = changedValue(subtitle); + return this; + } + + /** + * Sets the value for tags. + * + * @param tags the list of tags to set + * @return current instance of builder + */ + public BookDtoBuilder tags(List tags) { + this.tags = changedValue(tags); + return this; + } + + /** + * Sets the value for title. + * + * @param title the book title to set + * @return current instance of builder + */ + public BookDtoBuilder title(String title) { + this.title = changedValue(title); + return this; + } + + /** + * Validates that the author field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if author is null or empty + */ + BookDtoBuilder validateAuthor() { + if (!author.isSet() || author.value().trim().isEmpty()) { + throw new IllegalArgumentException("Author cannot be null or empty"); + } + return this; + } + + /** + * Validates that the isbn field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if isbn is null or empty + */ + BookDtoBuilder validateIsbn() { + if (!isbn.isSet() || isbn.value().trim().isEmpty()) { + throw new IllegalArgumentException("Isbn cannot be null or empty"); + } + return this; + } + + /** + * Validates that the title field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if title is null or empty + */ + BookDtoBuilder validateTitle() { + if (!title.isSet() || title.value().trim().isEmpty()) { + throw new IllegalArgumentException("Title cannot be null or empty"); + } + return this; + } + + /** + * Builds the configured DTO instance. + */ + public BookDto build() { + if (this.pages.isSet() && this.pages.value() == null) { + throw new IllegalStateException("Field 'pages' is marked as non-null but null value was provided"); + } + if (this.price.isSet() && this.price.value() == null) { + throw new IllegalStateException("Field 'price' is marked as non-null but null value was provided"); + } + if (this.available.isSet() && this.available.value() == null) { + throw new IllegalStateException("Field 'available' is marked as non-null but null value was provided"); + } + if (this.rating.isSet() && this.rating.value() == null) { + throw new IllegalStateException("Field 'rating' is marked as non-null but null value was provided"); + } + if (this.edition.isSet() && this.edition.value() == null) { + throw new IllegalStateException("Field 'edition' is marked as non-null but null value was provided"); + } + if (this.salesCount.isSet() && this.salesCount.value() == null) { + throw new IllegalStateException("Field 'salesCount' is marked as non-null but null value was provided"); + } + if (this.discount.isSet() && this.discount.value() == null) { + throw new IllegalStateException("Field 'discount' is marked as non-null but null value was provided"); + } + if (this.category.isSet() && this.category.value() == null) { + throw new IllegalStateException("Field 'category' is marked as non-null but null value was provided"); + } + BookDto result = new BookDto(); + this.title.ifSet(result::setTitle); + this.author.ifSet(result::setAuthor); + this.isbn.ifSet(result::setIsbn); + this.pages.ifSet(result::setPages); + this.price.ifSet(result::setPrice); + this.exactPrice.ifSet(result::setExactPrice); + this.available.ifSet(result::setAvailable); + this.rating.ifSet(result::setRating); + this.edition.ifSet(result::setEdition); + this.salesCount.ifSet(result::setSalesCount); + this.discount.ifSet(result::setDiscount); + this.category.ifSet(result::setCategory); + this.publishDate.ifSet(result::setPublishDate); + this.lastUpdated.ifSet(result::setLastUpdated); + this.subtitle.ifSet(result::setSubtitle); + this.tags.ifSet(result::setTags); + this.genres.ifSet(result::setGenres); + this.metadata.ifSet(result::setMetadata); + this.publisher.ifSet(result::setPublisher); + return result; + } + + /** + * Returns a string representation of this builder, including only fields that have been set. + * + * @return string representation of the builder + */ + @Override + public String toString() { + return new ToStringBuilder(this, BuilderToStringStyle.INSTANCE) + .append("title", this.title) + .append("author", this.author) + .append("isbn", this.isbn) + .append("pages", this.pages) + .append("price", this.price) + .append("exactPrice", this.exactPrice) + .append("available", this.available) + .append("rating", this.rating) + .append("edition", this.edition) + .append("salesCount", this.salesCount) + .append("discount", this.discount) + .append("category", this.category) + .append("publishDate", this.publishDate) + .append("lastUpdated", this.lastUpdated) + .append("subtitle", this.subtitle) + .append("tags", this.tags) + .append("genres", this.genres) + .append("metadata", this.metadata) + .append("publisher", this.publisher) + .toString(); + } +} diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/JacksonIntegrationDtoBuilder.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/JacksonIntegrationDtoBuilder.java new file mode 100644 index 00000000..8e99d43f --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/JacksonIntegrationDtoBuilder.java @@ -0,0 +1,248 @@ +package org.javahelpers.simple.builders.example; + +import static org.javahelpers.simple.builders.core.util.TrackedValue.changedValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.initialValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.unsetValue; + +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.annotation.processing.Generated; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.javahelpers.simple.builders.core.annotations.BuilderImplementation; +import org.javahelpers.simple.builders.core.interfaces.IBuilderBase; +import org.javahelpers.simple.builders.core.util.BuilderToStringStyle; +import org.javahelpers.simple.builders.core.util.TrackedValue; + +/** + * Builder for {@code org.javahelpers.simple.builders.example.JacksonIntegrationDto}. + *

+ * This builder provides a fluent API for creating instances of org.javahelpers.simple.builders.example.JacksonIntegrationDto with + * method chaining and validation. Use the static {@code create()} method + * to obtain a new builder instance, configure the desired properties using + * the setter methods, and then call {@code build()} to create the final DTO. + */ +@Generated("Generated by org.javahelpers.simple.builders.processor.BuilderProcessor") +@BuilderImplementation( + forClass = JacksonIntegrationDto.class +) +@JsonPOJOBuilder( + withPrefix = "" +) +public class JacksonIntegrationDtoBuilder implements IBuilderBase { + /** + * Tracked value for name: name. + */ + private TrackedValue name = unsetValue(); + + /** + * Tracked value for age: age. + */ + private TrackedValue age = unsetValue(); + + /** + * Empty constructor of builder for {@code org.javahelpers.simple.builders.example.JacksonIntegrationDto}. + */ + public JacksonIntegrationDtoBuilder() { + } + + /** + * Initialisation of builder for {@code org.javahelpers.simple.builders.example.JacksonIntegrationDto} by a instance. + * + * @param instance object instance for initialisiation + */ + public JacksonIntegrationDtoBuilder(JacksonIntegrationDto instance) { + this.name = initialValue(instance.name()); + this.age = initialValue(instance.age()); + if (this.age.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'age' is marked as non-null but source object has null value"); + } + } + + /** + * Creating a new builder for {@code org.javahelpers.simple.builders.example.JacksonIntegrationDto}. + * + * @return builder for {@code org.javahelpers.simple.builders.example.JacksonIntegrationDto} + */ + public static JacksonIntegrationDtoBuilder create() { + return new JacksonIntegrationDtoBuilder(); + } + + /** + * Sets the value for age. + * + * @param age age + * @return current instance of builder + */ + public JacksonIntegrationDtoBuilder age(int age) { + this.age = changedValue(age); + return this; + } + + /** + * Sets the value for age by invoking the provided supplier. + * + * @param ageSupplier supplier for age + * @return current instance of builder + */ + public JacksonIntegrationDtoBuilder age(Supplier ageSupplier) { + this.age = changedValue(ageSupplier.get()); + return this; + } + + /** + * Sets the value for name. + * + * @param name name + * @return current instance of builder + */ + public JacksonIntegrationDtoBuilder name(String name) { + this.name = changedValue(name); + return this; + } + + /** + * Sets the value for name by executing the provided consumer. + * + * @param nameStringBuilderConsumer consumer providing an instance of name + * @return current instance of builder + */ + public JacksonIntegrationDtoBuilder name(Consumer nameStringBuilderConsumer) { + StringBuilder builder = new StringBuilder(); + nameStringBuilderConsumer.accept(builder); + this.name = changedValue(builder.toString()); + return this; + } + + /** + * Sets the value for name by invoking the provided supplier. + * + * @param nameSupplier supplier for name + * @return current instance of builder + */ + public JacksonIntegrationDtoBuilder name(Supplier nameSupplier) { + this.name = changedValue(nameSupplier.get()); + return this; + } + + /** + * Sets the String value for name by using String.format(format, args). + * See {@link String#format(String, Object...)} for details. + * + * @param format A format string + * @param args Arguments referenced by the format specifiers in the format string. + * @return current instance of builder + */ + public JacksonIntegrationDtoBuilder name(String format, Object... args) { + this.name = changedValue(String.format(format, args)); + return this; + } + + /** + * Validates that the name field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if name is null or empty + */ + JacksonIntegrationDtoBuilder validateName() { + if (!name.isSet() || name.value().trim().isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + return this; + } + + /** + * Conditionally applies builder modifications if the condition is true. + * + * @param condition the condition to evaluate + * @param yesCondition the consumer to apply if condition is true + * @return this builder instance + */ + public JacksonIntegrationDtoBuilder conditional(BooleanSupplier condition, + Consumer yesCondition) { + return conditional(condition, yesCondition, null); + } + + /** + * Conditionally applies builder modifications based on a condition evaluation. + * + * @param condition the condition to evaluate + * @param trueCase the consumer to apply if condition is true + * @param falseCase the consumer to apply if condition is false (can be null) + * @return this builder instance + */ + public JacksonIntegrationDtoBuilder conditional(BooleanSupplier condition, + Consumer trueCase, + Consumer falseCase) { + if (condition.getAsBoolean()) { + trueCase.accept(this); + } else if (falseCase != null) { + falseCase.accept(this); + } + return this; + } + + /** + * Builds the configured DTO instance. + */ + @Override + public JacksonIntegrationDto build() { + if (!this.age.isSet()) { + throw new IllegalStateException("Required field 'age' must be set before calling build()"); + } + if (this.age.value() == null) { + throw new IllegalStateException("Field 'age' is marked as non-null but null value was provided"); + } + JacksonIntegrationDto result = new JacksonIntegrationDto(this.name.value(), this.age.value()); + return result; + } + + /** + * Returns a string representation of this builder, including only fields that have been set. + * + * @return string representation of the builder + */ + @Override + public String toString() { + return new ToStringBuilder(this, BuilderToStringStyle.INSTANCE) + .append("name", this.name) + .append("age", this.age) + .toString(); + } + + /** + * Interface that can be implemented by the DTO to provide fluent modification methods. + */ + public interface With { + /** + * Initializes a builder from an instance of this class, using methods of this builder to change values and returns the new built object. + * + * @param b the consumer to apply modifications + * @return the modified instance + */ + default JacksonIntegrationDto with(Consumer b) { + JacksonIntegrationDtoBuilder builder; + try { + builder = new JacksonIntegrationDtoBuilder(JacksonIntegrationDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'JacksonIntegrationDtoBuilder.With' should only be implemented by classes, which could be casted to 'JacksonIntegrationDto'", ex); + } + b.accept(builder); + return builder.build(); + } + + /** + * Creates a builder initialized from this instance. + * + * @return a builder initialized with this instance's values + */ + default JacksonIntegrationDtoBuilder with() { + try { + return new JacksonIntegrationDtoBuilder(JacksonIntegrationDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'JacksonIntegrationDtoBuilder.With' should only be implemented by classes, which could be casted to 'JacksonIntegrationDto'", ex); + } + } + } +} diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/MannschaftDtoBuilder.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/MannschaftDtoBuilder.java new file mode 100644 index 00000000..99357b79 --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/MannschaftDtoBuilder.java @@ -0,0 +1,282 @@ +package org.javahelpers.simple.builders.example; + +import static org.javahelpers.simple.builders.core.util.TrackedValue.changedValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.initialValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.unsetValue; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.annotation.processing.Generated; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.javahelpers.simple.builders.core.annotations.BuilderImplementation; +import org.javahelpers.simple.builders.core.builders.HashSetBuilderWithElementBuilders; +import org.javahelpers.simple.builders.core.interfaces.IBuilderBase; +import org.javahelpers.simple.builders.core.util.BuilderToStringStyle; +import org.javahelpers.simple.builders.core.util.TrackedValue; + +/** + * Builder for {@code org.javahelpers.simple.builders.example.MannschaftDto}. + *

+ * This builder provides a fluent API for creating instances of org.javahelpers.simple.builders.example.MannschaftDto with + * method chaining and validation. Use the static {@code create()} method + * to obtain a new builder instance, configure the desired properties using + * the setter methods, and then call {@code build()} to create the final DTO. + */ +@Generated("Generated by org.javahelpers.simple.builders.processor.BuilderProcessor") +@BuilderImplementation( + forClass = MannschaftDto.class +) +public class MannschaftDtoBuilder implements IBuilderBase { + /** + * Tracked value for name: name. + */ + private TrackedValue name = unsetValue(); + + /** + * Tracked value for sponsoren: sponsoren. + */ + private TrackedValue> sponsoren = unsetValue(); + + /** + * Empty constructor of builder for {@code org.javahelpers.simple.builders.example.MannschaftDto}. + */ + public MannschaftDtoBuilder() { + } + + /** + * Initialisation of builder for {@code org.javahelpers.simple.builders.example.MannschaftDto} by a instance. + * + * @param instance object instance for initialisiation + */ + public MannschaftDtoBuilder(MannschaftDto instance) { + this.name = initialValue(instance.getName()); + this.sponsoren = initialValue(instance.getSponsoren()); + } + + /** + * Creating a new builder for {@code org.javahelpers.simple.builders.example.MannschaftDto}. + * + * @return builder for {@code org.javahelpers.simple.builders.example.MannschaftDto} + */ + public static MannschaftDtoBuilder create() { + return new MannschaftDtoBuilder(); + } + + /** + * Adds a single element to sponsoren. + * + * @param element the element to add + * @return current instance of builder + */ + public MannschaftDtoBuilder add2Sponsoren(SponsorDto element) { + Set newCollection; + if (this.sponsoren.isSet()) { + newCollection = new HashSet<>(this.sponsoren.value()); + } else { + newCollection = new HashSet<>(); + } + newCollection.add(element); + this.sponsoren = changedValue(newCollection); + return this; + } + + /** + * Sets the value for name. + * + * @param name name + * @return current instance of builder + */ + public MannschaftDtoBuilder name(String name) { + this.name = changedValue(name); + return this; + } + + /** + * Sets the value for name by executing the provided consumer. + * + * @param nameStringBuilderConsumer consumer providing an instance of name + * @return current instance of builder + */ + public MannschaftDtoBuilder name(Consumer nameStringBuilderConsumer) { + StringBuilder builder = new StringBuilder(); + nameStringBuilderConsumer.accept(builder); + this.name = changedValue(builder.toString()); + return this; + } + + /** + * Sets the value for name by invoking the provided supplier. + * + * @param nameSupplier supplier for name + * @return current instance of builder + */ + public MannschaftDtoBuilder name(Supplier nameSupplier) { + this.name = changedValue(nameSupplier.get()); + return this; + } + + /** + * Sets the String value for name by using String.format(format, args). + * See {@link String#format(String, Object...)} for details. + * + * @param format A format string + * @param args Arguments referenced by the format specifiers in the format string. + * @return current instance of builder + */ + public MannschaftDtoBuilder name(String format, Object... args) { + this.name = changedValue(String.format(format, args)); + return this; + } + + /** + * Sets the value for sponsoren. + * + * @param sponsoren sponsoren + * @return current instance of builder + */ + public MannschaftDtoBuilder sponsoren(SponsorDto... sponsoren) { + this.sponsoren = changedValue(Set.of(sponsoren)); + return this; + } + + /** + * Sets the value for sponsoren. + * + * @param sponsoren sponsoren + * @return current instance of builder + */ + public MannschaftDtoBuilder sponsoren(Set sponsoren) { + this.sponsoren = changedValue(sponsoren); + return this; + } + + /** + * Sets the value for sponsoren using a builder consumer that produces the value. + * + * @param sponsorenBuilderConsumer consumer providing an instance of a builder for sponsoren + * @return current instance of builder + */ + public MannschaftDtoBuilder sponsoren( + Consumer> sponsorenBuilderConsumer) { + HashSetBuilderWithElementBuilders builder = this.sponsoren.isSet() ? new HashSetBuilderWithElementBuilders(this.sponsoren.value(), SponsorDtoBuilder::create) : new HashSetBuilderWithElementBuilders(SponsorDtoBuilder::create); + sponsorenBuilderConsumer.accept(builder); + this.sponsoren = changedValue(builder.build()); + return this; + } + + /** + * Sets the value for sponsoren by invoking the provided supplier. + * + * @param sponsorenSupplier supplier for sponsoren + * @return current instance of builder + */ + public MannschaftDtoBuilder sponsoren(Supplier> sponsorenSupplier) { + this.sponsoren = changedValue(sponsorenSupplier.get()); + return this; + } + + /** + * Validates that the name field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if name is null or empty + */ + MannschaftDtoBuilder validateName() { + if (!name.isSet() || name.value().trim().isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + return this; + } + + /** + * Conditionally applies builder modifications if the condition is true. + * + * @param condition the condition to evaluate + * @param yesCondition the consumer to apply if condition is true + * @return this builder instance + */ + public MannschaftDtoBuilder conditional(BooleanSupplier condition, + Consumer yesCondition) { + return conditional(condition, yesCondition, null); + } + + /** + * Conditionally applies builder modifications based on a condition evaluation. + * + * @param condition the condition to evaluate + * @param trueCase the consumer to apply if condition is true + * @param falseCase the consumer to apply if condition is false (can be null) + * @return this builder instance + */ + public MannschaftDtoBuilder conditional(BooleanSupplier condition, + Consumer trueCase, Consumer falseCase) { + if (condition.getAsBoolean()) { + trueCase.accept(this); + } else if (falseCase != null) { + falseCase.accept(this); + } + return this; + } + + /** + * Builds the configured DTO instance. + */ + @Override + public MannschaftDto build() { + MannschaftDto result = new MannschaftDto(); + this.name.ifSet(result::setName); + this.sponsoren.ifSet(result::setSponsoren); + return result; + } + + /** + * Returns a string representation of this builder, including only fields that have been set. + * + * @return string representation of the builder + */ + @Override + public String toString() { + return new ToStringBuilder(this, BuilderToStringStyle.INSTANCE) + .append("name", this.name) + .append("sponsoren", this.sponsoren) + .toString(); + } + + /** + * Interface that can be implemented by the DTO to provide fluent modification methods. + */ + public interface With { + /** + * Initializes a builder from an instance of this class, using methods of this builder to change values and returns the new built object. + * + * @param b the consumer to apply modifications + * @return the modified instance + */ + default MannschaftDto with(Consumer b) { + MannschaftDtoBuilder builder; + try { + builder = new MannschaftDtoBuilder(MannschaftDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'MannschaftDtoBuilder.With' should only be implemented by classes, which could be casted to 'MannschaftDto'", ex); + } + b.accept(builder); + return builder.build(); + } + + /** + * Creates a builder initialized from this instance. + * + * @return a builder initialized with this instance's values + */ + default MannschaftDtoBuilder with() { + try { + return new MannschaftDtoBuilder(MannschaftDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'MannschaftDtoBuilder.With' should only be implemented by classes, which could be casted to 'MannschaftDto'", ex); + } + } + } +} diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/PersonDtoBuilder.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/PersonDtoBuilder.java new file mode 100644 index 00000000..2ec212f0 --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/PersonDtoBuilder.java @@ -0,0 +1,407 @@ +package org.javahelpers.simple.builders.example; + +import static org.javahelpers.simple.builders.core.util.TrackedValue.changedValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.initialValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.unsetValue; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.annotation.processing.Generated; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.javahelpers.simple.builders.core.annotations.BuilderImplementation; +import org.javahelpers.simple.builders.core.builders.ArrayListBuilder; +import org.javahelpers.simple.builders.core.interfaces.IBuilderBase; +import org.javahelpers.simple.builders.core.util.BuilderToStringStyle; +import org.javahelpers.simple.builders.core.util.TrackedValue; + +/** + * Builder for {@code org.javahelpers.simple.builders.example.PersonDto}. + *

+ * This builder provides a fluent API for creating instances of org.javahelpers.simple.builders.example.PersonDto with + * method chaining and validation. Use the static {@code create()} method + * to obtain a new builder instance, configure the desired properties using + * the setter methods, and then call {@code build()} to create the final DTO. + */ +@Generated("Generated by org.javahelpers.simple.builders.processor.BuilderProcessor") +@BuilderImplementation( + forClass = PersonDto.class +) +public class PersonDtoBuilder implements IBuilderBase { + /** + * Tracked value for name: name. + */ + private TrackedValue name = unsetValue(); + + /** + * Tracked value for nickNames: nickNames. + */ + private TrackedValue> nickNames = unsetValue(); + + /** + * Tracked value for nickNames2: nickNames2. + */ + private TrackedValue nickNames2 = unsetValue(); + + /** + * Tracked value for birthdate: birthdate. + */ + private TrackedValue birthdate = unsetValue(); + + /** + * Tracked value for mannschaft: mannschaft. + */ + private TrackedValue mannschaft = unsetValue(); + + /** + * Empty constructor of builder for {@code org.javahelpers.simple.builders.example.PersonDto}. + */ + public PersonDtoBuilder() { + } + + /** + * Initialisation of builder for {@code org.javahelpers.simple.builders.example.PersonDto} by a instance. + * + * @param instance object instance for initialisiation + */ + public PersonDtoBuilder(PersonDto instance) { + this.name = initialValue(instance.getName()); + this.nickNames = initialValue(instance.getNickNames()); + this.birthdate = initialValue(instance.getBirthdate()); + this.mannschaft = initialValue(instance.getMannschaft()); + } + + /** + * Creating a new builder for {@code org.javahelpers.simple.builders.example.PersonDto}. + * + * @return builder for {@code org.javahelpers.simple.builders.example.PersonDto} + */ + public static PersonDtoBuilder create() { + return new PersonDtoBuilder(); + } + + /** + * Adds a single element to nickNames. + * + * @param element the element to add + * @return current instance of builder + */ + public PersonDtoBuilder add2NickNames(String element) { + List newCollection; + if (this.nickNames.isSet()) { + newCollection = new ArrayList<>(this.nickNames.value()); + } else { + newCollection = new ArrayList<>(); + } + newCollection.add(element); + this.nickNames = changedValue(newCollection); + return this; + } + + /** + * Sets the value for birthdate. + * + * @param birthdate birthdate + * @return current instance of builder + */ + public PersonDtoBuilder birthdate(LocalDate birthdate) { + this.birthdate = changedValue(birthdate); + return this; + } + + /** + * Sets the value for birthdate by invoking the provided supplier. + * + * @param birthdateSupplier supplier for birthdate + * @return current instance of builder + */ + public PersonDtoBuilder birthdate(Supplier birthdateSupplier) { + this.birthdate = changedValue(birthdateSupplier.get()); + return this; + } + + /** + * Sets the value for mannschaft. + * + * @param mannschaft mannschaft + * @return current instance of builder + */ + public PersonDtoBuilder mannschaft(MannschaftDto mannschaft) { + this.mannschaft = changedValue(mannschaft); + return this; + } + + /** + * Sets the value for mannschaft using a builder consumer that produces the value. + * + * @param mannschaftBuilderConsumer consumer providing an instance of a builder for mannschaft + * @return current instance of builder + */ + public PersonDtoBuilder mannschaft(Consumer mannschaftBuilderConsumer) { + MannschaftDtoBuilder builder = this.mannschaft.isSet() ? new MannschaftDtoBuilder(this.mannschaft.value()) : new MannschaftDtoBuilder(); + mannschaftBuilderConsumer.accept(builder); + this.mannschaft = changedValue(builder.build()); + return this; + } + + /** + * Sets the value for mannschaft by invoking the provided supplier. + * + * @param mannschaftSupplier supplier for mannschaft + * @return current instance of builder + */ + public PersonDtoBuilder mannschaft(Supplier mannschaftSupplier) { + this.mannschaft = changedValue(mannschaftSupplier.get()); + return this; + } + + /** + * Sets the value for name. + * + * @param name name + * @return current instance of builder + */ + public PersonDtoBuilder name(String name) { + this.name = changedValue(name); + return this; + } + + /** + * Sets the value for name by executing the provided consumer. + * + * @param nameStringBuilderConsumer consumer providing an instance of name + * @return current instance of builder + */ + public PersonDtoBuilder name(Consumer nameStringBuilderConsumer) { + StringBuilder builder = new StringBuilder(); + nameStringBuilderConsumer.accept(builder); + this.name = changedValue(builder.toString()); + return this; + } + + /** + * Sets the value for name by invoking the provided supplier. + * + * @param nameSupplier supplier for name + * @return current instance of builder + */ + public PersonDtoBuilder name(Supplier nameSupplier) { + this.name = changedValue(nameSupplier.get()); + return this; + } + + /** + * Sets the String value for name by using String.format(format, args). + * See {@link String#format(String, Object...)} for details. + * + * @param format A format string + * @param args Arguments referenced by the format specifiers in the format string. + * @return current instance of builder + */ + public PersonDtoBuilder name(String format, Object... args) { + this.name = changedValue(String.format(format, args)); + return this; + } + + /** + * Sets the value for nickNames. + * + * @param nickNames nickNames + * @return current instance of builder + */ + public PersonDtoBuilder nickNames(String... nickNames) { + this.nickNames = changedValue(List.of(nickNames)); + return this; + } + + /** + * Sets the value for nickNames. + * + * @param nickNames nickNames + * @return current instance of builder + */ + public PersonDtoBuilder nickNames(List nickNames) { + this.nickNames = changedValue(nickNames); + return this; + } + + /** + * Sets the value for nickNames using a builder consumer that produces the value. + * + * @param nickNamesBuilderConsumer consumer providing an instance of a builder for nickNames + * @return current instance of builder + */ + public PersonDtoBuilder nickNames(Consumer> nickNamesBuilderConsumer) { + ArrayListBuilder builder = this.nickNames.isSet() ? new ArrayListBuilder(this.nickNames.value()) : new ArrayListBuilder(); + nickNamesBuilderConsumer.accept(builder); + this.nickNames = changedValue(builder.build()); + return this; + } + + /** + * Sets the value for nickNames by invoking the provided supplier. + * + * @param nickNamesSupplier supplier for nickNames + * @return current instance of builder + */ + public PersonDtoBuilder nickNames(Supplier> nickNamesSupplier) { + this.nickNames = changedValue(nickNamesSupplier.get()); + return this; + } + + /** + * Sets the value for nickNames2. + * + * @param nickNames2 nickNames2 + * @return current instance of builder + */ + public PersonDtoBuilder nickNames2(String... nickNames2) { + this.nickNames2 = changedValue(nickNames2); + return this; + } + + /** + * Sets the value for nickNames2. + * + * @param nickNames2 nickNames2 + * @return current instance of builder + */ + public PersonDtoBuilder nickNames2(List nickNames2) { + this.nickNames2 = changedValue(nickNames2.toArray(new String[0])); + return this; + } + + /** + * Sets the value for nickNames2 using the fluent builder consumer. + * + * @param nickNames2BuilderConsumer consumer for nickNames2 + * @return current instance of builder + */ + public PersonDtoBuilder nickNames2(Consumer> nickNames2BuilderConsumer) { + ArrayListBuilder builder = this.nickNames2.isSet() ? new ArrayListBuilder(java.util.List.of(this.nickNames2.value())) : new ArrayListBuilder(); + nickNames2BuilderConsumer.accept(builder); + this.nickNames2 = changedValue(builder.build().toArray(new String[0])); + return this; + } + + /** + * Sets the value for nickNames2 by invoking the provided supplier. + * + * @param nickNames2Supplier supplier for nickNames2 + * @return current instance of builder + */ + public PersonDtoBuilder nickNames2(Supplier nickNames2Supplier) { + this.nickNames2 = changedValue(nickNames2Supplier.get()); + return this; + } + + /** + * Validates that the name field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if name is null or empty + */ + PersonDtoBuilder validateName() { + if (!name.isSet() || name.value().trim().isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + return this; + } + + /** + * Conditionally applies builder modifications if the condition is true. + * + * @param condition the condition to evaluate + * @param yesCondition the consumer to apply if condition is true + * @return this builder instance + */ + public PersonDtoBuilder conditional(BooleanSupplier condition, + Consumer yesCondition) { + return conditional(condition, yesCondition, null); + } + + /** + * Conditionally applies builder modifications based on a condition evaluation. + * + * @param condition the condition to evaluate + * @param trueCase the consumer to apply if condition is true + * @param falseCase the consumer to apply if condition is false (can be null) + * @return this builder instance + */ + public PersonDtoBuilder conditional(BooleanSupplier condition, + Consumer trueCase, Consumer falseCase) { + if (condition.getAsBoolean()) { + trueCase.accept(this); + } else if (falseCase != null) { + falseCase.accept(this); + } + return this; + } + + /** + * Builds the configured DTO instance. + */ + @Override + public PersonDto build() { + PersonDto result = new PersonDto(this.name.value()); + this.nickNames.ifSet(result::setNickNames); + this.nickNames2.ifSet(result::setNickNames2); + this.birthdate.ifSet(result::setBirthdate); + this.mannschaft.ifSet(result::setMannschaft); + return result; + } + + /** + * Returns a string representation of this builder, including only fields that have been set. + * + * @return string representation of the builder + */ + @Override + public String toString() { + return new ToStringBuilder(this, BuilderToStringStyle.INSTANCE) + .append("name", this.name) + .append("nickNames", this.nickNames) + .append("nickNames2", this.nickNames2) + .append("birthdate", this.birthdate) + .append("mannschaft", this.mannschaft) + .toString(); + } + + /** + * Interface that can be implemented by the DTO to provide fluent modification methods. + */ + public interface With { + /** + * Initializes a builder from an instance of this class, using methods of this builder to change values and returns the new built object. + * + * @param b the consumer to apply modifications + * @return the modified instance + */ + default PersonDto with(Consumer b) { + PersonDtoBuilder builder; + try { + builder = new PersonDtoBuilder(PersonDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'PersonDtoBuilder.With' should only be implemented by classes, which could be casted to 'PersonDto'", ex); + } + b.accept(builder); + return builder.build(); + } + + /** + * Creates a builder initialized from this instance. + * + * @return a builder initialized with this instance's values + */ + default PersonDtoBuilder with() { + try { + return new PersonDtoBuilder(PersonDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'PersonDtoBuilder.With' should only be implemented by classes, which could be casted to 'PersonDto'", ex); + } + } + } +} diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/ProductRecordBuilder.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/ProductRecordBuilder.java new file mode 100644 index 00000000..a34f67ec --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/ProductRecordBuilder.java @@ -0,0 +1,311 @@ +package org.javahelpers.simple.builders.example; + +import static org.javahelpers.simple.builders.core.util.TrackedValue.changedValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.initialValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.unsetValue; + +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.annotation.processing.Generated; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.javahelpers.simple.builders.core.annotations.BuilderImplementation; +import org.javahelpers.simple.builders.core.interfaces.IBuilderBase; +import org.javahelpers.simple.builders.core.util.BuilderToStringStyle; +import org.javahelpers.simple.builders.core.util.TrackedValue; + +/** + * Builder for {@code org.javahelpers.simple.builders.example.ProductRecord}. + *

+ * This builder provides a fluent API for creating instances of org.javahelpers.simple.builders.example.ProductRecord with + * method chaining and validation. Use the static {@code create()} method + * to obtain a new builder instance, configure the desired properties using + * the setter methods, and then call {@code build()} to create the final DTO. + */ +@Generated("Generated by org.javahelpers.simple.builders.processor.BuilderProcessor") +@BuilderImplementation( + forClass = ProductRecord.class +) +public class ProductRecordBuilder implements IBuilderBase { + /** + * Tracked value for name: name. + */ + private TrackedValue name = unsetValue(); + + /** + * Tracked value for price: price. + */ + private TrackedValue price = unsetValue(); + + /** + * Tracked value for category: category. + */ + private TrackedValue category = unsetValue(); + + /** + * Empty constructor of builder for {@code org.javahelpers.simple.builders.example.ProductRecord}. + */ + public ProductRecordBuilder() { + } + + /** + * Initialisation of builder for {@code org.javahelpers.simple.builders.example.ProductRecord} by a instance. + * + * @param instance object instance for initialisiation + */ + public ProductRecordBuilder(ProductRecord instance) { + this.name = initialValue(instance.name()); + this.price = initialValue(instance.price()); + if (this.price.value() == null) { + throw new IllegalArgumentException("Cannot initialize builder from instance: field 'price' is marked as non-null but source object has null value"); + } + this.category = initialValue(instance.category()); + } + + /** + * Creating a new builder for {@code org.javahelpers.simple.builders.example.ProductRecord}. + * + * @return builder for {@code org.javahelpers.simple.builders.example.ProductRecord} + */ + public static ProductRecordBuilder create() { + return new ProductRecordBuilder(); + } + + /** + * Sets the value for category. + * + * @param category category + * @return current instance of builder + */ + public ProductRecordBuilder category(String category) { + this.category = changedValue(category); + return this; + } + + /** + * Sets the value for category by executing the provided consumer. + * + * @param categoryStringBuilderConsumer consumer providing an instance of category + * @return current instance of builder + */ + public ProductRecordBuilder category(Consumer categoryStringBuilderConsumer) { + StringBuilder builder = new StringBuilder(); + categoryStringBuilderConsumer.accept(builder); + this.category = changedValue(builder.toString()); + return this; + } + + /** + * Sets the value for category by invoking the provided supplier. + * + * @param categorySupplier supplier for category + * @return current instance of builder + */ + public ProductRecordBuilder category(Supplier categorySupplier) { + this.category = changedValue(categorySupplier.get()); + return this; + } + + /** + * Sets the String value for category by using String.format(format, args). + * See {@link String#format(String, Object...)} for details. + * + * @param format A format string + * @param args Arguments referenced by the format specifiers in the format string. + * @return current instance of builder + */ + public ProductRecordBuilder category(String format, Object... args) { + this.category = changedValue(String.format(format, args)); + return this; + } + + /** + * Sets the value for name. + * + * @param name name + * @return current instance of builder + */ + public ProductRecordBuilder name(String name) { + this.name = changedValue(name); + return this; + } + + /** + * Sets the value for name by executing the provided consumer. + * + * @param nameStringBuilderConsumer consumer providing an instance of name + * @return current instance of builder + */ + public ProductRecordBuilder name(Consumer nameStringBuilderConsumer) { + StringBuilder builder = new StringBuilder(); + nameStringBuilderConsumer.accept(builder); + this.name = changedValue(builder.toString()); + return this; + } + + /** + * Sets the value for name by invoking the provided supplier. + * + * @param nameSupplier supplier for name + * @return current instance of builder + */ + public ProductRecordBuilder name(Supplier nameSupplier) { + this.name = changedValue(nameSupplier.get()); + return this; + } + + /** + * Sets the String value for name by using String.format(format, args). + * See {@link String#format(String, Object...)} for details. + * + * @param format A format string + * @param args Arguments referenced by the format specifiers in the format string. + * @return current instance of builder + */ + public ProductRecordBuilder name(String format, Object... args) { + this.name = changedValue(String.format(format, args)); + return this; + } + + /** + * Sets the value for price. + * + * @param price price + * @return current instance of builder + */ + public ProductRecordBuilder price(double price) { + this.price = changedValue(price); + return this; + } + + /** + * Sets the value for price by invoking the provided supplier. + * + * @param priceSupplier supplier for price + * @return current instance of builder + */ + public ProductRecordBuilder price(Supplier priceSupplier) { + this.price = changedValue(priceSupplier.get()); + return this; + } + + /** + * Validates that the category field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if category is null or empty + */ + ProductRecordBuilder validateCategory() { + if (!category.isSet() || category.value().trim().isEmpty()) { + throw new IllegalArgumentException("Category cannot be null or empty"); + } + return this; + } + + /** + * Validates that the name field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if name is null or empty + */ + ProductRecordBuilder validateName() { + if (!name.isSet() || name.value().trim().isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + return this; + } + + /** + * Conditionally applies builder modifications if the condition is true. + * + * @param condition the condition to evaluate + * @param yesCondition the consumer to apply if condition is true + * @return this builder instance + */ + public ProductRecordBuilder conditional(BooleanSupplier condition, + Consumer yesCondition) { + return conditional(condition, yesCondition, null); + } + + /** + * Conditionally applies builder modifications based on a condition evaluation. + * + * @param condition the condition to evaluate + * @param trueCase the consumer to apply if condition is true + * @param falseCase the consumer to apply if condition is false (can be null) + * @return this builder instance + */ + public ProductRecordBuilder conditional(BooleanSupplier condition, + Consumer trueCase, Consumer falseCase) { + if (condition.getAsBoolean()) { + trueCase.accept(this); + } else if (falseCase != null) { + falseCase.accept(this); + } + return this; + } + + /** + * Builds the configured DTO instance. + */ + @Override + public ProductRecord build() { + if (!this.price.isSet()) { + throw new IllegalStateException("Required field 'price' must be set before calling build()"); + } + if (this.price.value() == null) { + throw new IllegalStateException("Field 'price' is marked as non-null but null value was provided"); + } + ProductRecord result = new ProductRecord(this.name.value(), this.price.value(), this.category.value()); + return result; + } + + /** + * Returns a string representation of this builder, including only fields that have been set. + * + * @return string representation of the builder + */ + @Override + public String toString() { + return new ToStringBuilder(this, BuilderToStringStyle.INSTANCE) + .append("name", this.name) + .append("price", this.price) + .append("category", this.category) + .toString(); + } + + /** + * Interface that can be implemented by the DTO to provide fluent modification methods. + */ + public interface With { + /** + * Initializes a builder from an instance of this class, using methods of this builder to change values and returns the new built object. + * + * @param b the consumer to apply modifications + * @return the modified instance + */ + default ProductRecord with(Consumer b) { + ProductRecordBuilder builder; + try { + builder = new ProductRecordBuilder(ProductRecord.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'ProductRecordBuilder.With' should only be implemented by classes, which could be casted to 'ProductRecord'", ex); + } + b.accept(builder); + return builder.build(); + } + + /** + * Creates a builder initialized from this instance. + * + * @return a builder initialized with this instance's values + */ + default ProductRecordBuilder with() { + try { + return new ProductRecordBuilder(ProductRecord.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'ProductRecordBuilder.With' should only be implemented by classes, which could be casted to 'ProductRecord'", ex); + } + } + } +} diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/SimpleBuildersJacksonModule.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/SimpleBuildersJacksonModule.java new file mode 100644 index 00000000..5766b3ae --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/SimpleBuildersJacksonModule.java @@ -0,0 +1,16 @@ +package org.javahelpers.simple.builders.example; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.module.SimpleModule; + +public class SimpleBuildersJacksonModule extends SimpleModule { + public SimpleBuildersJacksonModule() { + setMixInAnnotation(JacksonIntegrationDto.class, JacksonIntegrationDtoMixin.class); + } + + @JsonDeserialize( + builder = JacksonIntegrationDtoBuilder.class + ) + private interface JacksonIntegrationDtoMixin { + } +} diff --git a/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/SponsorDtoBuilder.java b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/SponsorDtoBuilder.java new file mode 100644 index 00000000..861c1167 --- /dev/null +++ b/example/target/generated-sources/annotations/org/javahelpers/simple/builders/example/SponsorDtoBuilder.java @@ -0,0 +1,206 @@ +package org.javahelpers.simple.builders.example; + +import static org.javahelpers.simple.builders.core.util.TrackedValue.changedValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.initialValue; +import static org.javahelpers.simple.builders.core.util.TrackedValue.unsetValue; + +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.annotation.processing.Generated; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.javahelpers.simple.builders.core.annotations.BuilderImplementation; +import org.javahelpers.simple.builders.core.interfaces.IBuilderBase; +import org.javahelpers.simple.builders.core.util.BuilderToStringStyle; +import org.javahelpers.simple.builders.core.util.TrackedValue; + +/** + * Builder for {@code org.javahelpers.simple.builders.example.SponsorDto}. + *

+ * This builder provides a fluent API for creating instances of org.javahelpers.simple.builders.example.SponsorDto with + * method chaining and validation. Use the static {@code create()} method + * to obtain a new builder instance, configure the desired properties using + * the setter methods, and then call {@code build()} to create the final DTO. + */ +@Generated("Generated by org.javahelpers.simple.builders.processor.BuilderProcessor") +@BuilderImplementation( + forClass = SponsorDto.class +) +public class SponsorDtoBuilder implements IBuilderBase { + /** + * Tracked value for name: name. + */ + private TrackedValue name = unsetValue(); + + /** + * Empty constructor of builder for {@code org.javahelpers.simple.builders.example.SponsorDto}. + */ + public SponsorDtoBuilder() { + } + + /** + * Initialisation of builder for {@code org.javahelpers.simple.builders.example.SponsorDto} by a instance. + * + * @param instance object instance for initialisiation + */ + public SponsorDtoBuilder(SponsorDto instance) { + this.name = initialValue(instance.getName()); + } + + /** + * Creating a new builder for {@code org.javahelpers.simple.builders.example.SponsorDto}. + * + * @return builder for {@code org.javahelpers.simple.builders.example.SponsorDto} + */ + public static SponsorDtoBuilder create() { + return new SponsorDtoBuilder(); + } + + /** + * Sets the value for name. + * + * @param name name + * @return current instance of builder + */ + public SponsorDtoBuilder name(String name) { + this.name = changedValue(name); + return this; + } + + /** + * Sets the value for name by executing the provided consumer. + * + * @param nameStringBuilderConsumer consumer providing an instance of name + * @return current instance of builder + */ + public SponsorDtoBuilder name(Consumer nameStringBuilderConsumer) { + StringBuilder builder = new StringBuilder(); + nameStringBuilderConsumer.accept(builder); + this.name = changedValue(builder.toString()); + return this; + } + + /** + * Sets the value for name by invoking the provided supplier. + * + * @param nameSupplier supplier for name + * @return current instance of builder + */ + public SponsorDtoBuilder name(Supplier nameSupplier) { + this.name = changedValue(nameSupplier.get()); + return this; + } + + /** + * Sets the String value for name by using String.format(format, args). + * See {@link String#format(String, Object...)} for details. + * + * @param format A format string + * @param args Arguments referenced by the format specifiers in the format string. + * @return current instance of builder + */ + public SponsorDtoBuilder name(String format, Object... args) { + this.name = changedValue(String.format(format, args)); + return this; + } + + /** + * Validates that the name field is not null or empty. + * + * @return this builder instance for chaining + * @throws IllegalArgumentException if name is null or empty + */ + SponsorDtoBuilder validateName() { + if (!name.isSet() || name.value().trim().isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + return this; + } + + /** + * Conditionally applies builder modifications if the condition is true. + * + * @param condition the condition to evaluate + * @param yesCondition the consumer to apply if condition is true + * @return this builder instance + */ + public SponsorDtoBuilder conditional(BooleanSupplier condition, + Consumer yesCondition) { + return conditional(condition, yesCondition, null); + } + + /** + * Conditionally applies builder modifications based on a condition evaluation. + * + * @param condition the condition to evaluate + * @param trueCase the consumer to apply if condition is true + * @param falseCase the consumer to apply if condition is false (can be null) + * @return this builder instance + */ + public SponsorDtoBuilder conditional(BooleanSupplier condition, + Consumer trueCase, Consumer falseCase) { + if (condition.getAsBoolean()) { + trueCase.accept(this); + } else if (falseCase != null) { + falseCase.accept(this); + } + return this; + } + + /** + * Builds the configured DTO instance. + */ + @Override + public SponsorDto build() { + SponsorDto result = new SponsorDto(); + this.name.ifSet(result::setName); + return result; + } + + /** + * Returns a string representation of this builder, including only fields that have been set. + * + * @return string representation of the builder + */ + @Override + public String toString() { + return new ToStringBuilder(this, BuilderToStringStyle.INSTANCE) + .append("name", this.name) + .toString(); + } + + /** + * Interface that can be implemented by the DTO to provide fluent modification methods. + */ + public interface With { + /** + * Initializes a builder from an instance of this class, using methods of this builder to change values and returns the new built object. + * + * @param b the consumer to apply modifications + * @return the modified instance + */ + default SponsorDto with(Consumer b) { + SponsorDtoBuilder builder; + try { + builder = new SponsorDtoBuilder(SponsorDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'SponsorDtoBuilder.With' should only be implemented by classes, which could be casted to 'SponsorDto'", ex); + } + b.accept(builder); + return builder.build(); + } + + /** + * Creates a builder initialized from this instance. + * + * @return a builder initialized with this instance's values + */ + default SponsorDtoBuilder with() { + try { + return new SponsorDtoBuilder(SponsorDto.class.cast(this)); + } catch (ClassCastException ex) { + throw new IllegalArgumentException("The interface 'SponsorDtoBuilder.With' should only be implemented by classes, which could be casted to 'SponsorDto'", ex); + } + } + } +}