All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.auto.value.processor.autoannotation.vm Maven / Gradle / Ivy

There is a newer version: 1.11.0
Show newest version
## Copyright (C) 2014 Google, Inc.
##
## 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 each generated AutoAnnotation_Foo_bar class.
## This template uses the Apache Velocity Template Language (VTL).
## The variables ($pkg, $props, and so on) are defined by the fields of AutoAnnotationTemplateVars.
##
## 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.

#macro (cloneArray $a)
  #if ($gwtCompatible)
    `java.util.Arrays`.copyOf($a, ${a}.length)
  #else
    ${a}.clone()
  #end
#end

#if (!$pkg.empty)
package $pkg;
#end

## The following line will be replaced by the required imports during post-processing.
`import`

#if (!$generated.empty)
@${generated}("com.google.auto.value.processor.AutoAnnotationProcessor")
#else
// Generated by com.google.auto.value.processor.AutoAnnotationProcessor
#end
final class $className implements $annotationName {

## Fields

#foreach ($m in $members)
  #if ($params.containsKey($m.toString()))

  private final $m.type $m;

  #else

  private static final $m.type $m = $m.defaultValue;

  #end
#end

## Constructor

  $className(
#foreach ($p in $params.keySet())

      $params[$p].type $members[$p] #if ($foreach.hasNext) , #end
#end ) {
#foreach ($p in $params.keySet())
  #if (!$members[$p].kind.primitive)

    if ($p == null) {
      throw new NullPointerException("Null $p");
    }

  #end

  #if ($members[$p].kind == "ARRAY")
    #if ($params[$p].kind == "ARRAY")

    this.$p = #cloneArray(${p});

    #elseif ($members[$p].typeMirror.componentType.kind.primitive)

    this.$p = ${members[$p].typeMirror.componentType}ArrayFromCollection($p);

    #elseif ($members[$p].arrayOfClassWithBounds)

    @SuppressWarnings({"unchecked", "rawtypes"})
    ${members[$p].componentType}[] ${p}$ = ${p}.toArray(new Class[0]);
    this.$p = ${p}$;

    #else

    this.$p = ${p}.toArray(new ${members[$p].componentType}[0]);

    #end
  #else

    this.$p = $p;

  #end
#end

  }

## annotationType method (defined by the Annotation interface)

  @Override
  public Class annotationType() {
    return ${annotationName}.class;
  }

## Member getters

#foreach ($m in $members)

  @Override
  public ${m.type} ${m}() {

  #if ($m.kind == "ARRAY")

    return #cloneArray(${m});

  #else

    return ${m};

  #end

  }

#end

## toString

#macro (appendMemberString $m)
  #if ($m.typeMirror.toString() == "java.lang.String")
    #set ($appendQuotedStringMethod = "true")

    appendQuoted(sb, $m) ##
  #elseif ($m.typeMirror.toString() == "char")
    #set ($appendQuotedCharMethod = "true")

    appendQuoted(sb, $m) ##
  #elseif ($m.typeMirror.toString() == "java.lang.String[]")
    #set ($appendQuotedStringArrayMethod = "true")

    appendQuoted(sb, $m) ##
  #elseif ($m.typeMirror.toString() == "char[]")
    #set ($appendQuotedCharArrayMethod = "true")

    appendQuoted(sb, $m) ##
  #elseif ($m.kind == "ARRAY")

    sb.append(`java.util.Arrays`.toString($m)) ##
  #else

    sb.append($m) ##
  #end
#end

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder("@$annotationFullName(");

  #foreach ($p in $params.keySet())

    #if ($params.size() > 1 || $params.keySet().iterator().next() != "value")

    sb.append("$p=");
    #end

    #appendMemberString($members[$p]);

    #if ($foreach.hasNext)

    sb.append(", ");
    #end

  #end

    return sb.append(')').toString();
  }

## equals

#macro (memberEqualsThatExpression $m)
  #if ($m.kind == "FLOAT")
    Float.floatToIntBits($m) == Float.floatToIntBits(that.${m}()) ##
  #elseif ($m.kind == "DOUBLE")
    Double.doubleToLongBits($m) == Double.doubleToLongBits(that.${m}()) ##
  #elseif ($m.kind.primitive)
    $m == that.${m}() ##
  #elseif ($m.kind == "ARRAY")
    #if ($params.containsKey($m.toString()))
    `java.util.Arrays`.equals($m,
        (that instanceof $className)
            ? (($className) that).$m
            : that.${m}()) ##
    #else ## default value, so if |that| is also a $className then it has the same constant value
    that instanceof $className || `java.util.Arrays`.equals($m, that.${m}())
    #end
  #else
    ${m}.equals(that.${m}()) ##
  #end
#end

  @Override
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (o instanceof $annotationName) {

  #if ($members.isEmpty())

      return true;

  #else

      $annotationName that = ($annotationName) o;
      return ##
           #foreach ($m in $members)
           (#memberEqualsThatExpression ($m))##
             #if ($foreach.hasNext)

           && ##
             #end
           #end
           ;
  #end

    }
    return false;
  }

