diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderData.java b/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderData.java index 55b4fc9..0eef3bd 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderData.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderData.java @@ -26,7 +26,6 @@ public class BuilderData { private final SortedSet innerClasses = new TreeSet<>((o1, o2) -> o1.getBuilderClassName().compareTo(o2.getBuilderClassName())); private final boolean isAbstract; - private final boolean extendedBuilderIsAbstract; private final BuilderConfiguration builderConfiguration; private boolean builderPassingConstructor; @@ -35,7 +34,6 @@ public class BuilderData { sourceClassName = builder.sourceClassName; builderClassName = builder.builderClassName; extendedBuilderName = builder.extendedBuilderName; - extendedBuilderIsAbstract = builder.extendedBuilderIsAbstract; isAbstract = builder.isAbstract; builderConfiguration = builder.builderConfiguration; } @@ -60,6 +58,9 @@ public String getExtendedBuilderName() { } /** + * Sometimes you have a hierarchy of classes, and a similar hierarchy with builders. In this case for subclass builders this + * will return the name of the superclass builder. This method will return true if this is the case. + * * @return true if this builder extends another builder. */ public boolean extendsBuilder() { @@ -67,13 +68,11 @@ public boolean extendsBuilder() { } /** - * @return true if this builder would be of an abstract class. The builder will then not generate a build method. - */ - public boolean extendsAbstractBuilder() { - return extendedBuilderIsAbstract; - } - - /** + * The package name for this builder cannot always be logically determined. The package name returned here is what according to + * the java compiler is the package.
+ *
+ * For example it can handle package names like: I.Do.Not.Follow.Java.Conventions + * * @return the package name for this builder */ public String getPackageName() { @@ -108,6 +107,8 @@ public GenerationType getSourceClassName() { } /** + * used to check if the class for this builder is abstract, in that case the generated builder will also be abstract. + * * @return true if this builder is based on an abstract class. */ public boolean isAbstract() { @@ -115,6 +116,8 @@ public boolean isAbstract() { } /** + * Sometimes you want to disable the copy of method, because your class does not expose all of it's fields. + * * @return true if the copy of method should be generated */ public boolean isCopyOfGenerationEnabled() { @@ -122,6 +125,8 @@ public boolean isCopyOfGenerationEnabled() { } /** + * You can use a constructor that accepts the builder as an argument. If this is set to true then that is the case. + * * @param builderPassingConstructor whether or not the constructor accepts the builder */ public void setBuilderPassingConstructor(boolean builderPassingConstructor) { @@ -129,6 +134,10 @@ public void setBuilderPassingConstructor(boolean builderPassingConstructor) { } /** + * You can use a constructor that accepts the builder as an argument.
+ *
+ * For example: class MyClass { ... MyClass(MyClassBuilder builder) { ... } ... } + * * @return true if the only argument for the constructor is the builder itself. */ public boolean isBuilderPassingConstructor() { @@ -233,6 +242,8 @@ private List determineInvalidMembers() { } /** + * If this builder data object is not valid, then this method will return information for the user as to why it is not valid. + * * @return the validation error tekst for the compilation error when {@link #isValid()} returns false. */ public String getValidationError() { @@ -245,6 +256,8 @@ public String getValidationError() { } /** + * creates a new builder for creating a BuilderData object. + * * @return a new builder for creating a BuilderData object. */ public static BuilderDataBuilder builder() { @@ -257,7 +270,6 @@ public static BuilderDataBuilder builder() { public static class BuilderDataBuilder { private BuilderConfiguration builderConfiguration; private boolean isAbstract; - private boolean extendedBuilderIsAbstract; private String extendedBuilderName; private String builderClassName; private GenerationType sourceClassName; @@ -267,6 +279,8 @@ private BuilderDataBuilder() { } /** + * Used to set the package name. + * * @param packageName - the package name of this builder annotated class * @return itself for builder chaining */ @@ -276,6 +290,8 @@ public BuilderDataBuilder setPackageName(String packageName) { } /** + * Used to set the generated type for the builder annotated class + * * @param sourceClassName - the builder annotated class * @return itself for builder chaining */ @@ -285,6 +301,8 @@ public BuilderDataBuilder setSourceClassName(GenerationType sourceClassName) { } /** + * Used to set how the resulting builder class should be called + * * @param builderClassName - the resulting builder class name * @return itself for builder chaining */ @@ -294,6 +312,8 @@ public BuilderDataBuilder setBuilderClassName(String builderClassName) { } /** + * Used to set the builder configuration + * * @param builderConfiguration - the builderConfiguration containing generation settings * @return itself for builder chaining */ @@ -303,6 +323,8 @@ public BuilderDataBuilder setBuilderConfiguration(BuilderConfiguration builderCo } /** + * Used to set whether or not the source class is abstract. + * * @param isAbstract - whether the source class is abstract or not. * @return itself for builder chaining */ @@ -312,15 +334,8 @@ public BuilderDataBuilder setAbstract(boolean isAbstract) { } /** - * @param extendedBuilderIsAbstract - whether the source class extends a class that is abstract or not. - * @return itself for builder chaining - */ - public BuilderDataBuilder setExtendedBuilderIsAbstract(boolean extendedBuilderIsAbstract) { - this.extendedBuilderIsAbstract = extendedBuilderIsAbstract; - return this; - } - - /** + * Used to set the builder to extend, if there is no builder then this method should not be used. + * * @param extendedBuilderName - the name of the builder that this builder should extend if any. * @return itself for builder chaining */ @@ -330,6 +345,8 @@ public BuilderDataBuilder setExtendedBuilderName(String extendedBuilderName) { } /** + * Creates a new BuilderData object with information in this builder. + * * @return the BuilderData based on the builder */ public BuilderData build() { diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderGenerator.java b/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderGenerator.java index ab92ecf..5b068b9 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderGenerator.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderGenerator.java @@ -20,6 +20,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; @@ -46,13 +47,14 @@ public class BuilderGenerator { * * @param environmentConfiguration - contains the configuration supplied to the compiler * @param types - Utility class for working with Types. + * @param elements - Utility class for working with Elements. * @param messager - Feedback endpoint for communication errors/warnings to the java compiler * @param typeElement - The current element for which a builder needs to be generated. */ - public BuilderGenerator(EnvironmentConfiguration environmentConfiguration, Types types, Messager messager, - TypeElement typeElement) { + public BuilderGenerator(EnvironmentConfiguration environmentConfiguration, Types types, Elements elements, + Messager messager, TypeElement typeElement) { this.environmentConfiguration = environmentConfiguration; - typeUtils = new TypeUtils(types); + typeUtils = new TypeUtils(types, elements); this.messager = messager; this.typeElement = new Type(typeElement); } @@ -92,7 +94,6 @@ private BuilderData createBuilderData(Type typeElement) { .setAbstract(typeElement.isAbstract()) .setBuilderClassName(typeElement.getSimpleName() + BUILDER_SUFFIX) .setBuilderConfiguration(builderConfiguration) - .setExtendedBuilderIsAbstract(isExtendedAbstract(typeElement)) .setExtendedBuilderName(getExtendedBuilderName(typeElement)) .setPackageName(typeUtils.getPackageName(typeElement.getTypeElement())) .setSourceClassName(asGenerationType(typeElement.getTypeElement().asType())) @@ -164,7 +165,8 @@ private Member createMember(BuilderConfiguration builderConfiguration, Type type determineBuilderMethod(enclosedEle, builderConfiguration.getMethodPrefix())) .hasGetter(hasGetter(typeElement, enclosedEle)) .hasSetter(hasSetter(typeElement, enclosedEle)) - .inherited(currentElement != typeElement && currentElement.hasBuilderAnnotation()); + .inherited(currentElement != typeElement && currentElement.hasBuilderAnnotation()) + .javadoc(determineJavadoc(enclosedEle)); if (typeUtils.isList(propertyType)) { TypeMirror subType = typeUtils.getSubType(propertyType); memberBuilder @@ -182,6 +184,10 @@ private Member createMember(BuilderConfiguration builderConfiguration, Type type return memberBuilder.build(); } + private String determineJavadoc(TypeMember enclosedEle) { + return typeUtils.getJavadoc(enclosedEle); + } + private List getSurroundingClassesForGeneration(TypeMirror propertyType) { return typeUtils.getSurroundingClasses(propertyType).stream().map(this::asGenerationType).collect(toList()); } @@ -314,11 +320,6 @@ private String getExtendedBuilderName(Type type) { return null; } - private boolean isExtendedAbstract(Type type) { - Type parentType = getParentType(type); - return parentType != null && parentType.isAbstract(); - } - private Type getParentType(Type type) { return typeUtils.getParentType(type); } diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderProcessor.java b/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderProcessor.java index 0f6b4b6..e5a6582 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderProcessor.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/BuilderProcessor.java @@ -32,6 +32,13 @@ public class BuilderProcessor extends AbstractProcessor { private boolean testCompiling; private EnvironmentConfiguration environmentConfiguration; + /** + * Annotation Processor which handles the needed setup for the {@link BuilderGenerator} to do its work. + */ + public BuilderProcessor() { + // needed for javadoc + } + @Override public synchronized void init(ProcessingEnvironment processingEnv) { freeMarkerWriter = new FreeMarkerWriter(); @@ -49,7 +56,7 @@ public boolean process(Set annotations, RoundEnvironment if (testCompiling && typeElement.getSimpleName().toString().startsWith("Erroneous")) { continue; } - new BuilderGenerator(environmentConfiguration, processingEnv.getTypeUtils(), + new BuilderGenerator(environmentConfiguration, processingEnv.getTypeUtils(), processingEnv.getElementUtils(), processingEnv.getMessager(), typeElement).generate(processingEnv.getFiler(), freeMarkerWriter); } } diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/EnvironmentConfiguration.java b/generator/src/main/java/nl/loxia/builder/generator/ap/EnvironmentConfiguration.java index d153269..d72556a 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/EnvironmentConfiguration.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/EnvironmentConfiguration.java @@ -12,6 +12,8 @@ public class EnvironmentConfiguration { private final Optional methodPrefix; /** + * Instantiates the environment configuration. Upon construction the processing environment information is read. + * * @param processingEnv - The processing environment used by the compiler. */ public EnvironmentConfiguration(ProcessingEnvironment processingEnv) { @@ -21,6 +23,8 @@ public EnvironmentConfiguration(ProcessingEnvironment processingEnv) { } /** + * Used to return the global configuration for the copy of method generation + * * @return false if the copyOfMethodGeneration option is set to false, returns true otherwise. */ public boolean getCopyOfMethodGeneration() { @@ -28,6 +32,8 @@ public boolean getCopyOfMethodGeneration() { } /** + * Used to return the global configuration of the method prefix for chaining. + * * @return An optional value, if the methodPrefix option is supplied then the optional is filled with this value, otherwise it * is empty. */ diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/GenerationType.java b/generator/src/main/java/nl/loxia/builder/generator/ap/GenerationType.java index d949296..47d9ffc 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/GenerationType.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/GenerationType.java @@ -10,6 +10,8 @@ public class GenerationType { private final String packageName; /** + * Creates a generation type which represents a class. + * * @param mirror - the typeMirror used to generate a class reference in code. * @param packageName - the package in which this type mirror lives. */ @@ -19,6 +21,8 @@ public GenerationType(TypeMirror mirror, String packageName) { } /** + * Creates a generation type which represents a class. + * * @param type - the type used to generate a class reference in code. * @param packageName - the package in which this type mirror lives. */ @@ -28,13 +32,26 @@ public GenerationType(String type, String packageName) { } /** - * @return the typemirror for usage in code generation + * This is the fully qualified class name for this type. + * + * @return the type for usage in code generation */ public String getType() { return type; } /** + * This is the fully qualified class name for this type. + * + * @return the type for usage in code generation + */ + public String getTypeWithoutGenerics() { + return type.replaceAll("<.*>", ""); + } + + /** + * This is the package name for this type. + * * @return the package name of this type mirror as determined by the java compiler api instead of manually determining this. */ public String getPackageName() { diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/Member.java b/generator/src/main/java/nl/loxia/builder/generator/ap/Member.java index 8949a76..4e25fb4 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/Member.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/Member.java @@ -22,6 +22,7 @@ public class Member { private final boolean hasSetter; private final GenerationType subBuilderClassName; private final String methodName; + private final String javadoc; private Member(Member.Builder builder) { type = builder.type; @@ -36,6 +37,7 @@ private Member(Member.Builder builder) { subBuilderClassName = builder.subBuilderClassName; aliases = Collections.unmodifiableList(builder.aliases); methodName = builder.methodName; + javadoc = builder.javadoc; } /** @@ -176,6 +178,15 @@ public boolean isAbstract() { return isAbstract; } + /** + * If a field is annotated with javadoc, then this is transferred to the builder. + * + * @return the javadoc of this member. + */ + public String getJavadoc() { + return javadoc; + } + /** * A new builder for creating a member. * @@ -191,6 +202,7 @@ public static Builder builder() { * @author zegveb */ public static class Builder { + private String javadoc; private GenerationType type; private String name; private GenerationType subType; @@ -341,6 +353,19 @@ public Builder setBuilderMethod(String methodName) { } /** + * Sets the javadoc that should be inherited to this builder method + * + * @param javadoc - the javadoc that is on the field. + * @return itself for chaining + */ + public Builder javadoc(String javadoc) { + this.javadoc = javadoc; + return this; + } + + /** + * creates a new {@link Member} based on the information in this builder. + * * @return the build Member. */ public Member build() { diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/Type.java b/generator/src/main/java/nl/loxia/builder/generator/ap/Type.java index debdf86..66d0151 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/Type.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/Type.java @@ -24,6 +24,8 @@ public class Type { private final TypeElement typeElement; /** + * creates the type container. + * * @param typeElement the model item to simplify */ public Type(TypeElement typeElement) { @@ -31,6 +33,8 @@ public Type(TypeElement typeElement) { } /** + * For usage with {@link TypeUtils}. + * * @return the typeElement represented by this Type. */ public TypeElement getTypeElement() { @@ -46,14 +50,6 @@ public String getQualifiedName() { return typeElement.getQualifiedName().toString(); } - /** - * @return the package of the type. - */ - public String getPackageName() { - String qualifiedName = getQualifiedName(); - return qualifiedName.substring(0, qualifiedName.lastIndexOf('.')); - } - /** * see {@link TypeElement#getSimpleName()} * @@ -77,6 +73,8 @@ private Stream getEnclosedElementsStream() { } /** + * used to check if the abstract keyword is present + * * @return true if this type is marked as abstract. */ public boolean isAbstract() { @@ -95,6 +93,8 @@ public ANNOTATION getAnnotation(Class getSmallestConstructorArgumentNames() { } /** + * returns true if there is a getter present for the TypeMember inside this class. + * * @param typeMember representing the field * @return true if a getter method is available to retrieve the field. */ @@ -147,6 +149,8 @@ public boolean hasGetterFor(TypeMember typeMember) { } /** + * returns true if there is a setter present for the TypeMember inside this class. + * * @param typeMember representing the field * @return true if a getter method is available to retrieve the field. */ @@ -157,6 +161,8 @@ public boolean hasSetterFor(TypeMember typeMember) { } /** + * returns the annotation method value if present, otherwise null. + * * @param annotationClass - the annotation class for which the needs to be looked up. * @param annotationMethod - the name of the method for which the value is wanted. * @return the value associated with the specified annotation and method of that annotation. returns null if not found or not diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/TypeMember.java b/generator/src/main/java/nl/loxia/builder/generator/ap/TypeMember.java index 28f0f0a..6301d6a 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/TypeMember.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/TypeMember.java @@ -21,6 +21,8 @@ public class TypeMember { private final Element element; /** + * creates the type member container. + * * @param element the model item to simplify */ public TypeMember(Element element) { @@ -28,6 +30,8 @@ public TypeMember(Element element) { } /** + * used when this is a class to return this wrapped as a {@link Type}. Use {@link #isClass()} first to check it. + * * @return this element as a {@link Type} */ public Type asType() { @@ -35,6 +39,8 @@ public Type asType() { } /** + * checks if the element kind is of the type field. + * * @return true if this element represents a field. */ public boolean isField() { @@ -42,6 +48,8 @@ public boolean isField() { } /** + * checks if the element kind is of the type method. + * * @return true if this element represents a method. */ public boolean isMethod() { @@ -49,6 +57,8 @@ public boolean isMethod() { } /** + * checks if the element kind is of the type class. + * * @return true if this element represents a class. If true then you can use {@link #asType()} to get more information from it. */ public boolean isClass() { @@ -56,6 +66,8 @@ public boolean isClass() { } /** + * checks if the element kind is of the type constructor. + * * @return true if this element represents a constructor. */ public boolean isConstructor() { @@ -63,6 +75,8 @@ public boolean isConstructor() { } /** + * check if this elements is a setter. + * * @return true if this element represents a setter method. */ public boolean isSetterMethod() { @@ -78,6 +92,8 @@ private boolean isSetter(Name methodName) { } /** + * check if this elements is a getter. + * * @return true if this element represents a getter method. */ public boolean isGetterMethod() { @@ -102,6 +118,8 @@ public TypeMirror getReturnType() { } /** + * The {@link ExecutableElement#getParameters()} wrapped as {@link TypeMember}. + * * @return the parameters if this is a method or constructor otherwise an empty list. */ public List getParameters() { @@ -112,6 +130,9 @@ public List getParameters() { } /** + * determines the type represented by this member. For get methods it is the return type, for set methods it is the first + * parameter, for fields it is the type itself. + * * @return the return type for a getter, the first parameter for another method, or the element itself. */ public TypeMirror getPropertyType() { @@ -183,4 +204,12 @@ public boolean isOfAnUnavailableType() { return element.asType().getKind() == TypeKind.ERROR; } + /** + * For usage with {@link TypeUtils}. + * + * @return the element that is encapsulated by this TypeMember. + */ + public Element getElement() { + return element; + } } diff --git a/generator/src/main/java/nl/loxia/builder/generator/ap/TypeUtils.java b/generator/src/main/java/nl/loxia/builder/generator/ap/TypeUtils.java index 20488ba..a372040 100644 --- a/generator/src/main/java/nl/loxia/builder/generator/ap/TypeUtils.java +++ b/generator/src/main/java/nl/loxia/builder/generator/ap/TypeUtils.java @@ -14,19 +14,22 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; import javax.lang.model.util.Types; /** - * Utility method for working with {@link Types}. + * Utility method for working with {@link Types} and {@link Elements}. * * @author Ben Zegveld */ class TypeUtils { private final Types types; + private final Elements elements; - TypeUtils(Types types) { + TypeUtils(Types types, Elements elements) { this.types = types; + this.elements = elements; } /** @@ -210,4 +213,8 @@ public String getPackageName(Element element) { return packageName; } + public String getJavadoc(TypeMember enclosedEle) { + return elements.getDocComment(enclosedEle.getElement()); + } + } diff --git a/generator/src/main/resources/freemarker/classContent.ftl b/generator/src/main/resources/freemarker/classContent.ftl index 017f333..48553d9 100644 --- a/generator/src/main/resources/freemarker/classContent.ftl +++ b/generator/src/main/resources/freemarker/classContent.ftl @@ -1,43 +1,43 @@ <#macro generateContent cls indent=1> - <#list cls.members as member> - <@generateFields cls member indent/> - + <#list cls.members as member> + <@generateFields cls member indent/> + - <@generateConstructor cls indent/> + <@generateConstructor cls indent/> - <#-- for all fields --> - <#list cls.members as member> - <@generateWithMethod cls member indent/> + <#-- for all fields --> + <#list cls.members as member> + <@generateWithMethod cls member indent/> - <#if member.hasBuilder() && !member.hasSubType()> - <@generateWithBuilderMethod cls member indent/> + <#if member.hasBuilder() && !member.hasSubType()> + <@generateWithBuilderMethod cls member indent/> - - <#if cls.isBuilderPassingConstructor()> - <@generateGetMethod cls member indent/> + + <#if cls.isBuilderPassingConstructor()> + <@generateGetMethod cls member indent/> - - - <#-- for only List collection fields --> - <#list cls.collectionMembers as member> - <@generateCollectionAddIterable cls member indent/> + + + <#-- for only List collection fields --> + <#list cls.collectionMembers as member> + <@generateCollectionAddIterable cls member indent/> - <@generateCollectionAddVarArgs cls member indent/> + <@generateCollectionAddVarArgs cls member indent/> - <#if member.hasBuilder()> - <#if !member.isAbstract()> - <@generateCollectionAddBuilder cls member indent/> + <#if member.hasBuilder()> + <#if !member.isAbstract()> + <@generateCollectionAddBuilder cls member indent/> - - <#list member.aliases as alias> - <@generateCollectionAddAliasBuilder cls member alias indent/> - - - + + <#list member.aliases as alias> + <@generateCollectionAddAliasBuilder cls member alias indent/> + + + <@generateBuildMethod cls indent/> <@generateEndMethod cls indent/> <#if cls.isCopyOfGenerationEnabled()> - <@generateCopyOfMethod cls indent/> + <@generateCopyOfMethod cls indent/> <@generateInnerClassBuilder cls indent/> @@ -45,12 +45,12 @@ <#-- Inner class builder --> <#macro generateInnerClassBuilder cls indent> <#local spc>${""?left_pad(indent * 4)} - <#list cls.innerClasses as innerClass> + <#list cls.innerClasses as innerClass> ${spc}public static class ${innerClass.builderClassName} <#if innerClass.extendsBuilder()>extends ${innerClass.extendedBuilderName} { <@class.generateContent innerClass indent+1/> ${spc}} - + <#-- Generation of fields --> @@ -87,13 +87,26 @@ ${spc}} <#macro generateWithMethod cls member indent> <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> + <#if member.isList()> +${spc}/** + <@javadoc member spc true/> +${spc} * This replaces the collection currently present. Any previous calls to add${member.name?cap_first} are not saved. +${spc} */ + <#elseif member.hasBuilder()> +${spc}/** + <@javadoc member spc true/> +${spc} * If this is called after {@link #${member.methodName}()} then the Builder is lost. +${spc} */ + <#else> + <@javadoc member spc false/> + ${spc}public ${cls.builderClassName} ${member.methodName}(<@com.type member.type packageName/> ${member.name}) { ${spc} this.${member.name} = ${member.name}; - <#if member.hasBuilder() && !member.hasSubType()> + <#if member.hasBuilder() && !member.hasSubType()> ${spc} ${member.name}Builder = null; <#elseif member.hasBuilder()> ${spc} ${member.name}Builders = new java.util.ArrayList<>(); - + ${spc} return this; ${spc}} @@ -102,7 +115,7 @@ ${spc}} <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> ${spc}public <@com.type member.type packageName/> get${member.name?cap_first}() { - <#if member.hasBuilder() && !member.hasSubType()> + <#if member.hasBuilder() && !member.hasSubType()> ${spc} if (${member.name}Builder != null){ ${spc} return ${member.name}Builder.build(); ${spc} } @@ -111,7 +124,7 @@ ${spc} if (!${member.name}Builders.isEmpty()){ ${spc} return ${member.name}Builders.stream().map(builder -> builder.build()).collect(java.util.stream.Collectors.toList()); ${spc} } ${spc} ${member.name}Builders = new java.util.ArrayList<>(); - + ${spc} return this.${member.name}; ${spc}} @@ -119,6 +132,12 @@ ${spc}} <#macro generateWithBuilderMethod cls member indent> <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> +${spc}/** + <@javadoc member spc true/> +${spc} * returns a builder for chaining. Use the end() method to return back to the current builder.
+${spc} * Multiple calls to this method will return the same builder.
+${spc} * If this is called after {@link #${member.methodName}(<@com.type member.type packageName/>)} then this will return a new Builder and the previously set object is lost. +${spc} */ ${spc}public <@com.builderType member packageName sourceClassName/>> ${member.methodName}() { ${spc} if (${member.name}Builder == null) { ${spc} ${member.name}Builder = new <@com.builderType member packageName sourceClassName/><>(this); @@ -131,6 +150,10 @@ ${spc}} <#macro generateCollectionAddIterable cls member indent> <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> +${spc}/** + <@javadoc member spc true/> + <@javadocAddCollection member spc/> +${spc} */ ${spc}public ${cls.builderClassName} add${member.name?cap_first}(Iterable> ${member.name}) { ${spc} for (<@com.type member.subType packageName/> v : ${member.name}) { ${spc} this.${member.name}.add(v); @@ -142,6 +165,10 @@ ${spc}} <#macro generateCollectionAddVarArgs cls member indent> <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> +${spc}/** + <@javadoc member spc true/> + <@javadocAddCollection member spc/> +${spc} */ ${spc}public ${cls.builderClassName} add${member.name?cap_first}(<@com.type member.subType packageName/>... ${member.name}) { ${spc} for (<@com.type member.subType packageName/> v : ${member.name}) { ${spc} this.${member.name}.add(v); @@ -153,6 +180,10 @@ ${spc}} <#macro generateCollectionAddBuilder cls member indent> <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> +${spc}/** + <@javadoc member spc true/> +${spc} * Each call to this method creates a new Builder which will be stored in the list. Use the end() method to return back to the current builder. +${spc} */ ${spc}public <@com.type member.subBuilderClassName packageName/>> add${member.name?cap_first}() { ${spc} <@com.type member.subBuilderClassName packageName/><${cls.builderClassName}> child = new <@com.type member.subBuilderClassName packageName/><>(this); ${spc} ${member.name}Builders.add(child); @@ -163,6 +194,7 @@ ${spc}} <#macro generateCollectionAddAliasBuilder cls member alias indent> <#local spc>${""?left_pad(indent * 4)} <@inherited member indent/> + <@javadoc member spc false/> ${spc}public <@com.type alias.type packageName/>Builder> add${alias.name?cap_first}() { ${spc} <@com.type alias.type packageName/>Builder<${cls.builderClassName}> child = new <@com.type alias.type packageName/>Builder<>(this); ${spc} ${member.name}Builders.add(child); @@ -172,6 +204,9 @@ ${spc}} <#macro generateBuildMethod cls indent> <#local spc>${""?left_pad(indent * 4)} +${spc}/** +${spc} * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. +${spc} */ <#if cls.extendsBuilder()> ${spc}@Override @@ -219,6 +254,9 @@ ${spc}@Override <#local spc>${""?left_pad(indent * 4)} <#if !cls.extendsBuilder()> +${spc}/** +${spc} * returns the parent builder if present, otherwise null is returned. +${spc} */ ${spc}public PARENT end() { ${spc} return parent; ${spc}} @@ -252,29 +290,46 @@ ${spc}} <#macro generateCopyOfBody cls indent> <#local spc>${""?left_pad(indent * 4)} <#list cls.members as member> - <#if member.hasBuilder() && !member.hasSubType() && !member.isAbstract()> + <#if member.hasBuilder() && !member.hasSubType() && !member.isAbstract()> ${spc} builder.${member.name}Builder = <@com.builderType member packageName cls.sourceClassName/>.copyOf(bron.get${member.name?cap_first}(), builder); - <#elseif member.hasBuilder() && !member.isAbstract()> + <#elseif member.hasBuilder() && !member.isAbstract()> ${spc} builder.${member.name}Builders = new java.util.ArrayList<>(); ${spc} for (<@com.type member.subType packageName/> original : bron.get${member.name?cap_first}()) { - <#list member.aliases as alias> + <#list member.aliases as alias> ${spc} if (original instanceof <@com.type alias.type packageName/>){ ${spc} builder.${member.name}Builders.add(<@com.type alias.type packageName/>Builder.copyOf((<@com.type alias.type packageName/>) original, builder)); ${spc} } else - - <#local aliasSpc>${spc}<#if member.hasAliases()>${""?left_pad(4)} - <#if member.hasAliases()> + + <#local aliasSpc>${spc}<#if member.hasAliases()>${""?left_pad(4)} + <#if member.hasAliases()> ${spc} { - + ${aliasSpc} builder.${member.name}Builders.add(<@com.builderType member packageName cls.sourceClassName/>.copyOf(original, builder)); - <#if member.hasAliases()> + <#if member.hasAliases()> ${spc} } - + ${spc} } - <#elseif member.isList()> + <#elseif member.isList()> ${spc} builder.${member.name} = new java.util.ArrayList<>(bron.get${member.name?cap_first}()); <#else> ${spc} builder.${member.name} = bron.get${member.name?cap_first}(); + +<#macro javadoc member spc inline> + <#if member.javadoc??> + <#if inline> +${spc} * ${member.javadoc?trim}
+${spc} *
+ <#else> +${spc}/** +${spc} * ${member.javadoc?trim} +${spc} */ + + + + +<#macro javadocAddCollection member spc> +${spc} * this will add the supplied objects to the collection present. If an unmodifiable collection is set using {@link #${member.methodName}(<@com.typeWithoutGenerics member.type packageName/>)} then an Exception can be thrown. + \ No newline at end of file diff --git a/generator/src/main/resources/freemarker/commons.ftl b/generator/src/main/resources/freemarker/commons.ftl index 44a6bf2..99c1427 100644 --- a/generator/src/main/resources/freemarker/commons.ftl +++ b/generator/src/main/resources/freemarker/commons.ftl @@ -1,10 +1,20 @@ <#macro type classType packageName> <@compress single_line=true> - <#if classType.getPackageName() == "java.lang"> - ${classType.getType()?remove_beginning("java.lang.")} - <#else> + <#if classType.getPackageName() == "java.lang"> + ${classType.getType()?remove_beginning("java.lang.")} + <#else> ${classType.getType()?remove_beginning(packageName+".")?replace("<"+packageName+".", "<")} - + + + + +<#macro typeWithoutGenerics classType packageName> +<@compress single_line=true> + <#if classType.getPackageName() == "java.lang"> + ${classType.getTypeWithoutGenerics()?remove_beginning("java.lang.")} + <#else> + ${classType.getTypeWithoutGenerics()?remove_beginning(packageName+".")?replace("<"+packageName+".", "<")} + diff --git a/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/BuildableObject.java b/generator/src/test/java/nl/loxia/builder/generator/ap/test/BuildableObject.java similarity index 64% rename from generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/BuildableObject.java rename to generator/src/test/java/nl/loxia/builder/generator/ap/test/BuildableObject.java index 8ff5dca..a4582f8 100644 --- a/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/BuildableObject.java +++ b/generator/src/test/java/nl/loxia/builder/generator/ap/test/BuildableObject.java @@ -1,7 +1,10 @@ -package nl.loxia.builder.generator.ap.test.constructor; +package nl.loxia.builder.generator.ap.test; import nl.loxia.builder.generator.annotations.Builder; +/** + * This class is used for multiple tests as an object that has a builder of its own. + */ @Builder public class BuildableObject { private String val; diff --git a/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPass.java b/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPass.java index c1e7fe8..c46c78b 100644 --- a/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPass.java +++ b/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPass.java @@ -3,6 +3,7 @@ import java.util.List; import nl.loxia.builder.generator.annotations.Builder; +import nl.loxia.builder.generator.ap.test.BuildableObject; @Builder public class ConstructorPass { diff --git a/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPassTest.java b/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPassTest.java index 55abdee..2a52111 100644 --- a/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPassTest.java +++ b/generator/src/test/java/nl/loxia/builder/generator/ap/test/constructor/ConstructorPassTest.java @@ -7,6 +7,9 @@ import org.mapstruct.ap.testutil.ProcessorTest; import org.mapstruct.ap.testutil.WithClasses; +import nl.loxia.builder.generator.ap.test.BuildableObject; +import nl.loxia.builder.generator.ap.test.BuildableObjectBuilder; + public class ConstructorPassTest { @ProcessorTest diff --git a/generator/src/test/java/nl/loxia/builder/generator/ap/test/javadoc/JavadocAnnotatedFields.java b/generator/src/test/java/nl/loxia/builder/generator/ap/test/javadoc/JavadocAnnotatedFields.java new file mode 100644 index 0000000..f8b875b --- /dev/null +++ b/generator/src/test/java/nl/loxia/builder/generator/ap/test/javadoc/JavadocAnnotatedFields.java @@ -0,0 +1,43 @@ +package nl.loxia.builder.generator.ap.test.javadoc; + +import java.util.ArrayList; +import java.util.List; + +import nl.loxia.builder.generator.annotations.Builder; +import nl.loxia.builder.generator.ap.test.BuildableObject; +import nl.loxia.builder.generator.ap.test.seealso.SeeAlsoAnnotated; + +@Builder +public class JavadocAnnotatedFields { + + /** + * This field is used as an example for javadoc generation on with methods. + */ + private BuildableObject object; + + /** + * List field with javadoc. + */ + private final List list = new ArrayList<>(); + + /** + * See also field with javadoc. + */ + private final List seeAlso = new ArrayList<>(); + + public BuildableObject getObject() { + return object; + } + + public void setObject(BuildableObject object) { + this.object = object; + } + + public List getList() { + return list; + } + + public List getSeeAlso() { + return seeAlso; + } +} diff --git a/generator/src/test/java/nl/loxia/builder/generator/ap/test/javadoc/JavadocTest.java b/generator/src/test/java/nl/loxia/builder/generator/ap/test/javadoc/JavadocTest.java new file mode 100644 index 0000000..7225db9 --- /dev/null +++ b/generator/src/test/java/nl/loxia/builder/generator/ap/test/javadoc/JavadocTest.java @@ -0,0 +1,128 @@ +package nl.loxia.builder.generator.ap.test.javadoc; + +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mapstruct.ap.testutil.ProcessorTest; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.GeneratedSource; + +import nl.loxia.builder.generator.ap.test.BuildableObject; +import nl.loxia.builder.generator.ap.test.seealso.DuplicateField; +import nl.loxia.builder.generator.ap.test.seealso.SeeAlso; +import nl.loxia.builder.generator.ap.test.seealso.SeeAlsoAnnotated; +import nl.loxia.builder.generator.ap.test.seealso.SeeAlsoAnnotated2; +import nl.loxia.builder.generator.ap.test.seealso.SeeAlsoTarget; + +@WithClasses({ JavadocAnnotatedFields.class, BuildableObject.class, SeeAlso.class, + SeeAlsoAnnotated.class, SeeAlsoAnnotated2.class, SeeAlsoTarget.class, DuplicateField.class }) + +public class JavadocTest { + + @RegisterExtension + GeneratedSource generatedSource = new GeneratedSource(); + + @ProcessorTest + void shouldGenerateJavadocAtConstructor() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + "/**", System.lineSeparator(), + " * Generated by RIGD-Loxia Builder generator", System.lineSeparator(), + " */", System.lineSeparator(), + "public class JavadocAnnotatedFieldsBuilder {"); + } + + @ProcessorTest + void shouldGenerateJavadocAtEndMethod() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + " /**", System.lineSeparator(), + " * returns the parent builder if present, otherwise null is returned.", System.lineSeparator(), + " */", System.lineSeparator(), + " public PARENT end() {"); + } + + @ProcessorTest + void shouldGenerateJavadocAtBuildMethod() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + " /**", System.lineSeparator(), + " * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder.", + System.lineSeparator(), + " */", System.lineSeparator(), + " public JavadocAnnotatedFields build() {"); + } + + @ProcessorTest + void shouldGenerateJavadocAtChainingMethod() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + " /**", System.lineSeparator(), + " * This field is used as an example for javadoc generation on with methods.
", System.lineSeparator(), + " *
", System.lineSeparator(), + " * returns a builder for chaining. Use the end() method to return back to the current builder.
", + System.lineSeparator(), + " * Multiple calls to this method will return the same builder.
", System.lineSeparator(), + " * If this is called after {@link #withObject(nl.loxia.builder.generator.ap.test.BuildableObject)} " + + "then this will return a new Builder and the previously set object is lost.", + System.lineSeparator(), + " */", System.lineSeparator(), + " public nl.loxia.builder.generator.ap.test.BuildableObjectBuilder> withObject() {"); + } + + @ProcessorTest + void shouldGenerateJavadocAtSetMethod() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + " /**", System.lineSeparator(), + " * This field is used as an example for javadoc generation on with methods.
", System.lineSeparator(), + " *
", System.lineSeparator(), + " * If this is called after {@link #withObject()} then the Builder is lost.", System.lineSeparator(), + " */", System.lineSeparator(), + " public JavadocAnnotatedFieldsBuilder withObject(nl.loxia.builder.generator.ap.test.BuildableObject object) {"); + } + + @ProcessorTest + void shouldGenerateJavadocAtAddListMethod() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + " /**", System.lineSeparator(), + " * List field with javadoc.
", System.lineSeparator(), + " *
", System.lineSeparator(), + " * Each call to this method creates a new Builder which will be stored in the list. Use the end() method to return back to the current builder.", + System.lineSeparator(), + " */", System.lineSeparator(), + " public nl.loxia.builder.generator.ap.test.BuildableObjectBuilder> addList() {") + .containsSequence( + " /**", System.lineSeparator(), + " * List field with javadoc.
", System.lineSeparator(), + " *
", System.lineSeparator(), + " * this will add the supplied objects to the collection present. If an unmodifiable collection is set " + + "using {@link #withList(java.util.List)} then an Exception can be thrown.", + System.lineSeparator(), + " */", System.lineSeparator(), + " public JavadocAnnotatedFieldsBuilder addList(Iterable list) {") + .containsSequence( + " /**", System.lineSeparator(), + " * List field with javadoc.
", System.lineSeparator(), + " *
", System.lineSeparator(), + " * this will add the supplied objects to the collection present. If an unmodifiable collection is set " + + "using {@link #withList(java.util.List)} then an Exception can be thrown.", + System.lineSeparator(), + " */", System.lineSeparator(), + " public JavadocAnnotatedFieldsBuilder addList(nl.loxia.builder.generator.ap.test.BuildableObject... list) {"); + } + + @ProcessorTest + void shouldGenerateJavadocAtSeeAlsoReferencedMethod() { + generatedSource.forBuilder(JavadocAnnotatedFields.class).content() + .containsSequence( + " /**", System.lineSeparator(), + " * See also field with javadoc.", System.lineSeparator(), + " */", System.lineSeparator(), + " public nl.loxia.builder.generator.ap.test.seealso.SeeAlsoTargetBuilder") + .containsSequence( + " /**", System.lineSeparator(), + " * See also field with javadoc.", System.lineSeparator(), + " */", System.lineSeparator(), + " public nl.loxia.builder.generator.ap.test.seealso.DuplicateFieldBuilder"); + } +} diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/ListHandlingBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/ListHandlingBuilder.java index b675944..8c26211 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/ListHandlingBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/ListHandlingBuilder.java @@ -15,11 +15,17 @@ public ListHandlingBuilder(PARENT parent) { this.parent = parent; } + /** + * This replaces the collection currently present. Any previous calls to addValues are not saved. + */ public ListHandlingBuilder withValues(java.util.List values) { this.values = values; return this; } + /** + * this will add the supplied objects to the collection present. If an unmodifiable collection is set using {@link #withValues(java.util.List)} then an Exception can be thrown. + */ public ListHandlingBuilder addValues(Iterable values) { for (String v : values) { this.values.add(v); @@ -27,6 +33,9 @@ public ListHandlingBuilder addValues(Iterable values) return this; } + /** + * this will add the supplied objects to the collection present. If an unmodifiable collection is set using {@link #withValues(java.util.List)} then an Exception can be thrown. + */ public ListHandlingBuilder addValues(String... values) { for (String v : values) { this.values.add(v); @@ -34,12 +43,18 @@ public ListHandlingBuilder addValues(String... values) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public ListHandling build() { ListHandling result = new ListHandling(); result.getValues().addAll(values); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -61,4 +76,4 @@ public static ListHandlingBuilder copyOf(ListHandling bron, T parentBuild builder.values = new java.util.ArrayList<>(bron.getValues()); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInConstructorBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInConstructorBuilder.java index 01c3d97..cb44a39 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInConstructorBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInConstructorBuilder.java @@ -26,11 +26,17 @@ public SimpleClassAllFieldsInConstructorBuilder withStringField(String s return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public SimpleClassAllFieldsInConstructor build() { SimpleClassAllFieldsInConstructor result = new SimpleClassAllFieldsInConstructor(stringField, booleanField); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -54,4 +60,4 @@ public static SimpleClassAllFieldsInConstructorBuilder copyOf(SimpleClass builder.stringField = bron.getStringField(); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInSetterBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInSetterBuilder.java index cbf3b05..dfffd38 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInSetterBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassAllFieldsInSetterBuilder.java @@ -26,6 +26,9 @@ public SimpleClassAllFieldsInSetterBuilder withStringField(String string return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public SimpleClassAllFieldsInSetter build() { SimpleClassAllFieldsInSetter result = new SimpleClassAllFieldsInSetter(); result.setBooleanField(booleanField); @@ -33,6 +36,9 @@ public SimpleClassAllFieldsInSetter build() { return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -56,4 +62,4 @@ public static SimpleClassAllFieldsInSetterBuilder copyOf(SimpleClassAllFi builder.stringField = bron.getStringField(); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassMixedBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassMixedBuilder.java index a00d34c..dfe8867 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassMixedBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/SimpleClassMixedBuilder.java @@ -26,12 +26,18 @@ public SimpleClassMixedBuilder withStringField(String stringField) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public SimpleClassMixed build() { SimpleClassMixed result = new SimpleClassMixed(stringField); result.setBooleanField(booleanField); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -55,4 +61,4 @@ public static SimpleClassMixedBuilder copyOf(SimpleClassMixed bron, T par builder.stringField = bron.getStringField(); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderChainingBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderChainingBuilder.java index 4fdcb4e..e2d0d85 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderChainingBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderChainingBuilder.java @@ -16,12 +16,20 @@ public BuilderChainingBuilder(PARENT parent) { this.parent = parent; } + /** + * If this is called after {@link #withValue()} then the Builder is lost. + */ public BuilderChainingBuilder withValue(BuilderChainingChild value) { this.value = value; valueBuilder = null; return this; } + /** + * returns a builder for chaining. Use the end() method to return back to the current builder.
+ * Multiple calls to this method will return the same builder.
+ * If this is called after {@link #withValue(BuilderChainingChild)} then this will return a new Builder and the previously set object is lost. + */ public BuilderChainingChildBuilder> withValue() { if (valueBuilder == null) { valueBuilder = new BuilderChainingChildBuilder<>(this); @@ -30,12 +38,18 @@ public BuilderChainingChildBuilder> wit return valueBuilder; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public BuilderChaining build() { BuilderChaining result = new BuilderChaining(); result.setValue(valueBuilder != null ? valueBuilder.build() : value); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -57,4 +71,4 @@ public static BuilderChainingBuilder copyOf(BuilderChaining bron, T paren builder.valueBuilder = BuilderChainingChildBuilder.copyOf(bron.getValue(), builder); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderListChainingBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderListChainingBuilder.java index 3255fa1..13a9c52 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderListChainingBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderchaining/BuilderListChainingBuilder.java @@ -16,12 +16,18 @@ public BuilderListChainingBuilder(PARENT parent) { this.parent = parent; } + /** + * This replaces the collection currently present. Any previous calls to addValues are not saved. + */ public BuilderListChainingBuilder withValues(java.util.List values) { this.values = values; valuesBuilders = new java.util.ArrayList<>(); return this; } + /** + * this will add the supplied objects to the collection present. If an unmodifiable collection is set using {@link #withValues(java.util.List)} then an Exception can be thrown. + */ public BuilderListChainingBuilder addValues(Iterable values) { for (BuilderChainingChild v : values) { this.values.add(v); @@ -29,6 +35,9 @@ public BuilderListChainingBuilder addValues(Iterable addValues(BuilderChainingChild... values) { for (BuilderChainingChild v : values) { this.values.add(v); @@ -36,12 +45,18 @@ public BuilderListChainingBuilder addValues(BuilderChainingChild... valu return this; } + /** + * Each call to this method creates a new Builder which will be stored in the list. Use the end() method to return back to the current builder. + */ public BuilderChainingChildBuilder> addValues() { BuilderChainingChildBuilder> child = new BuilderChainingChildBuilder<>(this); valuesBuilders.add(child); return child; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public BuilderListChaining build() { BuilderListChaining result = new BuilderListChaining(); result.getValues().addAll(values); @@ -51,6 +66,9 @@ public BuilderListChaining build() { return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -78,4 +96,4 @@ public static BuilderListChainingBuilder copyOf(BuilderListChaining bron, } return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceBuilder.java index 39e8f63..6445597 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceBuilder.java @@ -25,6 +25,9 @@ public BuilderInheritenceBuilder withValue(String value) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ @Override public BuilderInheritence build() { BuilderInheritence result = new BuilderInheritence(); @@ -52,4 +55,4 @@ public static BuilderInheritenceBuilder copyOf(BuilderInheritence bron, T builder.value = bron.getValue(); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceOfinnerClassBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceOfinnerClassBuilder.java index f99dac5..15a7f67 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceOfinnerClassBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInheritenceOfinnerClassBuilder.java @@ -21,6 +21,9 @@ public BuilderInheritenceOfinnerClassBuilder withOtherValue(int otherVal } @Override + /** + * If this is called after {@link #withValue()} then the Builder is lost. + */ public BuilderInheritenceOfinnerClassBuilder withValue(BuilderInnerClass.InnerClass value) { this.value = value; valueBuilder = null; @@ -28,6 +31,11 @@ public BuilderInheritenceOfinnerClassBuilder withValue(BuilderInnerClass } @Override + /** + * returns a builder for chaining. Use the end() method to return back to the current builder.
+ * Multiple calls to this method will return the same builder.
+ * If this is called after {@link #withValue(BuilderInnerClass.InnerClass)} then this will return a new Builder and the previously set object is lost. + */ public BuilderInnerClassBuilder.InnerClassBuilder> withValue() { if (valueBuilder == null) { valueBuilder = new BuilderInnerClassBuilder.InnerClassBuilder<>(this); @@ -36,6 +44,9 @@ public BuilderInnerClassBuilder.InnerClassBuilder BuilderInheritenceOfinnerClassBuilder copyOf(BuilderInherit builder.valueBuilder = BuilderInnerClassBuilder.InnerClassBuilder.copyOf(bron.getValue(), builder); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInnerClassBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInnerClassBuilder.java index 15e4c9b..86a4b1b 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInnerClassBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/builderinheritence/BuilderInnerClassBuilder.java @@ -16,12 +16,20 @@ public BuilderInnerClassBuilder(PARENT parent) { this.parent = parent; } + /** + * If this is called after {@link #withValue()} then the Builder is lost. + */ public BuilderInnerClassBuilder withValue(BuilderInnerClass.InnerClass value) { this.value = value; valueBuilder = null; return this; } + /** + * returns a builder for chaining. Use the end() method to return back to the current builder.
+ * Multiple calls to this method will return the same builder.
+ * If this is called after {@link #withValue(BuilderInnerClass.InnerClass)} then this will return a new Builder and the previously set object is lost. + */ public BuilderInnerClassBuilder.InnerClassBuilder> withValue() { if (valueBuilder == null) { valueBuilder = new BuilderInnerClassBuilder.InnerClassBuilder<>(this); @@ -30,12 +38,18 @@ public BuilderInnerClassBuilder.InnerClassBuilder withValue(String value) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public BuilderInnerClass.InnerClass build() { BuilderInnerClass.InnerClass result = new BuilderInnerClass.InnerClass(); result.setValue(value); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -103,4 +123,4 @@ public static InnerClassBuilder copyOf(BuilderInnerClass.InnerClass bron, return builder; } } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/NoPrefixBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/NoPrefixBuilder.java index 85b46e8..b04bf73 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/NoPrefixBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/NoPrefixBuilder.java @@ -26,12 +26,18 @@ public NoPrefixBuilder stringField(String stringField) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public NoPrefix build() { NoPrefix result = new NoPrefix(stringField); result.setBooleanField(booleanField); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -55,4 +61,4 @@ public static NoPrefixBuilder copyOf(NoPrefix bron, T parentBuilder) { builder.stringField = bron.getStringField(); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SetPrefixBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SetPrefixBuilder.java index 9bf0fdb..0388ac9 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SetPrefixBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SetPrefixBuilder.java @@ -26,12 +26,18 @@ public SetPrefixBuilder setStringField(String stringField) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public SetPrefix build() { SetPrefix result = new SetPrefix(stringField); result.setBooleanField(booleanField); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } @@ -55,4 +61,4 @@ public static SetPrefixBuilder copyOf(SetPrefix bron, T parentBuilder) { builder.stringField = bron.getStringField(); return builder; } -} +} \ No newline at end of file diff --git a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SimpleClassMixedBuilder.java b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SimpleClassMixedBuilder.java index bbe8858..c66e480 100644 --- a/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SimpleClassMixedBuilder.java +++ b/generator/src/test/resources/fixtures/nl/loxia/builder/generator/ap/test/methodprefix/SimpleClassMixedBuilder.java @@ -26,12 +26,18 @@ public SimpleClassMixedBuilder witherStringField(String stringField) { return this; } + /** + * returns the build object. For builder chaining use the {@link #end()} method to return the parent builder. + */ public SimpleClassMixed build() { SimpleClassMixed result = new SimpleClassMixed(stringField); result.setBooleanField(booleanField); return result; } + /** + * returns the parent builder if present, otherwise null is returned. + */ public PARENT end() { return parent; } diff --git a/pom.xml b/pom.xml index ab6fb7a..9d89bdc 100644 --- a/pom.xml +++ b/pom.xml @@ -100,6 +100,9 @@ jar + + true +