From a715992b4e96dfb0a636ebbe1b79eec558ef6f8d Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Sun, 29 Mar 2026 21:59:14 +0200 Subject: [PATCH 1/8] Changing implementation to use a dto for javadoc --- .../roaster/RoasterCodeGenerator.java | 55 ++-- .../model/core/BuilderDefinitionDto.java | 8 +- .../processor/model/core/FieldDto.java | 11 +- .../processor/model/javadoc/JavadocDto.java | 272 ++++++++++++++++++ .../model/javadoc/JavadocParser.java | 143 +++++++++ .../model/javadoc/JavadocTagDto.java | 69 +++++ .../processor/model/method/MethodDto.java | 7 +- .../processor/model/type/NestedTypeDto.java | 7 +- 8 files changed, 523 insertions(+), 49 deletions(-) create mode 100644 processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java create mode 100644 processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java create mode 100644 processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java index bd86c0f0..05a915ac 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java @@ -55,6 +55,9 @@ import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.integration.JacksonModuleDefinitionDto; import org.javahelpers.simple.builders.processor.model.integration.JacksonModuleEntryDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocParser; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocTagDto; import org.javahelpers.simple.builders.processor.model.method.MethodCodePlaceholder; import org.javahelpers.simple.builders.processor.model.method.MethodCodeTypePlaceholder; import org.javahelpers.simple.builders.processor.model.method.MethodDto; @@ -211,7 +214,7 @@ private void applyJavaDocToField(JavaDocSource javaDoc, FieldDto fieldDto) { "Tracked value for %s: %s." .formatted( fieldDto.getFieldNameInBuilder(), - StringUtils.defaultString(fieldDto.getJavaDoc()))); + StringUtils.defaultString(JavadocParser.toString(fieldDto.getJavaDoc())))); } private void appendConstructors(JavaClassSource source, BuilderDefinitionDto builderDef) { @@ -234,7 +237,7 @@ private void appendEmptyConstructor( constructor.setBody(""); applyJavadoc( constructor, - "Empty constructor of builder for {@code %s}.".formatted(dtoClass.getFullQualifiedName())); + JavadocParser.parse("Empty constructor of builder for {@code %s}.".formatted(dtoClass.getFullQualifiedName()))); } private void appendConstructorWithInstance( @@ -249,12 +252,12 @@ private void appendConstructorWithInstance( constructor.setBody(buildConstructorBody(fields)); applyJavadoc( constructor, - """ + JavadocParser.parse(""" Initialisation of builder for {@code %s} by a instance. @param instance object instance for initialisiation """ - .formatted(dtoBaseClass.getFullQualifiedName())); + .formatted(dtoBaseClass.getFullQualifiedName()))); } private String buildConstructorBody(List fields) { @@ -490,45 +493,27 @@ private void addGenericDeclarations( } private void applyJavadoc( - org.jboss.forge.roaster.model.source.JavaDocCapableSource source, String javadoc) { - if (StringUtils.isBlank(javadoc)) { + org.jboss.forge.roaster.model.source.JavaDocCapableSource source, JavadocDto javadoc) { + if (javadoc == null || !javadoc.hasContent()) { return; } - // Normalize line endings without regex to avoid ReDoS vulnerability - String normalized = javadoc.replace("\r\n", "\n").replace("\r", "\n"); - // Remove trailing newlines using StringUtils - normalized = StringUtils.stripEnd(normalized, "\n"); - String[] lines = normalized.split("\n", -1); - StringBuilder text = new StringBuilder(); + + // Set description text + if (StringUtils.isNotBlank(javadoc.getDescription())) { + source.getJavaDoc().setText(javadoc.getDescription()); + } + + // Remove existing tags and add new ones source.getJavaDoc().removeAllTags(); - boolean inTags = false; - for (String line : lines) { - if (!inTags && line.startsWith("@")) { - inTags = true; - } - if (inTags && line.startsWith("@")) { - processJavadocTag(source, line); + for (JavadocTagDto tag : javadoc.getTags()) { + if (tag.hasValue()) { + source.getJavaDoc().addTagValue(tag.getFullTagName(), tag.tagValue()); } else { - if (!text.isEmpty()) { - text.append('\n'); - } - text.append(line); + source.getJavaDoc().addTagValue(tag.getFullTagName(), ""); } } - source.getJavaDoc().setText(text.toString()); } - private void processJavadocTag( - org.jboss.forge.roaster.model.source.JavaDocCapableSource source, String line) { - int firstSpace = line.indexOf(' '); - if (firstSpace > 1) { - source - .getJavaDoc() - .addTagValue(line.substring(0, firstSpace), line.substring(firstSpace + 1)); - } else if (line.length() > 1) { - source.getJavaDoc().addTagValue(line, ""); - } - } private void applyAnnotations( org.jboss.forge.roaster.model.source.AnnotationTargetSource source, diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java index 614709a0..29f90228 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java @@ -30,6 +30,8 @@ import java.util.Set; import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; import org.javahelpers.simple.builders.processor.model.annotation.InterfaceName; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; +import org.javahelpers.simple.builders.processor.model.integration.JacksonModuleDefinitionDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.type.GenericParameterDto; import org.javahelpers.simple.builders.processor.model.type.NestedTypeDto; @@ -88,7 +90,7 @@ public class BuilderDefinitionDto { private final Set interfaces = new LinkedHashSet<>(); /** Class-level JavaDoc for the generated builder class. */ - private String classJavadoc; + private JavadocDto classJavadoc; /** Configuration for builder generation. */ private BuilderConfiguration configuration; @@ -311,7 +313,7 @@ public void setConfiguration(BuilderConfiguration configuration) { * * @return the class JavaDoc, or null if not set */ - public String getClassJavadoc() { + public JavadocDto getClassJavadoc() { return classJavadoc; } @@ -320,7 +322,7 @@ public String getClassJavadoc() { * * @param classJavadoc the class JavaDoc to set */ - public void setClassJavadoc(String classJavadoc) { + public void setClassJavadoc(JavadocDto classJavadoc) { this.classJavadoc = classJavadoc; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java index 0a1df9ed..9010091f 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java @@ -29,6 +29,7 @@ import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.type.GenericParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -51,7 +52,7 @@ public class FieldDto { private final List fieldSetterMethodsList = new ArrayList<>(); /** Optional Javadoc of the field extracted from setter or constructor. */ - private String javaDoc; + private JavadocDto javaDoc; /** Method-level generics declared on the setter, to be reused in builder methods. */ private final List fieldGenerics = new ArrayList<>(); @@ -163,18 +164,18 @@ public void addMethod(MethodDto methodDto) { /** * Getting extracted Javadoc. * - * @return Javadoc text or null if none present + * @return Javadoc or null if none present */ - public String getJavaDoc() { + public JavadocDto getJavaDoc() { return javaDoc; } /** * Setting extracted Javadoc. * - * @param javaDoc Javadoc text + * @param javaDoc Javadoc */ - public void setJavaDoc(String javaDoc) { + public void setJavaDoc(JavadocDto javaDoc) { this.javaDoc = javaDoc; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java new file mode 100644 index 00000000..2c32e6c3 --- /dev/null +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java @@ -0,0 +1,272 @@ +/* + * MIT License + * + * Copyright (c) 2026 Andreas Igel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.javahelpers.simple.builders.processor.model.javadoc; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.apache.commons.lang3.StringUtils; + +/** Represents structured Javadoc with description text and tags. + * + *

Used for method and class-level javadoc. Note that @param tags are for documenting + * method parameters, not for individual parameter javadoc. + * + *

Example usage for a method: + *

{@code
+ * JavadocDto javadoc = new JavadocDto("Builds a new PersonDto.")
+ *     .addParam("name", "the person's name")
+ *     .addParam("age", "the person's age")
+ *     .addReturn("a new PersonDto instance")
+ *     .addThrows("IllegalArgumentException", "if name is null");
+ * }
+ * + *

Example usage for a class: + *

{@code
+ * JavadocDto classJavadoc = new JavadocDto("Builder for PersonDto objects.")
+ *     .addSee("PersonDto")
+ *     .addDeprecated();
+ * }
+ */ +public class JavadocDto { + + /** The main description text (everything before the first tag). */ + private String description; + + /** List of Javadoc tags in the order they appear. */ + private final List tags = new ArrayList<>(); + + /** Default constructor. */ + public JavadocDto() { + // Default constructor + } + + /** + * Constructor with description text. + * + * @param description the main description text + */ + public JavadocDto(String description) { + this.description = description; + } + + /** + * Constructor with description and tags. + * + * @param description the main description text + * @param tags the list of tags + */ + public JavadocDto(String description, List tags) { + this.description = description; + if (tags != null) { + this.tags.addAll(tags); + } + } + + /** + * Gets the main description text. + * + * @return the description text + */ + public String getDescription() { + return description; + } + + /** + * Sets the main description text. + * + * @param description the description text + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the list of Javadoc tags. + * + * @return the list of tags + */ + public List getTags() { + return tags; + } + + /** + * Adds a tag with the given name and value. + * + * @param tagName the tag name without @ prefix + * @param tagValue the tag value + */ + public void addTag(String tagName, String tagValue) { + if (tagName != null) { + tags.add(new JavadocTagDto(tagName, tagValue)); + } + } + + /** + * Adds a tag without a value. + * + * @param tagName the tag name without @ prefix + */ + public void addTag(String tagName) { + addTag(JavadocTagDto.withoutValue(tagName)); + } + + /** + * Adds a @param tag. + * + * @param paramName the parameter name + * @param description the parameter description + * @return this JavadocDto for fluent chaining + */ + public JavadocDto addParam(String paramName, String description) { + addTag("param", paramName + " " + description); + return this; + } + + /** + * Adds a @return tag. + * + * @param description the return description + * @return this JavadocDto for fluent chaining + */ + public JavadocDto addReturn(String description) { + addTag("return", description); + return this; + } + + /** + * Adds a @throws tag. + * + * @param exceptionName the exception name + * @param description the exception description + * @return this JavadocDto for fluent chaining + */ + public JavadocDto addThrows(String exceptionName, String description) { + addTag("throws", exceptionName + " " + description); + return this; + } + + /** + * Adds a @see tag. + * + * @param reference the reference description + * @return this JavadocDto for fluent chaining + */ + public JavadocDto addSee(String reference) { + addTag("see", reference); + return this; + } + + /** + * Adds a @deprecated tag. + * + * @return this JavadocDto for fluent chaining + */ + public JavadocDto addDeprecated() { + addTag("deprecated"); + return this; + } + + /** + * Gets the first tag with the specified name. + * + * @param tagName the tag name to search for (without @ prefix) + * @return the first matching tag, or null if not found + */ + public JavadocTagDto getTag(String tagName) { + return tags.stream() + .filter(tag -> Objects.equals(tag.tagName(), tagName)) + .findFirst() + .orElse(null); + } + + /** + * Gets all tags with the specified name. + * + * @param tagName the tag name to search for (without @ prefix) + * @return list of matching tags + */ + public List getTags(String tagName) { + return tags.stream() + .filter(tag -> Objects.equals(tag.tagName(), tagName)) + .toList(); + } + + /** + * Returns whether this Javadoc has any content (description or tags). + * + * @return true if there is description text or at least one tag + */ + public boolean hasContent() { + return StringUtils.isNotBlank(description) || !tags.isEmpty(); + } + + /** + * Returns whether this Javadoc has any tags. + * + * @return true if there is at least one tag + */ + public boolean hasTags() { + return !tags.isEmpty(); + } + + /** + * Removes all tags with the specified name. + * + * @param tagName the tag name to remove (without @ prefix) + * @return true if any tags were removed + */ + public boolean removeTags(String tagName) { + return tags.removeIf(tag -> Objects.equals(tag.tagName(), tagName)); + } + + /** + * Clears all tags. + */ + public void clearTags() { + tags.clear(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JavadocDto that = (JavadocDto) o; + return Objects.equals(description, that.description) && Objects.equals(tags, that.tags); + } + + @Override + public int hashCode() { + return Objects.hash(description, tags); + } + + @Override + public String toString() { + return "JavadocDto{" + + "description='" + description + '\'' + + ", tags=" + tags + + '}'; + } +} diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java new file mode 100644 index 00000000..0923c479 --- /dev/null +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java @@ -0,0 +1,143 @@ +/* + * MIT License + * + * Copyright (c) 2026 Andreas Igel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.javahelpers.simple.builders.processor.model.javadoc; + +import org.apache.commons.lang3.StringUtils; + +/** Utility class for parsing Javadoc strings into structured JavadocDto objects. */ +public final class JavadocParser { + + private JavadocParser() { + // Utility class - prevent instantiation + } + + /** + * Parses a Javadoc string into a structured JavadocDto. + * + * @param javadocString the raw Javadoc string (may be null or empty) + * @return the parsed JavadocDto, or null if the input is null or empty + */ + public static JavadocDto parse(String javadocString) { + if (StringUtils.isBlank(javadocString)) { + return null; + } + + // Normalize line endings without regex to avoid ReDoS vulnerability + String normalized = javadocString.replace("\r\n", "\n").replace("\r", "\n"); + // Remove trailing newlines using StringUtils + normalized = StringUtils.stripEnd(normalized, "\n"); + String[] lines = normalized.split("\n", -1); + + JavadocDto javadoc = new JavadocDto(); + StringBuilder description = new StringBuilder(); + boolean inTags = false; + + for (String line : lines) { + if (!inTags && line.startsWith("@")) { + inTags = true; + } + + if (inTags && line.startsWith("@")) { + // Process tag line + JavadocTagDto tag = parseTagLine(line); + if (tag != null) { + javadoc.addTag(tag.tagName(), tag.tagValue()); + } + } else { + // Process description line + if (!description.isEmpty()) { + description.append('\n'); + } + description.append(line); + } + } + + // Set description (may be empty) + String descriptionText = description.toString().trim(); + if (!descriptionText.isEmpty()) { + javadoc.setDescription(descriptionText); + } + + return javadoc; + } + + /** + * Parses a single tag line into a JavadocTagDto. + * + * @param line the tag line (starts with @) + * @return the parsed tag, or null if invalid + */ + private static JavadocTagDto parseTagLine(String line) { + if (line == null || !line.startsWith("@") || line.length() <= 1) { + return null; + } + + int firstSpace = line.indexOf(' '); + if (firstSpace > 1) { + // Tag with value: @param name description + String tagName = line.substring(1, firstSpace); // Remove @ prefix + String tagValue = line.substring(firstSpace + 1); + return new JavadocTagDto(tagName, tagValue); + } else if (line.length() > 1) { + // Tag without value: @deprecated + String tagName = line.substring(1); // Remove @ prefix + return JavadocTagDto.withoutValue(tagName); + } + + return null; + } + + /** + * Converts a JavadocDto back to a string representation. + * + * @param javadoc the JavadocDto to convert (may be null) + * @return the string representation, or null if input is null + */ + public static String toString(JavadocDto javadoc) { + if (javadoc == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + + // Add description + if (StringUtils.isNotBlank(javadoc.getDescription())) { + sb.append(javadoc.getDescription()); + } + + // Add tags + for (JavadocTagDto tag : javadoc.getTags()) { + if (sb.length() > 0) { + sb.append('\n'); + } + sb.append('@').append(tag.tagName()); + if (tag.hasValue()) { + sb.append(' ').append(tag.tagValue()); + } + } + + return sb.toString(); + } +} diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java new file mode 100644 index 00000000..af10996f --- /dev/null +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java @@ -0,0 +1,69 @@ +/* + * MIT License + * + * Copyright (c) 2026 Andreas Igel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.javahelpers.simple.builders.processor.model.javadoc; + +/** Represents a single Javadoc tag with its name and value. */ +public record JavadocTagDto(String tagName, String tagValue) { + + /** + * Creates a new Javadoc tag. + * + * @param tagName the tag name without @ prefix (e.g., "param", "return", "throws", "see") + * @param tagValue the tag value/content (may be empty for tags without content like @deprecated) + */ + public JavadocTagDto { + if (tagName != null && tagName.startsWith("@")) { + throw new IllegalArgumentException("Tag name should not include @ prefix: " + tagName); + } + } + + /** + * Creates a tag without a value. + * + * @param tagName the tag name without @ prefix + * @return a new JavadocTagDto with empty value + */ + public static JavadocTagDto withoutValue(String tagName) { + return new JavadocTagDto(tagName, ""); + } + + /** + * Returns whether this tag has a non-empty value. + * + * @return true if the tag value is not null and not empty + */ + public boolean hasValue() { + return tagValue != null && !tagValue.trim().isEmpty(); + } + + /** + * Returns the full tag name with @ prefix for display purposes. + * + * @return the tag name with @ prefix (e.g., "@param") + */ + public String getFullTagName() { + return "@" + tagName; + } +} diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/method/MethodDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/method/MethodDto.java index 5a4b54eb..4d8e5662 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/method/MethodDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/method/MethodDto.java @@ -31,6 +31,7 @@ import javax.lang.model.element.Modifier; import org.apache.commons.lang3.StringUtils; import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.type.GenericParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -61,7 +62,7 @@ public class MethodDto { private TypeName returnType; /** Javadoc comment for the method. */ - private String javadoc; + private JavadocDto javadoc; /** List of annotations on this method. */ private final List annotations = new ArrayList<>(); @@ -326,7 +327,7 @@ public String getSignatureKey() { return sb.toString(); } - public String getJavadoc() { + public JavadocDto getJavadoc() { return javadoc; } @@ -335,7 +336,7 @@ public String getJavadoc() { * * @param javadoc the Javadoc comment */ - public void setJavadoc(String javadoc) { + public void setJavadoc(JavadocDto javadoc) { this.javadoc = javadoc; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/type/NestedTypeDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/type/NestedTypeDto.java index d7455152..3a82163c 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/type/NestedTypeDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/type/NestedTypeDto.java @@ -26,6 +26,7 @@ import java.util.LinkedList; import java.util.List; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; /** @@ -48,7 +49,7 @@ public class NestedTypeDto { private final List methods = new LinkedList<>(); /** Javadoc comment for this nested type. */ - private String javadoc; + private JavadocDto javadoc; public enum NestedTypeKind { INTERFACE, @@ -87,11 +88,11 @@ public void addMethod(MethodDto method) { this.methods.add(method); } - public String getJavadoc() { + public JavadocDto getJavadoc() { return javadoc; } - public void setJavadoc(String javadoc) { + public void setJavadoc(JavadocDto javadoc) { this.javadoc = javadoc; } } From 8ae9c14794aad156bed192a81cfda99d96b7478c Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Fri, 3 Apr 2026 13:10:01 +0200 Subject: [PATCH 2/8] First version of replacing String JavaDoc in Model and Parsing by a defined DTO which solves that on generation so that parsing is not needed --- .../custom/StringValidationGenerator.java | 8 +- .../roaster/RoasterCodeGenerator.java | 25 +-- .../builder/ClassJavaDocEnhancer.java | 28 ++-- .../builder/ConditionalEnhancer.java | 26 ++-- .../builder/CoreMethodsEnhancer.java | 19 +-- .../builder/WithInterfaceEnhancer.java | 21 ++- .../field/AddToCollectionGenerator.java | 11 +- .../field/ArrayBuilderConsumerGenerator.java | 13 +- .../field/ArrayConversionGenerator.java | 13 +- .../field/StringBuilderConsumerGenerator.java | 16 +- .../field/StringFormatHelperGenerator.java | 18 +-- .../field/SupplierMethodGenerator.java | 15 +- .../generators/util/MethodGeneratorUtil.java | 48 +++--- .../model/core/BuilderDefinitionDto.java | 1 - .../processor/model/javadoc/JavadocDto.java | 32 ++-- .../model/javadoc/JavadocParser.java | 143 ------------------ .../processing/BuilderDefinitionCreator.java | 3 +- 17 files changed, 141 insertions(+), 299 deletions(-) delete mode 100644 processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java diff --git a/example-custom-generator/src/main/java/org/javahelpers/simple/builders/example/custom/StringValidationGenerator.java b/example-custom-generator/src/main/java/org/javahelpers/simple/builders/example/custom/StringValidationGenerator.java index 2e523ec7..ef197823 100644 --- a/example-custom-generator/src/main/java/org/javahelpers/simple/builders/example/custom/StringValidationGenerator.java +++ b/example-custom-generator/src/main/java/org/javahelpers/simple/builders/example/custom/StringValidationGenerator.java @@ -29,6 +29,7 @@ import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.processing.ProcessingContext; @@ -81,10 +82,9 @@ public List generateMethods(FieldDto field, TypeName builderType, Pro MethodDto validationMethod = new MethodDto(methodName, builderType); validationMethod.setCode(methodBody); validationMethod.setJavadoc( - "Validates that the " + fieldInDto + " field is not null or empty.\n" + - "\n" + - "@return this builder instance for chaining\n" + - "@throws IllegalArgumentException if " + fieldInDto + " is null or empty" + new JavadocDto("Validates that the " + fieldInDto + " field is not null or empty.") + .addReturn("this builder instance for chaining") + .addThrows("IllegalArgumentException", "if " + fieldInDto + " is null or empty") ); return List.of(validationMethod); diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java index 05a915ac..98063865 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java @@ -56,7 +56,6 @@ import org.javahelpers.simple.builders.processor.model.integration.JacksonModuleDefinitionDto; import org.javahelpers.simple.builders.processor.model.integration.JacksonModuleEntryDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; -import org.javahelpers.simple.builders.processor.model.javadoc.JavadocParser; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocTagDto; import org.javahelpers.simple.builders.processor.model.method.MethodCodePlaceholder; import org.javahelpers.simple.builders.processor.model.method.MethodCodeTypePlaceholder; @@ -214,7 +213,10 @@ private void applyJavaDocToField(JavaDocSource javaDoc, FieldDto fieldDto) { "Tracked value for %s: %s." .formatted( fieldDto.getFieldNameInBuilder(), - StringUtils.defaultString(JavadocParser.toString(fieldDto.getJavaDoc())))); + StringUtils.defaultString( + fieldDto.getJavaDoc() != null + ? fieldDto.getJavaDoc().getDescription() + : null))); } private void appendConstructors(JavaClassSource source, BuilderDefinitionDto builderDef) { @@ -237,7 +239,9 @@ private void appendEmptyConstructor( constructor.setBody(""); applyJavadoc( constructor, - JavadocParser.parse("Empty constructor of builder for {@code %s}.".formatted(dtoClass.getFullQualifiedName()))); + new JavadocDto( + "Empty constructor of builder for {@code %s}." + .formatted(dtoClass.getFullQualifiedName()))); } private void appendConstructorWithInstance( @@ -252,12 +256,10 @@ private void appendConstructorWithInstance( constructor.setBody(buildConstructorBody(fields)); applyJavadoc( constructor, - JavadocParser.parse(""" - Initialisation of builder for {@code %s} by a instance. - - @param instance object instance for initialisiation - """ - .formatted(dtoBaseClass.getFullQualifiedName()))); + new JavadocDto( + "Initialisation of builder for {@code %s} by a instance." + .formatted(dtoBaseClass.getFullQualifiedName())) + .addParam("instance", "object instance for initialisiation")); } private String buildConstructorBody(List fields) { @@ -497,12 +499,12 @@ private void applyJavadoc( if (javadoc == null || !javadoc.hasContent()) { return; } - + // Set description text if (StringUtils.isNotBlank(javadoc.getDescription())) { source.getJavaDoc().setText(javadoc.getDescription()); } - + // Remove existing tags and add new ones source.getJavaDoc().removeAllTags(); for (JavadocTagDto tag : javadoc.getTags()) { @@ -514,7 +516,6 @@ private void applyJavadoc( } } - private void applyAnnotations( org.jboss.forge.roaster.model.source.AnnotationTargetSource source, java.util.Collection annotations) { diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java index a25a3d25..9366f4d6 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java @@ -26,6 +26,7 @@ import org.javahelpers.simple.builders.processor.generators.BuilderEnhancer; import org.javahelpers.simple.builders.processor.model.core.BuilderDefinitionDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; import org.javahelpers.simple.builders.processor.processing.ProcessingContext; @@ -86,7 +87,7 @@ public boolean appliesTo( @Override public void enhanceBuilder(BuilderDefinitionDto builderDto, ProcessingContext context) { TypeName targetType = builderDto.getBuildingTargetTypeName(); - String javadoc = createClassJavadoc(targetType); + JavadocDto javadoc = createClassJavadoc(targetType); builderDto.setClassJavadoc(javadoc); } @@ -94,19 +95,20 @@ public void enhanceBuilder(BuilderDefinitionDto builderDto, ProcessingContext co * Creates comprehensive JavaDoc for the builder class. * * @param targetType the target DTO type - * @return String containing the JavaDoc content + * @return JavadocDto containing the JavaDoc content */ - private String createClassJavadoc(TypeName targetType) { + private JavadocDto createClassJavadoc(TypeName targetType) { String qualifiedClassName = targetType.getFullQualifiedName(); - return String.format( - """ - Builder for {@code %s}. -

- This builder provides a fluent API for creating instances of %s 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. - """, - qualifiedClassName, qualifiedClassName); + return new JavadocDto( + String.format( + """ + Builder for {@code %s}. +

+ This builder provides a fluent API for creating instances of %s 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.\ + """, + qualifiedClassName, qualifiedClassName)); } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ConditionalEnhancer.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ConditionalEnhancer.java index 94dfac35..59267d1f 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ConditionalEnhancer.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ConditionalEnhancer.java @@ -29,6 +29,7 @@ import org.javahelpers.simple.builders.processor.generators.BuilderEnhancer; import org.javahelpers.simple.builders.processor.generators.util.MethodGeneratorUtil; import org.javahelpers.simple.builders.processor.model.core.BuilderDefinitionDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -135,14 +136,12 @@ private MethodDto createConditionalMethod(BuilderDefinitionDto builderDto) { """); method.setJavadoc( - """ - 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 - """); + new JavadocDto( + "Conditionally applies builder modifications based on a condition evaluation.") + .addParam("condition", "the condition to evaluate") + .addParam("trueCase", "the consumer to apply if condition is true") + .addParam("falseCase", "the consumer to apply if condition is false (can be null)") + .addReturn("this builder instance")); return method; } @@ -161,13 +160,10 @@ private MethodDto createConditionalPositiveOnlyMethod(BuilderDefinitionDto build method.setCode("return conditional(condition, yesCondition, null);"); method.setJavadoc( - """ - 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 - """); + new JavadocDto("Conditionally applies builder modifications if the condition is true.") + .addParam("condition", "the condition to evaluate") + .addParam("yesCondition", "the consumer to apply if condition is true") + .addReturn("this builder instance")); return method; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java index 6bfa592d..b0f806a4 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java @@ -32,6 +32,7 @@ import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; import org.javahelpers.simple.builders.processor.model.core.BuilderDefinitionDto; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.type.GenericParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -193,7 +194,7 @@ protected MethodDto createBuildMethod(BuilderDefinitionDto builderDto) { method.addArgument("dtoBaseType", builderDto.getBuildingTargetTypeName()); method.addArgument("buildResultType", returnType); - method.setJavadoc("Builds the configured DTO instance."); + method.setJavadoc(new JavadocDto("Builds the configured DTO instance.")); return method; } @@ -226,12 +227,8 @@ protected MethodDto createStaticCreateMethod(BuilderDefinitionDto builderDto) { String targetFullName = builderDto.getBuildingTargetTypeName().getFullQualifiedName(); method.setJavadoc( - """ - Creating a new builder for {@code %s}. - - @return builder for {@code %s} - """ - .formatted(targetFullName, targetFullName)); + new JavadocDto("Creating a new builder for {@code %s}.".formatted(targetFullName)) + .addReturn("builder for {@code %s}".formatted(targetFullName))); return method; } @@ -260,11 +257,9 @@ protected MethodDto createToStringMethod(BuilderDefinitionDto builderDto) { new TypeName("org.javahelpers.simple.builders.core.util", "BuilderToStringStyle")); method.setJavadoc( - """ - Returns a string representation of this builder, including only fields that have been set. - - @return string representation of the builder - """); + new JavadocDto( + "Returns a string representation of this builder, including only fields that have been set.") + .addReturn("string representation of the builder")); return method; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/WithInterfaceEnhancer.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/WithInterfaceEnhancer.java index ba685b23..545472fd 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/WithInterfaceEnhancer.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/WithInterfaceEnhancer.java @@ -27,6 +27,7 @@ import org.javahelpers.simple.builders.processor.generators.BuilderEnhancer; import org.javahelpers.simple.builders.processor.generators.util.MethodGeneratorUtil; import org.javahelpers.simple.builders.processor.model.core.BuilderDefinitionDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.NestedTypeDto; @@ -114,7 +115,8 @@ private NestedTypeDto createWithInterface(BuilderDefinitionDto builderDto) { withInterface.setKind(NestedTypeDto.NestedTypeKind.INTERFACE); withInterface.setPublic(true); withInterface.setJavadoc( - "Interface that can be implemented by the DTO to provide fluent modification methods."); + new JavadocDto( + "Interface that can be implemented by the DTO to provide fluent modification methods.")); // Create the first method: DtoType with(Consumer b) MethodDto withConsumerMethod = createWithConsumerMethod(builderDto); @@ -166,12 +168,10 @@ private MethodDto createWithConsumerMethod(BuilderDefinitionDto builderDef) { "illegalargumentexception", JavaLangMapper.map2TypeName(IllegalArgumentException.class)); method.setJavadoc( - """ - 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 - """); + new JavadocDto( + "Initializes a builder from an instance of this class, using methods of this builder to change values and returns the new built object.") + .addParam("b", "the consumer to apply modifications") + .addReturn("the modified instance")); return method; } @@ -202,11 +202,8 @@ private MethodDto createWithBuilderMethod(BuilderDefinitionDto builderDef) { "illegalargumentexception", JavaLangMapper.map2TypeName(IllegalArgumentException.class)); method.setJavadoc( - """ - Creates a builder initialized from this instance. - - @return a builder initialized with this instance's values - """); + new JavadocDto("Creates a builder initialized from this instance.") + .addReturn("a builder initialized with this instance's values")); return method; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java index 493387b7..00432357 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java @@ -31,6 +31,7 @@ import org.apache.commons.lang3.StringUtils; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -178,13 +179,9 @@ private MethodDto createAddToCollectionMethod( methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); methodDto.setJavadoc( - """ - Adds a single element to %s. - - @param element the element to add - @return current instance of builder - """ - .formatted(originalFieldName)); + new JavadocDto("Adds a single element to %s.".formatted(originalFieldName)) + .addParam("element", "the element to add") + .addReturn("current instance of builder")); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java index df492715..3cc63560 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java @@ -31,6 +31,7 @@ import org.javahelpers.simple.builders.core.builders.ArrayListBuilder; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -145,13 +146,11 @@ private MethodDto createFieldConsumerWithArrayBuilder( methodDto.addArgument("elementType", elementType); methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); methodDto.setJavadoc( - """ - Sets the value for %s using the fluent builder consumer. - - @param %s consumer for %s - @return current instance of builder - """ - .formatted(fieldName, parameter.getParameterName(), field.getJavaDoc())); + new JavadocDto( + "Sets the value for %s using the fluent builder consumer." + .formatted(fieldName)) + .addParam(parameter.getParameterName(), "consumer for %s".formatted(fieldName)) + .addReturn("current instance of builder")); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java index d045d9a8..68709fb2 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java @@ -30,6 +30,7 @@ import java.util.List; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -128,14 +129,12 @@ private MethodDto createFieldSetterForArrayFromList( methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.addArgument("elementType", elementType); methodDto.setPriority(MethodDto.PRIORITY_HIGH); + String fieldJavadocDesc = + field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( - """ - Sets the value for %s. - - @param %s %s - @return current instance of builder - """ - .formatted(fieldName, parameter.getParameterName(), field.getJavaDoc())); + new JavadocDto("Sets the value for %s.".formatted(fieldName)) + .addParam(parameter.getParameterName(), fieldJavadocDesc) + .addReturn("current instance of builder")); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java index 207afb19..443bdb44 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java @@ -31,6 +31,7 @@ import java.util.List; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -112,7 +113,7 @@ public List generateMethods( createStringBuilderConsumer( field.getOriginalFieldName(), field.getFieldNameInBuilder(), - field.getJavaDoc(), + field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null, transform, builderType, context); @@ -148,13 +149,12 @@ private MethodDto createStringBuilderConsumer( methodDto.setReturnType(builderType); methodDto.setPriority(MethodDto.PRIORITY_LOW); methodDto.setJavadoc( - """ - Sets the value for %s by executing the provided consumer. - - @param %s consumer providing an instance of %s - @return current instance of builder - """ - .formatted(fieldName, parameter.getParameterName(), fieldJavadoc)); + new JavadocDto( + "Sets the value for %s by executing the provided consumer." + .formatted(fieldName)) + .addParam( + parameter.getParameterName(), "consumer providing an instance of " + fieldJavadoc) + .addReturn("current instance of builder")); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java index 17a538df..a67d2e71 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java @@ -35,6 +35,7 @@ import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -189,15 +190,14 @@ private MethodDto createStringFormatMethodWithTransform( methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.setPriority(MethodDto.PRIORITY_HIGH); methodDto.setJavadoc( - """ - Sets the String value for %s by using String.format(format, args). - See {@link String#format(String, Object...)} for details. - - @param %s A format string - @param %s Arguments referenced by the format specifiers in the format string. - @return current instance of builder - """ - .formatted(fieldName, formatParam.getParameterName(), argsParam.getParameterName())); + new JavadocDto( + "Sets the String value for %s by using String.format(format, args).\nSee {@link String#format(String, Object...)} for details." + .formatted(fieldName)) + .addParam(formatParam.getParameterName(), "A format string") + .addParam( + argsParam.getParameterName(), + "Arguments referenced by the format specifiers in the format string.") + .addReturn("current instance of builder")); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java index 5e64f022..dd65532d 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java @@ -32,6 +32,7 @@ import java.util.function.Supplier; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.TypeName; @@ -95,7 +96,7 @@ public List generateMethods( createFieldSupplier( field.getOriginalFieldName(), field.getFieldNameInBuilder(), - field.getJavaDoc(), + field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null, field.getFieldType(), builderType, context); @@ -144,13 +145,11 @@ private MethodDto createFieldSupplier( methodDto.setPriority(MethodDto.PRIORITY_HIGH); methodDto.setJavadoc( - """ - Sets the value for %s by invoking the provided supplier. - - @param %s supplier for %s - @return current instance of builder - """ - .formatted(fieldName, parameter.getParameterName(), fieldJavaDoc)); + new JavadocDto( + "Sets the value for %s by invoking the provided supplier." + .formatted(fieldName)) + .addParam(parameterName, "supplier for " + fieldJavaDoc) + .addReturn("current instance of builder")); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java index 981b282c..ab494353 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java @@ -31,6 +31,7 @@ import org.apache.commons.lang3.StringUtils; import org.javahelpers.simple.builders.processor.analysis.JavaLangMapper; import org.javahelpers.simple.builders.processor.model.core.FieldDto; +import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto; import org.javahelpers.simple.builders.processor.model.type.GenericParameterDto; @@ -186,15 +187,13 @@ public static MethodDto createBuilderMethodForFieldWithTransform( methodDto.setPriority(transform == null ? MethodDto.PRIORITY_HIGHEST : MethodDto.PRIORITY_HIGH); + String fieldJavadocDesc = + field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( - """ - Sets the value for %s. - - @param %s %s - @return current instance of builder - """ - .formatted( - field.getOriginalFieldName(), parameter.getParameterName(), field.getJavaDoc())); + new JavadocDto( + "Sets the value for %s.".formatted(field.getOriginalFieldName())) + .addParam(parameter.getParameterName(), fieldJavadocDesc) + .addReturn("current instance of builder")); return methodDto; } @@ -246,15 +245,17 @@ public static MethodDto createFieldConsumerWithBuilder( additionalTemplateArguments.forEach(methodDto::addArgument); methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); + String fieldJavadocDesc = + field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( - """ - Sets the value for %s using a builder consumer that produces the value. + new JavadocDto( + "Sets the value for %s using a builder consumer that produces the value." + .formatted(field.getFieldNameInBuilder())) + .addParam( + parameter.getParameterName(), + "consumer providing an instance of a builder for " + fieldJavadocDesc) + .addReturn("current instance of builder")); - @param %s consumer providing an instance of a builder for %s - @return current instance of builder - """ - .formatted( - field.getFieldNameInBuilder(), parameter.getParameterName(), field.getJavaDoc())); return methodDto; } @@ -375,15 +376,16 @@ public static MethodDto createSimpleFieldConsumer( methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); + String fieldJavadocDesc = + field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( - """ - Sets the value for %s by executing the provided consumer. - - @param %s consumer providing an instance of %s - @return current instance of builder - """ - .formatted( - field.getOriginalFieldName(), parameter.getParameterName(), field.getJavaDoc())); + new JavadocDto( + "Sets the value for %s by executing the provided consumer." + .formatted(field.getOriginalFieldName())) + .addParam( + parameter.getParameterName(), + "consumer providing an instance of " + fieldJavadocDesc) + .addReturn("current instance of builder")); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java index 29f90228..e19df4da 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/BuilderDefinitionDto.java @@ -31,7 +31,6 @@ import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; import org.javahelpers.simple.builders.processor.model.annotation.InterfaceName; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; -import org.javahelpers.simple.builders.processor.model.integration.JacksonModuleDefinitionDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; import org.javahelpers.simple.builders.processor.model.type.GenericParameterDto; import org.javahelpers.simple.builders.processor.model.type.NestedTypeDto; diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java index 2c32e6c3..cb17958c 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java @@ -29,12 +29,14 @@ import java.util.Objects; import org.apache.commons.lang3.StringUtils; -/** Represents structured Javadoc with description text and tags. - * - *

