Skip to content

Commit

Permalink
#41 generate javadoc for builder methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Zegveld authored Dec 5, 2023
1 parent d8de422 commit 4408736
Show file tree
Hide file tree
Showing 29 changed files with 579 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public class BuilderData {
private final SortedSet<BuilderData> 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;

Expand All @@ -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;
}
Expand All @@ -60,20 +58,21 @@ 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() {
return extendedBuilderName != null;
}

/**
* @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. <BR>
* <BR>
* For example it can handle package names like: I.Do.Not.Follow.Java.Conventions
*
* @return the package name for this builder
*/
public String getPackageName() {
Expand Down Expand Up @@ -108,27 +107,37 @@ 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() {
return 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() {
return builderConfiguration.isCopyOfEnabled();
}

/**
* 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) {
this.builderPassingConstructor = builderPassingConstructor;
}

/**
* You can use a constructor that accepts the builder as an argument.<BR>
* <BR>
* For example: class MyClass { ... MyClass(MyClassBuilder builder) { ... } ... }
*
* @return true if the only argument for the constructor is the builder itself.
*/
public boolean isBuilderPassingConstructor() {
Expand Down Expand Up @@ -233,6 +242,8 @@ private List<String> 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() {
Expand All @@ -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() {
Expand All @@ -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;
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down Expand Up @@ -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()))
Expand Down Expand Up @@ -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
Expand All @@ -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<GenerationType> getSurroundingClassesForGeneration(TypeMirror propertyType) {
return typeUtils.getSurroundingClasses(propertyType).stream().map(this::asGenerationType).collect(toList());
}
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -49,7 +56,7 @@ public boolean process(Set<? extends TypeElement> 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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class EnvironmentConfiguration {
private final Optional<String> 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) {
Expand All @@ -21,13 +23,17 @@ 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() {
return copyOfMethodGeneration;
}

/**
* 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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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.
*/
Expand All @@ -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() {
Expand Down
Loading

0 comments on commit 4408736

Please sign in to comment.