Skip to content
Open
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
<!-- Disable annotation processing for the main (not test!) compilation phase. -->
<executions>
<execution>
<id>compile</id>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
public String setterPrefix() default "set";

/**
* The prefix to use for with methods. Specify {@link AccessorMethods#SUPPRESS_WITHS} to prevent with methods
* The prefix to use for with methods. Specify {@link AccessorMethods#SUPPRESS} to prevent with methods
* from being generated by default.
*/
public String withPrefix() default "with";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,15 @@
* visibility declared in the {@link GenerateBuilder} annotation will be used.
*/
public Visibility visibility() default Visibility.INHERIT;

/**
* A flag indicating, whether or not this parameter is required when instantiating the builder (i.e. a parameter for
* the constructor of the builder).
*/
public boolean requiredOnInstantiation() default false;
/**
* A flag indicating, whether or not this parameter is required when creating the actual object instance (i.e. a
* parameter of the {@link GenerateBuilder#createName() create} method of the builder).
*/
public boolean requiredOnCreation() default false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,23 @@ final class OptionModel {
private final String withName;
private final String defaultExpr;
private final Visibility visiblity;
private final boolean requiredOnInstantiation;
private final boolean requiredOnCreation;



public OptionModel(TypeMirror type, String name, String getterName, String setterName,
String withName, String defaultExpr, Visibility visiblity) {
String withName, String defaultExpr, Visibility visiblity, boolean requiredOnInstantiation,
boolean requiredOnCreation) {
this.type = type;
this.name = name;
this.getterName = getterName;
this.setterName = setterName;
this.withName = withName;
this.defaultExpr = defaultExpr;
this.visiblity = visiblity;
this.requiredOnInstantiation = requiredOnInstantiation;
this.requiredOnCreation = requiredOnCreation;
}

public String getName() {
Expand Down Expand Up @@ -87,4 +92,16 @@ public Visibility getVisibility() {
}



public boolean isRequiredOnInstantiation() {
return requiredOnInstantiation;
}



public boolean isRequiredOnCreation() {
return requiredOnCreation;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ final class SpecModel {
private final List<? extends TypeParameterElement> typeParameters;

private final List<OptionModel> options = new ArrayList<>();
private final List<OptionModel> optionsForInstantiation = new ArrayList<>();
private final List<OptionModel> optionsForCreation = new ArrayList<>();

private final String createName;

Expand Down Expand Up @@ -174,20 +176,34 @@ public SpecModel(ExecutableElement instantiator, ProcessingEnvironment processin
this.defaults = DefaultsModel.create(defaultsTypeElem, processingEnv);


processOptions(util);
processOptions(processingEnv);
}



private void processOptions(Util util) {
private void processOptions(ProcessingEnvironment processingEnv) {
for(VariableElement ve : instantiator.getParameters()) {
OptionModel optModel = processOption(util, ve);
OptionModel optModel = processOption(processingEnv, ve);
this.options.add(optModel);
if (optModel.isRequiredOnCreation()) {
this.optionsForCreation.add(optModel);
}
if (optModel.isRequiredOnInstantiation()) {
this.optionsForInstantiation.add(optModel);
}
}
}

private OptionModel processOption(Util util, VariableElement ve) {
private OptionModel processOption(ProcessingEnvironment processingEnv, VariableElement ve) {
Option ann = ve.getAnnotation(Option.class);

boolean requiredOnInstantiation = ann != null && ann.requiredOnInstantiation();
boolean requiredOnCreation = ann != null && ann.requiredOnCreation();

if (requiredOnInstantiation && requiredOnCreation) {
processingEnv.getMessager().printMessage(Kind.WARNING, "Attribute is required for both instantiation and creation. The value provided at creation will take precedence.", ve);
}

String name = "";
if(ann != null) {
name = ann.name();
Expand All @@ -207,6 +223,12 @@ private OptionModel processOption(Util util, VariableElement ve) {
if("".equals(defaultExpr)) {
defaultExpr = defaults.getDefaultsExpression(name);
}
if((requiredOnInstantiation || requiredOnCreation) && defaultExpr != null) {
processingEnv.getMessager().printMessage(Kind.WARNING, "Attribute has a default expression and is required on instantiation/creation. The value provided at instantiation/creation will take precedence.", ve);
}
if (requiredOnInstantiation) {
defaultExpr = name;
}


TypeMirror type = ve.asType();
Expand All @@ -215,27 +237,36 @@ private OptionModel processOption(Util util, VariableElement ve) {
if(ann != null) {
getterName = ann.getterName();
}
if("".equals(getterName)) {
if (AccessorMethods.SUPPRESS.equals(getterName)) {
getterName = null;
}
else if("".equals(getterName)) {
getterName = getterName(name, tk);
}

String setterName = "";
if(ann != null) {
setterName = ann.setterName();
}
if("".equals(setterName)) {
if (AccessorMethods.SUPPRESS.equals(setterName)) {
setterName = null;
}
else if("".equals(setterName)) {
setterName = setterName(name, tk);
}

String withName = "";
if(ann != null) {
withName = ann.withName();
}
if(withName.isEmpty()) {
if (AccessorMethods.SUPPRESS.equals(withName)) {
withName = null;
}
else if("".equals(withName)) {
withName = withName(name, tk);
}

OptionModel optModel = new OptionModel(type, name, getterName, setterName, withName, defaultExpr, Visibility.PRIVATE);
OptionModel optModel = new OptionModel(type, name, getterName, setterName, withName, defaultExpr, Visibility.PRIVATE, requiredOnInstantiation, requiredOnCreation);

return optModel;
}
Expand Down Expand Up @@ -314,6 +345,14 @@ public List<OptionModel> getOptions() {
return options;
}

public List<OptionModel> getOptionsForInstantiation() {
return optionsForInstantiation;
}

public List<OptionModel> getOptionsForCreation() {
return optionsForCreation;
}


public List<? extends TypeParameterElement> getTypeParameters() {
return typeParameters;
Expand Down
19 changes: 13 additions & 6 deletions src/main/resources/stringtemplates/builder-source.stg
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,15 @@ option_defn(opt) ::= <<
>>

ctor_defn(spec) ::= <<
public <spec.name>() {
public <spec.name>(<ctor_params(spec)>) {
<spec.options:{opt | <option_init(opt)>}; separator="\n">
}
>>

ctor_params(spec) ::= <<
<spec.optionsForInstantiation:{opt | <opt.type> <opt.name>}; separator=", ">
>>

option_init(opt) ::= <<
<if(opt.defaultExpr)>this.<opt.name> = <opt.defaultExpr>;<endif>
>>
Expand All @@ -93,19 +97,22 @@ throws_decl(types) ::= <<


create_defn(spec) ::= <<
public <spec.instanceType; format="TypeMirror"> <spec.createName>() <throws_decl(spec.instantiator.thrownTypes)>{
public <spec.instanceType; format="TypeMirror"> <spec.createName>(<create_params(spec)>) <throws_decl(spec.instantiator.thrownTypes)>{
return $createDispatch(
<spec.options:{opt | this.<opt.name>}; separator=",\n">
<spec.options:{opt | <opt.name>}; separator=",\n">
);
}
>>

create_params(spec) ::= <<
<spec.optionsForCreation:{opt | <opt.type> <opt.name>}; separator=", ">
>>


option_methods(opt, spec) ::= <<
<getter(opt)>
<setter(opt)>
<with(opt, spec)>
<if(opt.getterName)><getter(opt)><endif>
<if(opt.setterName)><setter(opt)><endif>
<if(opt.withName)><with(opt, spec)><endif>
>>

getter(opt) ::= <<
Expand Down