Used for method and class-level javadoc. Note that @param tags are for documenting - * method parameters, not for individual parameter javadoc. - * +/** + * Represents structured Javadoc with description text and tags. + * + *

Used for method and class-level javadoc. Note that @param tags are for documenting method + * parameters, not for individual parameter javadoc. + * *

Example usage for a method: + * *

{@code
  * JavadocDto javadoc = new JavadocDto("Builds a new PersonDto.")
  *     .addParam("name", "the person's name")
@@ -42,8 +44,9 @@
  *     .addReturn("a new PersonDto instance")
  *     .addThrows("IllegalArgumentException", "if name is null");
  * }
- * + * *

Example usage for a class: + * *

{@code
  * JavadocDto classJavadoc = new JavadocDto("Builder for PersonDto objects.")
  *     .addSee("PersonDto")
@@ -130,7 +133,9 @@ public void addTag(String tagName, String tagValue) {
    * @param tagName the tag name without @ prefix
    */
   public void addTag(String tagName) {
-    addTag(JavadocTagDto.withoutValue(tagName));
+    if (tagName != null) {
+      tags.add(JavadocTagDto.withoutValue(tagName));
+    }
   }
 
   /**
@@ -209,9 +214,7 @@ public JavadocTagDto getTag(String tagName) {
    * @return list of matching tags
    */
   public List getTags(String tagName) {
-    return tags.stream()
-        .filter(tag -> Objects.equals(tag.tagName(), tagName))
-        .toList();
+    return tags.stream().filter(tag -> Objects.equals(tag.tagName(), tagName)).toList();
   }
 
   /**
@@ -242,9 +245,7 @@ public boolean removeTags(String tagName) {
     return tags.removeIf(tag -> Objects.equals(tag.tagName(), tagName));
   }
 
-  /**
-   * Clears all tags.
-   */
+  /** Clears all tags. */
   public void clearTags() {
     tags.clear();
   }
@@ -264,9 +265,6 @@ public int hashCode() {
 
   @Override
   public String toString() {
-    return "JavadocDto{" +
-        "description='" + description + '\'' +
-        ", tags=" + tags +
-        '}';
+    return "JavadocDto{" + "description='" + description + '\'' + ", tags=" + tags + '}';
   }
 }
diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java
deleted file mode 100644
index 0923c479..00000000
--- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocParser.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2026 Andreas Igel
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.javahelpers.simple.builders.processor.model.javadoc;
-
-import org.apache.commons.lang3.StringUtils;
-
-/** Utility class for parsing Javadoc strings into structured JavadocDto objects. */
-public final class JavadocParser {
-
-  private JavadocParser() {
-    // Utility class - prevent instantiation
-  }
-
-  /**
-   * Parses a Javadoc string into a structured JavadocDto.
-   *
-   * @param javadocString the raw Javadoc string (may be null or empty)
-   * @return the parsed JavadocDto, or null if the input is null or empty
-   */
-  public static JavadocDto parse(String javadocString) {
-    if (StringUtils.isBlank(javadocString)) {
-      return null;
-    }
-
-    // Normalize line endings without regex to avoid ReDoS vulnerability
-    String normalized = javadocString.replace("\r\n", "\n").replace("\r", "\n");
-    // Remove trailing newlines using StringUtils
-    normalized = StringUtils.stripEnd(normalized, "\n");
-    String[] lines = normalized.split("\n", -1);
-
-    JavadocDto javadoc = new JavadocDto();
-    StringBuilder description = new StringBuilder();
-    boolean inTags = false;
-
-    for (String line : lines) {
-      if (!inTags && line.startsWith("@")) {
-        inTags = true;
-      }
-
-      if (inTags && line.startsWith("@")) {
-        // Process tag line
-        JavadocTagDto tag = parseTagLine(line);
-        if (tag != null) {
-          javadoc.addTag(tag.tagName(), tag.tagValue());
-        }
-      } else {
-        // Process description line
-        if (!description.isEmpty()) {
-          description.append('\n');
-        }
-        description.append(line);
-      }
-    }
-
-    // Set description (may be empty)
-    String descriptionText = description.toString().trim();
-    if (!descriptionText.isEmpty()) {
-      javadoc.setDescription(descriptionText);
-    }
-
-    return javadoc;
-  }
-
-  /**
-   * Parses a single tag line into a JavadocTagDto.
-   *
-   * @param line the tag line (starts with @)
-   * @return the parsed tag, or null if invalid
-   */
-  private static JavadocTagDto parseTagLine(String line) {
-    if (line == null || !line.startsWith("@") || line.length() <= 1) {
-      return null;
-    }
-
-    int firstSpace = line.indexOf(' ');
-    if (firstSpace > 1) {
-      // Tag with value: @param name description
-      String tagName = line.substring(1, firstSpace); // Remove @ prefix
-      String tagValue = line.substring(firstSpace + 1);
-      return new JavadocTagDto(tagName, tagValue);
-    } else if (line.length() > 1) {
-      // Tag without value: @deprecated
-      String tagName = line.substring(1); // Remove @ prefix
-      return JavadocTagDto.withoutValue(tagName);
-    }
-
-    return null;
-  }
-
-  /**
-   * Converts a JavadocDto back to a string representation.
-   *
-   * @param javadoc the JavadocDto to convert (may be null)
-   * @return the string representation, or null if input is null
-   */
-  public static String toString(JavadocDto javadoc) {
-    if (javadoc == null) {
-      return null;
-    }
-
-    StringBuilder sb = new StringBuilder();
-
-    // Add description
-    if (StringUtils.isNotBlank(javadoc.getDescription())) {
-      sb.append(javadoc.getDescription());
-    }
-
-    // Add tags
-    for (JavadocTagDto tag : javadoc.getTags()) {
-      if (sb.length() > 0) {
-        sb.append('\n');
-      }
-      sb.append('@').append(tag.tagName());
-      if (tag.hasValue()) {
-        sb.append(' ').append(tag.tagValue());
-      }
-    }
-
-    return sb.toString();
-  }
-}
diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java
index f5f9620a..272e04ae 100644
--- a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java
+++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java
@@ -48,6 +48,7 @@
 import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto;
 import org.javahelpers.simple.builders.processor.model.core.BuilderDefinitionDto;
 import org.javahelpers.simple.builders.processor.model.core.FieldDto;
