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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -81,10 +82,9 @@ public List<MethodDto> 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);
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/core/target/site/jacoco/jacoco.xml,${project.basedir}/processor/target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
<sonar.exclusions>**/example/**</sonar.exclusions>
<!-- Coverage exclusion needs to match jacoco configuration in processor module -->
<sonar.coverage.exclusions>**/*Mapper*.java,**/processor/dtos/**,**/generated/**</sonar.coverage.exclusions>
<sonar.coverage.exclusions>**/*Mapper*.java,**/processor/model/**,**/processor/exceptions/**,**/generated/**</sonar.coverage.exclusions>

<!-- Plugin Versions -->
<plugin.maven.compiler.version>3.13.0</plugin.maven.compiler.version>
Expand Down
4 changes: 2 additions & 2 deletions processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@
<excludes>
<!-- Exclude mapper utilities from coverage -->
<exclude>**/*Mapper*.class</exclude>
<!-- Exclude DTOs package from coverage -->
<exclude>**/processor/dtos/**</exclude>
<!-- Exclude DTOs (model package) from coverage -->
<exclude>**/processor/model/**</exclude>
<!-- Exclude exception classes from coverage (simple constructors) -->
<exclude>**/processor/exceptions/**</exclude>
</excludes>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
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.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;
Expand Down Expand Up @@ -207,11 +209,10 @@ private void appendField(JavaClassSource source, FieldDto fieldDto) {
}

private void applyJavaDocToField(JavaDocSource<?> javaDoc, FieldDto fieldDto) {
javaDoc.setText(
"Tracked value for <code>%s</code>: %s."
.formatted(
fieldDto.getFieldNameInBuilder(),
StringUtils.defaultString(fieldDto.getJavaDoc())));
JavadocDto trackedValueJavadoc = fieldDto.getJavaDoc();
if (trackedValueJavadoc != null) {
javaDoc.setText(trackedValueJavadoc.getDescription());
}
}

private void appendConstructors(JavaClassSource source, BuilderDefinitionDto builderDef) {
Expand All @@ -234,7 +235,8 @@ private void appendEmptyConstructor(
constructor.setBody("");
applyJavadoc(
constructor,
"Empty constructor of builder for {@code %s}.".formatted(dtoClass.getFullQualifiedName()));
new JavadocDto(
"Empty constructor of builder for {@code %s}.", dtoClass.getFullQualifiedName()));
}

private void appendConstructorWithInstance(
Expand All @@ -249,12 +251,10 @@ private void appendConstructorWithInstance(
constructor.setBody(buildConstructorBody(fields));
applyJavadoc(
constructor,
"""
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.",
dtoBaseClass.getFullQualifiedName())
.addParam("instance", "object instance for initialisiation"));
}

private String buildConstructorBody(List<FieldDto> fields) {
Expand Down Expand Up @@ -490,44 +490,29 @@ 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();

// 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());
}

// 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -86,26 +87,26 @@ 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);
}

/**
* 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(
return new JavadocDto(
"""
Builder for {@code %s}.
<p>
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.
the setter methods, and then call {@code build()} to create the final DTO.\
""",
qualifiedClassName, qualifiedClassName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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}.", targetFullName)
.addReturn("builder for {@code %s}", targetFullName));

return method;
}
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<BuilderType> b)
MethodDto withConsumerMethod = createWithConsumerMethod(builderDto);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
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;
import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto;
import org.javahelpers.simple.builders.processor.model.type.TypeName;
Expand Down Expand Up @@ -178,13 +180,9 @@ private MethodDto createAddToCollectionMethod(
methodDto.setPriority(MethodDto.PRIORITY_MEDIUM);

methodDto.setJavadoc(
"""
Adds a single element to <code>%s</code>.

@param element the element to add
@return current instance of builder
"""
.formatted(originalFieldName));
new JavadocDto("Adds a single element to <code>%s</code>.", originalFieldName)
.addParam("element", "the element to add")
.addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE));

return methodDto;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
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;
import org.javahelpers.simple.builders.processor.model.method.MethodParameterDto;
import org.javahelpers.simple.builders.processor.model.type.TypeName;
Expand Down Expand Up @@ -145,13 +147,10 @@ private MethodDto createFieldConsumerWithArrayBuilder(
methodDto.addArgument("elementType", elementType);
methodDto.setPriority(MethodDto.PRIORITY_MEDIUM);
methodDto.setJavadoc(
"""
Sets the value for <code>%s</code> 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 <code>%s</code> using the fluent builder consumer.", fieldName)
.addParam(parameter.getParameterName(), "consumer for %s", fieldName)
.addReturn(JavadocConstants.RETURN_BUILDER_INSTANCE));
return methodDto;
}
}
Loading
Loading