blob: 630330cafa056c981111c6488527901d5144fd64 [file] [log] [blame]
## Copyright 2014 Google LLC
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##
##
## Template for AutoValue and AutoBuilder builders.
## This template uses the Apache Velocity Template Language (VTL).
## The variables ($isFinal, $props, and so on) are defined by the fields of AutoValueOrBuilderTemplateVars.
##
## Comments, like this one, begin with ##. The comment text extends up to and including the newline
## character at the end of the line. So comments also serve to join a line to the next one.
## Velocity deletes a newline after a directive (#if, #foreach, #end etc) so ## is not needed there.
## That does mean that we sometimes need an extra blank line after such a directive.
##
## Post-processing will remove unwanted spaces and blank lines, but will not join two lines.
## It will also replace classes spelled as (e.g.) `java.util.Arrays`, with the backquotes, to
## use just Arrays if that class can be imported unambiguously, or java.util.Arrays if not.
##
#foreach ($a in $builderAnnotations)
$a
#end
#if (!$autoBuilder) static #end##
#if ($isFinal) final #end##
class ${builderName}${builderFormalTypes} ##
#if ($builderIsInterface) implements #else extends #end
${builderTypeName}${builderActualTypes} {
#foreach ($p in $props)
#if ($p.kind.primitive)
private $types.boxedClass($p.typeMirror).simpleName $p;
#else
#if ($builderPropertyBuilders[$p.name])
## If you have ImmutableList.Builder<String> stringsBuilder() then we define two fields:
## private ImmutableList.Builder<String> stringsBuilder$;
## private ImmutableList<String> strings;
private ${builderPropertyBuilders[$p.name].builderType} ##
${builderPropertyBuilders[$p.name].name};
#end
private $p.type $p #if ($p.optional && !$p.nullable) = $p.optional.empty #end ;
#end
#end
${builderName}() {
}
#if ($toBuilderConstructor)
private ${builderName}(${origClass}${actualTypes} source) {
#foreach ($p in $props)
this.$p = source.${p.getter}();
#end
}
#end
#foreach ($p in $props)
## The following is either null or an instance of PropertyBuilderClassifier.PropertyBuilder
#set ($propertyBuilder = $builderPropertyBuilders[$p.name])
## Setter and/or property builder
#foreach ($setter in $builderSetters[$p.name])
@`java.lang.Override`
${setter.access}${builderTypeName}${builderActualTypes} ##
${setter.name}(${setter.nullableAnnotation}$setter.parameterType $p) {
## Omit null check for primitive, or @Nullable, or if we are going to be calling a copy method
## such as Optional.of, which will have its own null check if appropriate.
#if (!$setter.primitiveParameter && !$p.nullable && ${setter.copy($p)} == $p)
#if ($identifiers)
if ($p == null) {
throw new NullPointerException("Null $p.name");
}
#else
## Just throw NullPointerException with no message if it's null.
## The Object cast has no effect on the code but silences an ErrorProne warning.
((`java.lang.Object`) ${p}).getClass();
#end
#end
#if ($propertyBuilder)
if (${propertyBuilder.name} != null) {
throw new IllegalStateException(#if ($identifiers)"Cannot set $p after calling ${p.name}Builder()"#end);
}
#end
this.$p = ${setter.copy($p)};
return this;
}
#end
#if ($propertyBuilder)
@`java.lang.Override`
${propertyBuilder.access}$propertyBuilder.builderType ${p.name}Builder($propertyBuilder.propertyBuilderMethodParameters) {
if (${propertyBuilder.name} == null) {
## This is the first time someone has asked for the builder. If the property it sets already
## has a value (because it came from a toBuilder() call on the AutoValue class, or because
## there is also a setter for this property) then we copy that value into the builder.
## Otherwise the builder starts out empty.
## If we have neither a setter nor a toBuilder() method, then the builder always starts
## off empty.
#if ($builderSetters[$p.name].empty && $toBuilderMethods.empty)
${propertyBuilder.name} = ${propertyBuilder.initializer};
#else
if ($p == null) {
${propertyBuilder.name} = ${propertyBuilder.initializer};
} else {
#if (${propertyBuilder.builtToBuilder})
${propertyBuilder.name} = ${p}.${propertyBuilder.builtToBuilder}();
#else
${propertyBuilder.name} = ${propertyBuilder.initializer};
${propertyBuilder.name}.${propertyBuilder.copyAll}($p);
#end
$p = null;
}
#end
} #if (!$propertyBuilder.propertyBuilderMethodParameters.empty) else {
## This check only happens if the property-builder method has a parameter.
## We don't know if the existing builder was created with the same parameter,
## so we throw to avoid possibly giving you a builder that is different from
## the one you asked for.
throw new IllegalStateException("Property builder for $p.name is already defined");
}
#end
return $propertyBuilder.name;
}
#end
## Getter
#if ($builderGetters[$p.name])
@`java.lang.Override`
${p.nullableAnnotation}${builderGetters[$p.name].access}$builderGetters[$p.name].type ${p.getter}() {
#if ($builderGetters[$p.name].optional)
if ($p == null) {
return $builderGetters[$p.name].optional.empty;
} else {
return ${builderGetters[$p.name].optional.rawType}.of($p);
}
#else
#if ($builderRequiredProperties.contains($p))
if ($p == null) {
throw new IllegalStateException(#if ($identifiers)"Property \"$p.name\" has not been set"#end);
}
#end
#if ($propertyBuilder)
if (${propertyBuilder.name} != null) {
return ${propertyBuilder.name}.build();
}
if ($p == null) {
${propertyBuilder.beforeInitDefault}
$p = ${propertyBuilder.initDefault};
}
#end
return $p;
#end
}
#end
#end
## build() method
@`java.lang.Override`
${buildMethod.get().access}${builtType} ${buildMethod.get().name}() ${buildMethod.get().throws} {
#foreach ($p in $props)
#set ($propertyBuilder = $builderPropertyBuilders[$p.name])
#if ($propertyBuilder)
if (${propertyBuilder.name} != null) {
this.$p = ${propertyBuilder.name}.build();
} else if (this.$p == null) {
${propertyBuilder.beforeInitDefault}
this.$p = ${propertyBuilder.initDefault};
}
#end
#end
#if (!$builderRequiredProperties.empty)
if (#foreach ($p in $builderRequiredProperties)##
this.$p == null##
#if ($foreach.hasNext)
|| #end
#end) {
#if ($identifiers) ## build a friendly message showing all missing properties
#if ($builderRequiredProperties.size() == 1)
`java.lang.String` missing = " $builderRequiredProperties.iterator().next()";
#else
`java.lang.StringBuilder` missing = new `java.lang.StringBuilder`();
#foreach ($p in $builderRequiredProperties)
if (this.$p == null) {
missing.append(" $p.name");
}
#end
#end
throw new IllegalStateException("Missing required properties:" + missing);
#else ## just throw an exception if anything is missing
throw new IllegalStateException();
#end
}
#end
#if ($builtType != "void") return #end ${build}(
#foreach ($p in $props)
this.$p #if ($foreach.hasNext) , #end
#end );
}
}