+import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto;
 import org.javahelpers.simple.builders.processor.model.method.MethodDto;
 import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto;
 import org.javahelpers.simple.builders.processor.model.type.TypeName;
@@ -448,7 +449,7 @@ private static Optional createFieldDto(
         fieldNameInBuilder); // Use renamed field name for builder field storage
     field.setOriginalFieldName(fieldName);
     field.setFieldType(fieldType);
-    field.setJavaDoc(javaDoc);
+    field.setJavaDoc(javaDoc != null ? new JavadocDto(javaDoc) : null);
 
     // Note: setterName will be set explicitly by the caller before field renaming
 

From bd8da28dd0d0883551b653c2d4a8463b562fbfe9 Mon Sep 17 00:00:00 2001
From: AndreasIgel 
Date: Fri, 3 Apr 2026 15:37:11 +0200
Subject: [PATCH 3/8] Improving JavaDocDto for providing easy utility functions

---
 .../roaster/RoasterCodeGenerator.java         |  7 ++-
 .../builder/ClassJavaDocEnhancer.java         | 19 ++++---
 .../builder/CoreMethodsEnhancer.java          |  4 +-
 .../field/AddToCollectionGenerator.java       |  2 +-
 .../field/ArrayBuilderConsumerGenerator.java  |  5 +-
 .../field/ArrayConversionGenerator.java       |  2 +-
 .../field/StringBuilderConsumerGenerator.java |  5 +-
 .../field/StringFormatHelperGenerator.java    |  4 +-
 .../field/SupplierMethodGenerator.java        |  5 +-
 .../generators/util/MethodGeneratorUtil.java  | 17 +++---
 .../processor/model/javadoc/JavadocDto.java   | 54 ++++++++++++++++---
 .../processing/BuilderDefinitionCreator.java  | 18 ++++---
 12 files changed, 91 insertions(+), 51 deletions(-)

diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java
index 98063865..3968749d 100644
--- a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java
+++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java
@@ -240,8 +240,7 @@ private void appendEmptyConstructor(
     applyJavadoc(
         constructor,
         new JavadocDto(
-            "Empty constructor of builder for {@code %s}."
-                .formatted(dtoClass.getFullQualifiedName())));
+            "Empty constructor of builder for {@code %s}.", dtoClass.getFullQualifiedName()));
   }
 
   private void appendConstructorWithInstance(
@@ -257,8 +256,8 @@ private void appendConstructorWithInstance(
     applyJavadoc(
         constructor,
         new JavadocDto(
-                "Initialisation of builder for {@code %s} by a instance."
-                    .formatted(dtoBaseClass.getFullQualifiedName()))
+                "Initialisation of builder for {@code %s} by a instance.",
+                dtoBaseClass.getFullQualifiedName())
             .addParam("instance", "object instance for initialisiation"));
   }
 
diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java
index 9366f4d6..71ae20f9 100644
--- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java
+++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/ClassJavaDocEnhancer.java
@@ -100,15 +100,14 @@ public void enhanceBuilder(BuilderDefinitionDto builderDto, ProcessingContext co
   private JavadocDto createClassJavadoc(TypeName targetType) {
     String qualifiedClassName = targetType.getFullQualifiedName();
     return new JavadocDto(
-        String.format(
-            """
-            Builder for {@code %s}.
-            

- This builder provides a fluent API for creating instances of %s 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.\ - """, - qualifiedClassName, qualifiedClassName)); + """ + Builder for {@code %s}. +

+ This builder provides a fluent API for creating instances of %s 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.\ + """, + qualifiedClassName, qualifiedClassName); } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java index b0f806a4..c7aeef7b 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/builder/CoreMethodsEnhancer.java @@ -227,8 +227,8 @@ protected MethodDto createStaticCreateMethod(BuilderDefinitionDto builderDto) { String targetFullName = builderDto.getBuildingTargetTypeName().getFullQualifiedName(); method.setJavadoc( - new JavadocDto("Creating a new builder for {@code %s}.".formatted(targetFullName)) - .addReturn("builder for {@code %s}".formatted(targetFullName))); + new JavadocDto("Creating a new builder for {@code %s}.", targetFullName) + .addReturn("builder for {@code %s}", targetFullName)); return method; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java index 00432357..2c314bee 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java @@ -179,7 +179,7 @@ private MethodDto createAddToCollectionMethod( methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); methodDto.setJavadoc( - new JavadocDto("Adds a single element to %s.".formatted(originalFieldName)) + new JavadocDto("Adds a single element to %s.", originalFieldName) .addParam("element", "the element to add") .addReturn("current instance of builder")); diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java index 3cc63560..ef70d997 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java @@ -147,9 +147,8 @@ private MethodDto createFieldConsumerWithArrayBuilder( methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); methodDto.setJavadoc( new JavadocDto( - "Sets the value for %s using the fluent builder consumer." - .formatted(fieldName)) - .addParam(parameter.getParameterName(), "consumer for %s".formatted(fieldName)) + "Sets the value for %s using the fluent builder consumer.", fieldName) + .addParam(parameter.getParameterName(), "consumer for %s", fieldName) .addReturn("current instance of builder")); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java index 68709fb2..e9630f95 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java @@ -132,7 +132,7 @@ private MethodDto createFieldSetterForArrayFromList( String fieldJavadocDesc = field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( - new JavadocDto("Sets the value for %s.".formatted(fieldName)) + new JavadocDto("Sets the value for %s.", fieldName) .addParam(parameter.getParameterName(), fieldJavadocDesc) .addReturn("current instance of builder")); return methodDto; diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java index 443bdb44..e647e808 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java @@ -150,10 +150,9 @@ private MethodDto createStringBuilderConsumer( methodDto.setPriority(MethodDto.PRIORITY_LOW); methodDto.setJavadoc( new JavadocDto( - "Sets the value for %s by executing the provided consumer." - .formatted(fieldName)) + "Sets the value for %s by executing the provided consumer.", fieldName) .addParam( - parameter.getParameterName(), "consumer providing an instance of " + fieldJavadoc) + parameter.getParameterName(), "consumer providing an instance of %s", fieldJavadoc) .addReturn("current instance of builder")); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java index a67d2e71..976b0be9 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java @@ -191,8 +191,8 @@ private MethodDto createStringFormatMethodWithTransform( methodDto.setPriority(MethodDto.PRIORITY_HIGH); methodDto.setJavadoc( new JavadocDto( - "Sets the String value for %s by using String.format(format, args).\nSee {@link String#format(String, Object...)} for details." - .formatted(fieldName)) + "Sets the String value for %s by using String.format(format, args).\nSee {@link String#format(String, Object...)} for details.", + fieldName) .addParam(formatParam.getParameterName(), "A format string") .addParam( argsParam.getParameterName(), diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java index dd65532d..55921ba9 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java @@ -146,9 +146,8 @@ private MethodDto createFieldSupplier( methodDto.setJavadoc( new JavadocDto( - "Sets the value for %s by invoking the provided supplier." - .formatted(fieldName)) - .addParam(parameterName, "supplier for " + fieldJavaDoc) + "Sets the value for %s by invoking the provided supplier.", fieldName) + .addParam(parameterName, "supplier for %s", fieldJavaDoc) .addReturn("current instance of builder")); return methodDto; diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java index ab494353..ea6db5f2 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java @@ -190,8 +190,7 @@ public static MethodDto createBuilderMethodForFieldWithTransform( String fieldJavadocDesc = field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( - new JavadocDto( - "Sets the value for %s.".formatted(field.getOriginalFieldName())) + new JavadocDto("Sets the value for %s.", field.getOriginalFieldName()) .addParam(parameter.getParameterName(), fieldJavadocDesc) .addReturn("current instance of builder")); @@ -249,11 +248,12 @@ public static MethodDto createFieldConsumerWithBuilder( field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( new JavadocDto( - "Sets the value for %s using a builder consumer that produces the value." - .formatted(field.getFieldNameInBuilder())) + "Sets the value for %s using a builder consumer that produces the value.", + field.getFieldNameInBuilder()) .addParam( parameter.getParameterName(), - "consumer providing an instance of a builder for " + fieldJavadocDesc) + "consumer providing an instance of a builder for %s", + fieldJavadocDesc) .addReturn("current instance of builder")); return methodDto; @@ -380,11 +380,12 @@ public static MethodDto createSimpleFieldConsumer( field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; methodDto.setJavadoc( new JavadocDto( - "Sets the value for %s by executing the provided consumer." - .formatted(field.getOriginalFieldName())) + "Sets the value for %s by executing the provided consumer.", + field.getOriginalFieldName()) .addParam( parameter.getParameterName(), - "consumer providing an instance of " + fieldJavadocDesc) + "consumer providing an instance of %s", + fieldJavadocDesc) .addReturn("current instance of builder")); return methodDto; diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java index cb17958c..00fd66ac 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java @@ -75,6 +75,24 @@ public JavadocDto(String description) { this.description = description; } + /** + * Constructor with formatted description text. + * + *

Allows using String.format-style formatting directly in the constructor. + * + *

Example: + * + *

{@code
+   * new JavadocDto("Sets the value for %s.", fieldName)
+   * }
+ * + * @param format the format string (using String.format syntax) + * @param args the arguments referenced by the format specifiers + */ + public JavadocDto(String format, Object... args) { + this.description = String.format(format, args); + } + /** * Constructor with description and tags. * @@ -139,24 +157,48 @@ public void addTag(String tagName) { } /** - * Adds a @param tag. + * Adds a @param tag with optional formatted description. + * + *

Supports String.format-style formatting when args are provided. + * + *

Examples: + * + *

{@code
+   * addParam("value", "the value to set")              // No formatting
+   * addParam("value", "the %s to set", fieldName)      // With formatting
+   * }
* * @param paramName the parameter name - * @param description the parameter description + * @param descriptionFormat the format string for the parameter description + * @param args optional arguments referenced by format specifiers in the description * @return this JavadocDto for fluent chaining */ - public JavadocDto addParam(String paramName, String description) { + public JavadocDto addParam(String paramName, String descriptionFormat, Object... args) { + String description = + args.length > 0 ? String.format(descriptionFormat, args) : descriptionFormat; addTag("param", paramName + " " + description); return this; } /** - * Adds a @return tag. + * Adds a @return tag with optional formatted description. + * + *

Supports String.format-style formatting when args are provided. + * + *

Examples: + * + *

{@code
+   * addReturn("current instance of builder")           // No formatting
+   * addReturn("builder for {@code %s}", className)     // With formatting
+   * }
* - * @param description the return description + * @param descriptionFormat the format string for the return description + * @param args optional arguments referenced by format specifiers in the description * @return this JavadocDto for fluent chaining */ - public JavadocDto addReturn(String description) { + public JavadocDto addReturn(String descriptionFormat, Object... args) { + String description = + args.length > 0 ? String.format(descriptionFormat, args) : descriptionFormat; addTag("return", description); return this; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java index 272e04ae..12fa0762 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java @@ -304,10 +304,11 @@ private static Optional createFieldFromSetter( // Extract only the @param Javadoc for the single setter parameter (if present) String fullJavaDoc = context.getDocComment(mth); - String javaDoc = JavaLangAnalyser.extractParamJavaDoc(fullJavaDoc, fieldParameter); - if (javaDoc == null) { - javaDoc = fieldName; + String javaDocStr = JavaLangAnalyser.extractParamJavaDoc(fullJavaDoc, fieldParameter); + if (javaDocStr == null) { + javaDocStr = fieldName; } + JavadocDto javaDoc = new JavadocDto(javaDocStr); // Check for field name conflicts and rename if necessary String finalFieldName = @@ -337,11 +338,12 @@ private static Optional createFieldFromConstructor( Map fieldNameRegistry) { String fieldName = param.getSimpleName().toString(); // Set javadoc (default to field name if no javadoc found) - String javaDoc = + String javaDocStr = JavaLangAnalyser.extractParamJavaDoc(context.getDocComment(annotatedType), param); - if (javaDoc == null) { - javaDoc = fieldName; + if (javaDocStr == null) { + javaDocStr = fieldName; } + JavadocDto javaDoc = new JavadocDto(javaDocStr); // Convert TypeElement to TypeName once TypeName dtoType = JavaLangMapper.map2TypeName(annotatedType, context); @@ -431,7 +433,7 @@ The reason could be having helperfunctions in the DTO or a mistake in the DTO (e private static Optional createFieldDto( String fieldName, String fieldNameInBuilder, - String javaDoc, + JavadocDto javaDoc, VariableElement param, TypeName dtoType, TypeName builderType, @@ -449,7 +451,7 @@ private static Optional createFieldDto( fieldNameInBuilder); // Use renamed field name for builder field storage field.setOriginalFieldName(fieldName); field.setFieldType(fieldType); - field.setJavaDoc(javaDoc != null ? new JavadocDto(javaDoc) : null); + field.setJavaDoc(javaDoc); // Note: setterName will be set explicitly by the caller before field renaming From 78b3bb5507407e12fa73ebd7924c5cde290c6b8a Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Fri, 3 Apr 2026 16:31:12 +0200 Subject: [PATCH 4/8] Improving codequality by small optimizations and moving generation of builder.field-javaDoc into BuilderDefinitionCreator --- .../roaster/RoasterCodeGenerator.java | 16 +++---- .../field/ArrayConversionGenerator.java | 3 +- .../field/StringBuilderConsumerGenerator.java | 2 +- .../field/SupplierMethodGenerator.java | 2 +- .../generators/util/MethodGeneratorUtil.java | 9 ++-- .../processor/model/core/FieldDto.java | 42 +++++++++++++++++-- .../processor/model/javadoc/JavadocDto.java | 40 +++++++++++++----- .../processing/BuilderDefinitionCreator.java | 39 ++++++++++------- 8 files changed, 107 insertions(+), 46 deletions(-) diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java index 3968749d..4360b33e 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java @@ -209,14 +209,10 @@ private void appendField(JavaClassSource source, FieldDto fieldDto) { } private void applyJavaDocToField(JavaDocSource javaDoc, FieldDto fieldDto) { - javaDoc.setText( - "Tracked value for %s: %s." - .formatted( - fieldDto.getFieldNameInBuilder(), - StringUtils.defaultString( - fieldDto.getJavaDoc() != null - ? fieldDto.getJavaDoc().getDescription() - : null))); + JavadocDto trackedValueJavadoc = fieldDto.getJavaDoc(); + if (trackedValueJavadoc != null) { + javaDoc.setText(trackedValueJavadoc.getDescription()); + } } private void appendConstructors(JavaClassSource source, BuilderDefinitionDto builderDef) { @@ -499,6 +495,10 @@ private void applyJavadoc( return; } + // Note: source.getJavaDoc() never returns null - Roaster creates the JavaDoc if it doesn't + // exist + // The early return above ensures we only create JavaDoc when there's actual content to set + // Set description text if (StringUtils.isNotBlank(javadoc.getDescription())) { source.getJavaDoc().setText(javadoc.getDescription()); diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java index e9630f95..05a98a11 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java @@ -129,8 +129,7 @@ private MethodDto createFieldSetterForArrayFromList( methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.addArgument("elementType", elementType); methodDto.setPriority(MethodDto.PRIORITY_HIGH); - String fieldJavadocDesc = - field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; + String fieldJavadocDesc = field.getJavaDocDescriptionOrFieldName(); methodDto.setJavadoc( new JavadocDto("Sets the value for %s.", fieldName) .addParam(parameter.getParameterName(), fieldJavadocDesc) diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java index e647e808..40e79201 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java @@ -113,7 +113,7 @@ public List generateMethods( createStringBuilderConsumer( field.getOriginalFieldName(), field.getFieldNameInBuilder(), - field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null, + field.getJavaDocDescriptionOrFieldName(), transform, builderType, context); diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java index 55921ba9..0a5adf8a 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java @@ -96,7 +96,7 @@ public List generateMethods( createFieldSupplier( field.getOriginalFieldName(), field.getFieldNameInBuilder(), - field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null, + field.getJavaDocDescriptionOrFieldName(), field.getFieldType(), builderType, context); diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java index ea6db5f2..ed977def 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java @@ -187,8 +187,7 @@ public static MethodDto createBuilderMethodForFieldWithTransform( methodDto.setPriority(transform == null ? MethodDto.PRIORITY_HIGHEST : MethodDto.PRIORITY_HIGH); - String fieldJavadocDesc = - field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; + String fieldJavadocDesc = field.getJavaDocDescriptionOrFieldName(); methodDto.setJavadoc( new JavadocDto("Sets the value for %s.", field.getOriginalFieldName()) .addParam(parameter.getParameterName(), fieldJavadocDesc) @@ -244,8 +243,7 @@ public static MethodDto createFieldConsumerWithBuilder( additionalTemplateArguments.forEach(methodDto::addArgument); methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); - String fieldJavadocDesc = - field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; + String fieldJavadocDesc = field.getJavaDocDescriptionOrFieldName(); methodDto.setJavadoc( new JavadocDto( "Sets the value for %s using a builder consumer that produces the value.", @@ -376,8 +374,7 @@ public static MethodDto createSimpleFieldConsumer( methodDto.addArgument("builderFieldWrapper", TRACKED_VALUE_TYPE); methodDto.setPriority(MethodDto.PRIORITY_MEDIUM); - String fieldJavadocDesc = - field.getJavaDoc() != null ? field.getJavaDoc().getDescription() : null; + String fieldJavadocDesc = field.getJavaDocDescriptionOrFieldName(); methodDto.setJavadoc( new JavadocDto( "Sets the value for %s by executing the provided consumer.", diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java index 9010091f..3f565fdb 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/core/FieldDto.java @@ -51,7 +51,13 @@ public class FieldDto { /** List of all methods in builder, which provide helpers to change the field. */ private final List fieldSetterMethodsList = new ArrayList<>(); - /** Optional Javadoc of the field extracted from setter or constructor. */ + /** + * Original javadoc description extracted from setter or constructor parameter. This is used when + * generating javadoc for builder methods that reference this field. + */ + private String originalJavaDocDescription; + + /** Javadoc for the tracked value field in the builder. */ private JavadocDto javaDoc; /** Method-level generics declared on the setter, to be reused in builder methods. */ @@ -162,7 +168,37 @@ public void addMethod(MethodDto methodDto) { } /** - * Getting extracted Javadoc. + * Gets the original javadoc description extracted from the DTO. + * + * @return the original javadoc description, or null if none present + */ + public String getOriginalJavaDocDescription() { + return originalJavaDocDescription; + } + + /** + * Sets the original javadoc description extracted from the DTO. + * + * @param originalJavaDocDescription the original javadoc description + */ + public void setOriginalJavaDocDescription(String originalJavaDocDescription) { + this.originalJavaDocDescription = originalJavaDocDescription; + } + + /** + * Gets the original javadoc description if available, otherwise returns the original field name. + * + *

This is useful when generating javadoc for builder methods that reference the field, as it + * provides a meaningful description even when no explicit javadoc was provided. + * + * @return the javadoc description if available, otherwise the original field name + */ + public String getJavaDocDescriptionOrFieldName() { + return originalJavaDocDescription != null ? originalJavaDocDescription : originalFieldName; + } + + /** + * Getting Javadoc for the tracked value field in the builder. * * @return Javadoc or null if none present */ @@ -171,7 +207,7 @@ public JavadocDto getJavaDoc() { } /** - * Setting extracted Javadoc. + * Setting Javadoc for the tracked value field in the builder. * * @param javaDoc Javadoc */ diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java index 00fd66ac..707efcdd 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java @@ -174,8 +174,7 @@ public void addTag(String tagName) { * @return this JavadocDto for fluent chaining */ public JavadocDto addParam(String paramName, String descriptionFormat, Object... args) { - String description = - args.length > 0 ? String.format(descriptionFormat, args) : descriptionFormat; + String description = String.format(descriptionFormat, args); addTag("param", paramName + " " + description); return this; } @@ -197,31 +196,52 @@ public JavadocDto addParam(String paramName, String descriptionFormat, Object... * @return this JavadocDto for fluent chaining */ public JavadocDto addReturn(String descriptionFormat, Object... args) { - String description = - args.length > 0 ? String.format(descriptionFormat, args) : descriptionFormat; + String description = String.format(descriptionFormat, args); addTag("return", description); return this; } /** - * Adds a @throws tag. + * Adds a @throws tag with optional formatted description. + * + *

Supports String.format-style formatting when args are provided. + * + *

Examples: + * + *

{@code
+   * addThrows("IllegalArgumentException", "if name is null")
+   * addThrows("IllegalStateException", "if %s is invalid", fieldName)
+   * }
* * @param exceptionName the exception name - * @param description the exception description + * @param descriptionFormat the format string for the exception description + * @param args optional arguments referenced by format specifiers in the description * @return this JavadocDto for fluent chaining */ - public JavadocDto addThrows(String exceptionName, String description) { + public JavadocDto addThrows(String exceptionName, String descriptionFormat, Object... args) { + String description = String.format(descriptionFormat, args); addTag("throws", exceptionName + " " + description); return this; } /** - * Adds a @see tag. + * Adds a @see tag with optional formatted reference. + * + *

Supports String.format-style formatting when args are provided. + * + *

Examples: + * + *

{@code
+   * addSee("PersonDto")
+   * addSee("%s#%s", className, methodName)
+   * }
* - * @param reference the reference description + * @param referenceFormat the format string for the reference + * @param args optional arguments referenced by format specifiers in the reference * @return this JavadocDto for fluent chaining */ - public JavadocDto addSee(String reference) { + public JavadocDto addSee(String referenceFormat, Object... args) { + String reference = String.format(referenceFormat, args); addTag("see", reference); return this; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java index 12fa0762..fb2e512d 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/BuilderDefinitionCreator.java @@ -304,11 +304,7 @@ private static Optional createFieldFromSetter( // Extract only the @param Javadoc for the single setter parameter (if present) String fullJavaDoc = context.getDocComment(mth); - String javaDocStr = JavaLangAnalyser.extractParamJavaDoc(fullJavaDoc, fieldParameter); - if (javaDocStr == null) { - javaDocStr = fieldName; - } - JavadocDto javaDoc = new JavadocDto(javaDocStr); + String javaDocDescription = JavaLangAnalyser.extractParamJavaDoc(fullJavaDoc, fieldParameter); // Check for field name conflicts and rename if necessary String finalFieldName = @@ -317,7 +313,13 @@ private static Optional createFieldFromSetter( // Pass both original field name (for methods) and final field name (for builder field) Optional result = createFieldDto( - fieldName, finalFieldName, javaDoc, fieldParameter, dtoType, builderType, context); + fieldName, + finalFieldName, + javaDocDescription, + fieldParameter, + dtoType, + builderType, + context); if (result.isPresent()) { fieldNameRegistry.put(finalFieldName, result.get()); @@ -337,13 +339,9 @@ private static Optional createFieldFromConstructor( ProcessingContext context, Map fieldNameRegistry) { String fieldName = param.getSimpleName().toString(); - // Set javadoc (default to field name if no javadoc found) - String javaDocStr = + // Extract javadoc from constructor parameter (if present) + String javaDocDescription = JavaLangAnalyser.extractParamJavaDoc(context.getDocComment(annotatedType), param); - if (javaDocStr == null) { - javaDocStr = fieldName; - } - JavadocDto javaDoc = new JavadocDto(javaDocStr); // Convert TypeElement to TypeName once TypeName dtoType = JavaLangMapper.map2TypeName(annotatedType, context); @@ -353,7 +351,8 @@ private static Optional createFieldFromConstructor( // Pass both original field name (for methods) and final field name (for builder field) Optional result = - createFieldDto(fieldName, finalFieldName, javaDoc, param, dtoType, builderType, context); + createFieldDto( + fieldName, finalFieldName, javaDocDescription, param, dtoType, builderType, context); if (result.isPresent()) { fieldNameRegistry.put(finalFieldName, result.get()); @@ -433,7 +432,7 @@ The reason could be having helperfunctions in the DTO or a mistake in the DTO (e private static Optional createFieldDto( String fieldName, String fieldNameInBuilder, - JavadocDto javaDoc, + String javaDocDescription, VariableElement param, TypeName dtoType, TypeName builderType, @@ -451,7 +450,17 @@ private static Optional createFieldDto( fieldNameInBuilder); // Use renamed field name for builder field storage field.setOriginalFieldName(fieldName); field.setFieldType(fieldType); - field.setJavaDoc(javaDoc); + + // Store original javadoc description for reuse in builder method javadocs + field.setOriginalJavaDocDescription(StringUtils.trimToNull(javaDocDescription)); + + // Create javadoc for the tracked value field in the builder + String javaDocDescriptionOrFieldname = field.getJavaDocDescriptionOrFieldName(); + JavadocDto trackedValueJavadoc = + new JavadocDto( + "Tracked value for %s: %s.", + fieldNameInBuilder, javaDocDescriptionOrFieldname); + field.setJavaDoc(trackedValueJavadoc); // Note: setterName will be set explicitly by the caller before field renaming From 8eef1e0091fb8e884e0361930d231c56f90ee684 Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Fri, 3 Apr 2026 16:43:23 +0200 Subject: [PATCH 5/8] Fixing coverage calculation (DTOs should not need coverage) --- processor/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/processor/pom.xml b/processor/pom.xml index 38788390..9faa92f6 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -329,8 +329,8 @@ **/*Mapper*.class - - **/processor/dtos/** + + **/processor/model/** **/processor/exceptions/** From c46f8c23d859387debf23a7ed03153e23bba7812 Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Fri, 3 Apr 2026 16:45:13 +0200 Subject: [PATCH 6/8] Fixing sonarQube codesmells --- .../field/AddToCollectionGenerator.java | 3 +- .../field/ArrayBuilderConsumerGenerator.java | 3 +- .../field/ArrayConversionGenerator.java | 3 +- .../field/StringBuilderConsumerGenerator.java | 3 +- .../field/StringFormatHelperGenerator.java | 3 +- .../field/SupplierMethodGenerator.java | 3 +- .../generators/util/JavadocConstants.java | 42 +++++++++++++++++++ .../generators/util/MethodGeneratorUtil.java | 6 +-- .../processor/model/javadoc/JavadocDto.java | 18 ++++---- .../model/javadoc/JavadocTagDto.java | 2 +- 10 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/JavadocConstants.java diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java index 2c314bee..3d91e0d9 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/AddToCollectionGenerator.java @@ -30,6 +30,7 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; +import org.javahelpers.simple.builders.processor.generators.util.JavadocConstants; import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; @@ -181,7 +182,7 @@ private MethodDto createAddToCollectionMethod( methodDto.setJavadoc( new JavadocDto("Adds a single element to %s.", originalFieldName) .addParam("element", "the element to add") - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java index ef70d997..02f59310 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayBuilderConsumerGenerator.java @@ -30,6 +30,7 @@ import java.util.List; import org.javahelpers.simple.builders.core.builders.ArrayListBuilder; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; +import org.javahelpers.simple.builders.processor.generators.util.JavadocConstants; import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; @@ -149,7 +150,7 @@ private MethodDto createFieldConsumerWithArrayBuilder( new JavadocDto( "Sets the value for %s using the fluent builder consumer.", fieldName) .addParam(parameter.getParameterName(), "consumer for %s", fieldName) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java index 05a98a11..927f06c7 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/ArrayConversionGenerator.java @@ -29,6 +29,7 @@ import java.util.List; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; +import org.javahelpers.simple.builders.processor.generators.util.JavadocConstants; import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; @@ -133,7 +134,7 @@ private MethodDto createFieldSetterForArrayFromList( methodDto.setJavadoc( new JavadocDto("Sets the value for %s.", fieldName) .addParam(parameter.getParameterName(), fieldJavadocDesc) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java index 40e79201..7735031f 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringBuilderConsumerGenerator.java @@ -30,6 +30,7 @@ import java.util.List; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; +import org.javahelpers.simple.builders.processor.generators.util.JavadocConstants; import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; @@ -153,7 +154,7 @@ private MethodDto createStringBuilderConsumer( "Sets the value for %s by executing the provided consumer.", fieldName) .addParam( parameter.getParameterName(), "consumer providing an instance of %s", fieldJavadoc) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java index 976b0be9..b6182c0b 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/StringFormatHelperGenerator.java @@ -33,6 +33,7 @@ import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; +import org.javahelpers.simple.builders.processor.generators.util.JavadocConstants; import org.javahelpers.simple.builders.processor.model.annotation.AnnotationDto; import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; @@ -197,7 +198,7 @@ private MethodDto createStringFormatMethodWithTransform( .addParam( argsParam.getParameterName(), "Arguments referenced by the format specifiers in the format string.") - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java index 0a5adf8a..8e8ef06d 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/field/SupplierMethodGenerator.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.function.Supplier; import org.javahelpers.simple.builders.processor.generators.MethodGenerator; +import org.javahelpers.simple.builders.processor.generators.util.JavadocConstants; import org.javahelpers.simple.builders.processor.model.core.FieldDto; import org.javahelpers.simple.builders.processor.model.javadoc.JavadocDto; import org.javahelpers.simple.builders.processor.model.method.MethodDto; @@ -148,7 +149,7 @@ private MethodDto createFieldSupplier( new JavadocDto( "Sets the value for %s by invoking the provided supplier.", fieldName) .addParam(parameterName, "supplier for %s", fieldJavaDoc) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/JavadocConstants.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/JavadocConstants.java new file mode 100644 index 00000000..5b16b12a --- /dev/null +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/JavadocConstants.java @@ -0,0 +1,42 @@ +/* + * MIT License + * + * Copyright (c) 2026 Andreas Igel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.javahelpers.simple.builders.processor.generators.util; + +/** + * Constants for commonly used javadoc text in builder generation. + * + *

This class contains reusable javadoc descriptions and text snippets that are used across + * multiple builder method generators. + */ +public final class JavadocConstants { + + /** Common return description for builder methods that return the builder instance. */ + public static final String RETURN_BUILDER_INSTANCE = "current instance of builder"; + + /** Private constructor to prevent instantiation. */ + private JavadocConstants() { + throw new UnsupportedOperationException("Utility class"); + } +} diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java index ed977def..e58984b8 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/generators/util/MethodGeneratorUtil.java @@ -191,7 +191,7 @@ public static MethodDto createBuilderMethodForFieldWithTransform( methodDto.setJavadoc( new JavadocDto("Sets the value for %s.", field.getOriginalFieldName()) .addParam(parameter.getParameterName(), fieldJavadocDesc) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } @@ -252,7 +252,7 @@ public static MethodDto createFieldConsumerWithBuilder( parameter.getParameterName(), "consumer providing an instance of a builder for %s", fieldJavadocDesc) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } @@ -383,7 +383,7 @@ public static MethodDto createSimpleFieldConsumer( parameter.getParameterName(), "consumer providing an instance of %s", fieldJavadocDesc) - .addReturn("current instance of builder")); + .addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE)); return methodDto; } diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java index 707efcdd..6e2043ce 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java @@ -174,8 +174,8 @@ public void addTag(String tagName) { * @return this JavadocDto for fluent chaining */ public JavadocDto addParam(String paramName, String descriptionFormat, Object... args) { - String description = String.format(descriptionFormat, args); - addTag("param", paramName + " " + description); + String paramDescription = String.format(descriptionFormat, args); + addTag("param", paramName + " " + paramDescription); return this; } @@ -196,8 +196,8 @@ public JavadocDto addParam(String paramName, String descriptionFormat, Object... * @return this JavadocDto for fluent chaining */ public JavadocDto addReturn(String descriptionFormat, Object... args) { - String description = String.format(descriptionFormat, args); - addTag("return", description); + String returnDescription = String.format(descriptionFormat, args); + addTag("return", returnDescription); return this; } @@ -219,8 +219,8 @@ public JavadocDto addReturn(String descriptionFormat, Object... args) { * @return this JavadocDto for fluent chaining */ public JavadocDto addThrows(String exceptionName, String descriptionFormat, Object... args) { - String description = String.format(descriptionFormat, args); - addTag("throws", exceptionName + " " + description); + String throwsDescription = String.format(descriptionFormat, args); + addTag("throws", exceptionName + " " + throwsDescription); return this; } @@ -241,13 +241,13 @@ public JavadocDto addThrows(String exceptionName, String descriptionFormat, Obje * @return this JavadocDto for fluent chaining */ public JavadocDto addSee(String referenceFormat, Object... args) { - String reference = String.format(referenceFormat, args); - addTag("see", reference); + String seeReference = String.format(referenceFormat, args); + addTag("see", seeReference); return this; } /** - * Adds a @deprecated tag. + * Adds a deprecated tag. * * @return this JavadocDto for fluent chaining */ diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java index af10996f..f3934650 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocTagDto.java @@ -31,7 +31,7 @@ public record JavadocTagDto(String tagName, String tagValue) { * Creates a new Javadoc tag. * * @param tagName the tag name without @ prefix (e.g., "param", "return", "throws", "see") - * @param tagValue the tag value/content (may be empty for tags without content like @deprecated) + * @param tagValue the tag value/content (may be empty for tags without content like deprecated) */ public JavadocTagDto { if (tagName != null && tagName.startsWith("@")) { From 5b56555a7d90ad01d97e683902952d662be66c62 Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Fri, 3 Apr 2026 16:58:29 +0200 Subject: [PATCH 7/8] Fixing sonarQube exclusions for model and exceptions --- pom.xml | 2 +- sonar-project.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6cb6588f..1be6fd76 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ ${project.basedir}/core/target/site/jacoco/jacoco.xml,${project.basedir}/processor/target/site/jacoco/jacoco.xml **/example/** - **/*Mapper*.java,**/processor/dtos/**,**/generated/** + **/*Mapper*.java,**/processor/model/**,**/processor/exceptions/**,**/generated/** 3.13.0 diff --git a/sonar-project.properties b/sonar-project.properties index 81a7cb47..192f94fc 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -17,7 +17,7 @@ sonar.coverage.jacoco.xmlReportPaths=processor/target/site/jacoco/jacoco.xml # Exclusions sonar.exclusions=**/generated/**,example/** -sonar.coverage.exclusions=**/*Mapper*.java,**/processor/dtos/**,**/processor/exceptions/**,**/generated/**,example/** +sonar.coverage.exclusions=**/*Mapper*.java,**/processor/model/**,**/processor/exceptions/**,**/generated/**,example/** # Java Version sonar.java.source=17 From a8838d255f6b88f7941927ba9407dd280fa48509 Mon Sep 17 00:00:00 2001 From: AndreasIgel Date: Fri, 3 Apr 2026 16:58:46 +0200 Subject: [PATCH 8/8] Removing unused methods from JavadocDto --- .../processor/model/javadoc/JavadocDto.java | 102 +----------------- 1 file changed, 3 insertions(+), 99 deletions(-) diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java index 6e2043ce..dc21fb92 100644 --- a/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java +++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/model/javadoc/JavadocDto.java @@ -35,22 +35,14 @@ *

Used for method and class-level javadoc. Note that @param tags are for documenting method * parameters, not for individual parameter javadoc. * - *

Example usage for a method: + *

Example usage: * *

{@code
  * JavadocDto javadoc = new JavadocDto("Builds a new PersonDto.")
  *     .addParam("name", "the person's name")
  *     .addParam("age", "the person's age")
- *     .addReturn("a new PersonDto instance")
- *     .addThrows("IllegalArgumentException", "if name is null");
- * }
- * - *

Example usage for a class: - * - *

{@code
- * JavadocDto classJavadoc = new JavadocDto("Builder for PersonDto objects.")
- *     .addSee("PersonDto")
- *     .addDeprecated();
+ *     .addThrows("IllegalArgumentException", "if name is null")
+ *     .addReturn("a new PersonDto instance");
  * }
*/ public class JavadocDto { @@ -115,15 +107,6 @@ public String getDescription() { return description; } - /** - * Sets the main description text. - * - * @param description the description text - */ - public void setDescription(String description) { - this.description = description; - } - /** * Gets the list of Javadoc tags. * @@ -224,61 +207,6 @@ public JavadocDto addThrows(String exceptionName, String descriptionFormat, Obje return this; } - /** - * Adds a @see tag with optional formatted reference. - * - *

Supports String.format-style formatting when args are provided. - * - *

Examples: - * - *

{@code
-   * addSee("PersonDto")
-   * addSee("%s#%s", className, methodName)
-   * }
- * - * @param referenceFormat the format string for the reference - * @param args optional arguments referenced by format specifiers in the reference - * @return this JavadocDto for fluent chaining - */ - public JavadocDto addSee(String referenceFormat, Object... args) { - String seeReference = String.format(referenceFormat, args); - addTag("see", seeReference); - return this; - } - - /** - * Adds a deprecated tag. - * - * @return this JavadocDto for fluent chaining - */ - public JavadocDto addDeprecated() { - addTag("deprecated"); - return this; - } - - /** - * Gets the first tag with the specified name. - * - * @param tagName the tag name to search for (without @ prefix) - * @return the first matching tag, or null if not found - */ - public JavadocTagDto getTag(String tagName) { - return tags.stream() - .filter(tag -> Objects.equals(tag.tagName(), tagName)) - .findFirst() - .orElse(null); - } - - /** - * Gets all tags with the specified name. - * - * @param tagName the tag name to search for (without @ prefix) - * @return list of matching tags - */ - public List getTags(String tagName) { - return tags.stream().filter(tag -> Objects.equals(tag.tagName(), tagName)).toList(); - } - /** * Returns whether this Javadoc has any content (description or tags). * @@ -288,30 +216,6 @@ public boolean hasContent() { return StringUtils.isNotBlank(description) || !tags.isEmpty(); } - /** - * Returns whether this Javadoc has any tags. - * - * @return true if there is at least one tag - */ - public boolean hasTags() { - return !tags.isEmpty(); - } - - /** - * Removes all tags with the specified name. - * - * @param tagName the tag name to remove (without @ prefix) - * @return true if any tags were removed - */ - public boolean removeTags(String tagName) { - return tags.removeIf(tag -> Objects.equals(tag.tagName(), tagName)); - } - - /** Clears all tags. */ - public void clearTags() { - tags.clear(); - } - @Override public boolean equals(Object o) { if (this == o) return true;