## hashCode

#macro (memberHashCodeExpression $m)
  #if ($m.kind == "LONG")
    (int) (($m >>> 32) ^ $m) ##
  #elseif ($m.kind == "FLOAT")
    Float.floatToIntBits($m) ##
  #elseif ($m.kind == "DOUBLE")
    (int) ((Double.doubleToLongBits($m) >>> 32) ^ Double.doubleToLongBits($m)) ##
  #elseif ($m.kind == "BOOLEAN")
    $m ? 1231 : 1237 ##
  #elseif ($m.kind.primitive)
    $m ##
  #elseif ($m.kind == "ARRAY")
    `java.util.Arrays`.hashCode($m) ##
  #else
    ${m}.hashCode() ##
  #end
#end

## Compute the member name's contribution to the hashcode directly in the
## template engine, to avoid triggering a compiler error for integer overflow.
#macro (memberNameHash $m)
  #set ($hc = 127 * $m.toString().hashCode())
  ${hc} ##
#end

## The hashCode is the sum of two parts, an invariable part and a variable part. The invariable part
## comes from defaulted members (ones that don't appear in the @AutoAnnotation method parameters)
## whose values have hash codes that never change. (That doesn't include Class constants, for
## example.) We precompute the invariable part, as an optimization but also in order to avoid
## falling afoul of constant-overflow checks in the compiler.

  @Override
  public int hashCode() {
    return
    ## If the invariable part is 0, we avoid outputting `return 0 + ...` just because it generates
    ## unnecessary byte code. But if there are no members then we must say `return 0;` here.
    #if ($invariableHashSum != 0 || $members.empty)

        $invariableHashSum
        // $invariableHashSum is the contribution from default members $invariableHashes
    #end
    #foreach ($m in $members)
      #if (!$invariableHashes.contains($m.toString()))

        + (#memberNameHash($m) ^ (#memberHashCodeExpression($m)))
            // #memberNameHash($m) is 127 * "${m}".hashCode()
      #end
    #end

        ;

  }

## support functions

#foreach ($w in $wrapperTypesUsedInCollections)
  #set ($prim = $w.getField("TYPE").get(""))

  private static ${prim}[] ${prim}ArrayFromCollection(`java.util.Collection`<${w.simpleName}> c) {
    ${prim}[] a = new ${prim}[c.size()];
    int i = 0;
    for (${prim} x : c) {
      a[i++] = x;
    }
    return a;
  }
#end

#if ($appendQuotedStringArrayMethod)
  #set ($appendQuotedStringMethod = "true")

  private static void appendQuoted(StringBuilder sb, String[] strings) {
    sb.append('[');
    String sep = "";
    for (String s : strings) {
      sb.append(sep);
      sep = ", ";
      appendQuoted(sb, s);
    }
    sb.append(']');
  }
#end

#if ($appendQuotedCharArrayMethod)
  #set ($appendQuotedCharMethod = "true")

  private static void appendQuoted(StringBuilder sb, char[] chars) {
    sb.append('[');
    String sep = "";
    for (char c : chars) {
      sb.append(sep);
      sep = ", ";
      appendQuoted(sb, c);
    }
    sb.append(']');
  }
#end

#if ($appendQuotedStringMethod)
  #set ($appendEscapedMethod = "true")

  private static void appendQuoted(StringBuilder sb, String s) {
    sb.append('"');
    for (int i = 0; i < s.length(); i++) {
      appendEscaped(sb, s.charAt(i));
    }
    sb.append('"');
  }
#end

#if ($appendQuotedCharMethod)
  #set ($appendEscapedMethod = "true")

  private static void appendQuoted(StringBuilder sb, char c) {
    sb.append('\'');
    appendEscaped(sb, c);
    sb.append('\'');
  }
#end

#if ($appendEscapedMethod)
  private static void appendEscaped(StringBuilder sb, char c) {
    switch (c) {
    case '\\':
    case '"':
    case '\'':
      sb.append('\\').append(c);
      break;
    case '\n':
      sb.append("\\n");
      break;
    case '\r':
      sb.append("\\r");
      break;
    case '\t':
      sb.append("\\t");
      break;
    default:
      if (c < 0x20) {
        sb.append('\\');
        appendWithZeroPadding(sb, Integer.toOctalString(c), 3);
      } else if (c < 0x7f || Character.isLetter(c)) {
        sb.append(c);
      } else {
        sb.append("\\u");
        appendWithZeroPadding(sb, Integer.toHexString(c), 4);
      }
      break;
    }
  }

  ## We use this rather than String.format because that doesn't exist on GWT.

  private static void appendWithZeroPadding(StringBuilder sb, String s, int width) {
    for (int i = width - s.length(); i > 0; i--) {
      sb.append('0');
    }
    sb.append(s);
  }
#end
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy