• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.squareup.javapoet;
17 
18 import java.io.IOException;
19 import java.lang.reflect.Type;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Set;
24 import javax.lang.model.SourceVersion;
25 import javax.lang.model.element.ElementKind;
26 import javax.lang.model.element.ExecutableElement;
27 import javax.lang.model.element.Modifier;
28 import javax.lang.model.element.VariableElement;
29 
30 import static com.squareup.javapoet.Util.checkArgument;
31 import static com.squareup.javapoet.Util.checkNotNull;
32 
33 /** A generated parameter declaration. */
34 public final class ParameterSpec {
35   public final String name;
36   public final List<AnnotationSpec> annotations;
37   public final Set<Modifier> modifiers;
38   public final TypeName type;
39   public final CodeBlock javadoc;
40 
ParameterSpec(Builder builder)41   private ParameterSpec(Builder builder) {
42     this.name = checkNotNull(builder.name, "name == null");
43     this.annotations = Util.immutableList(builder.annotations);
44     this.modifiers = Util.immutableSet(builder.modifiers);
45     this.type = checkNotNull(builder.type, "type == null");
46     this.javadoc = builder.javadoc.build();
47   }
48 
hasModifier(Modifier modifier)49   public boolean hasModifier(Modifier modifier) {
50     return modifiers.contains(modifier);
51   }
52 
emit(CodeWriter codeWriter, boolean varargs)53   void emit(CodeWriter codeWriter, boolean varargs) throws IOException {
54     codeWriter.emitAnnotations(annotations, true);
55     codeWriter.emitModifiers(modifiers);
56     if (varargs) {
57       TypeName.asArray(type).emit(codeWriter, true);
58     } else {
59       type.emit(codeWriter);
60     }
61     codeWriter.emit(" $L", name);
62   }
63 
equals(Object o)64   @Override public boolean equals(Object o) {
65     if (this == o) return true;
66     if (o == null) return false;
67     if (getClass() != o.getClass()) return false;
68     return toString().equals(o.toString());
69   }
70 
hashCode()71   @Override public int hashCode() {
72     return toString().hashCode();
73   }
74 
toString()75   @Override public String toString() {
76     StringBuilder out = new StringBuilder();
77     try {
78       CodeWriter codeWriter = new CodeWriter(out);
79       emit(codeWriter, false);
80       return out.toString();
81     } catch (IOException e) {
82       throw new AssertionError();
83     }
84   }
85 
get(VariableElement element)86   public static ParameterSpec get(VariableElement element) {
87     checkArgument(element.getKind().equals(ElementKind.PARAMETER), "element is not a parameter");
88 
89     TypeName type = TypeName.get(element.asType());
90     String name = element.getSimpleName().toString();
91     // Copying parameter annotations can be incorrect so we're deliberately not including them.
92     // See https://github.com/square/javapoet/issues/482.
93     return ParameterSpec.builder(type, name)
94         .addModifiers(element.getModifiers())
95         .build();
96   }
97 
parametersOf(ExecutableElement method)98   static List<ParameterSpec> parametersOf(ExecutableElement method) {
99     List<ParameterSpec> result = new ArrayList<>();
100     for (VariableElement parameter : method.getParameters()) {
101       result.add(ParameterSpec.get(parameter));
102     }
103     return result;
104   }
105 
isValidParameterName(String name)106   private static boolean isValidParameterName(String name) {
107     // Allow "this" for explicit receiver parameters
108     // See https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.1.
109     if (name.endsWith(".this")) {
110       return SourceVersion.isIdentifier(name.substring(0, name.length() - ".this".length()));
111     }
112     return name.equals("this") || SourceVersion.isName(name);
113   }
114 
builder(TypeName type, String name, Modifier... modifiers)115   public static Builder builder(TypeName type, String name, Modifier... modifiers) {
116     checkNotNull(type, "type == null");
117     checkArgument(isValidParameterName(name), "not a valid name: %s", name);
118     return new Builder(type, name)
119         .addModifiers(modifiers);
120   }
121 
builder(Type type, String name, Modifier... modifiers)122   public static Builder builder(Type type, String name, Modifier... modifiers) {
123     return builder(TypeName.get(type), name, modifiers);
124   }
125 
toBuilder()126   public Builder toBuilder() {
127     return toBuilder(type, name);
128   }
129 
toBuilder(TypeName type, String name)130   Builder toBuilder(TypeName type, String name) {
131     Builder builder = new Builder(type, name);
132     builder.annotations.addAll(annotations);
133     builder.modifiers.addAll(modifiers);
134     return builder;
135   }
136 
137   public static final class Builder {
138     private final TypeName type;
139     private final String name;
140     private final CodeBlock.Builder javadoc = CodeBlock.builder();
141 
142     public final List<AnnotationSpec> annotations = new ArrayList<>();
143     public final List<Modifier> modifiers = new ArrayList<>();
144 
Builder(TypeName type, String name)145     private Builder(TypeName type, String name) {
146       this.type = type;
147       this.name = name;
148     }
149 
addJavadoc(String format, Object... args)150     public Builder addJavadoc(String format, Object... args) {
151       javadoc.add(format, args);
152       return this;
153     }
154 
addJavadoc(CodeBlock block)155     public Builder addJavadoc(CodeBlock block) {
156       javadoc.add(block);
157       return this;
158     }
159 
addAnnotations(Iterable<AnnotationSpec> annotationSpecs)160     public Builder addAnnotations(Iterable<AnnotationSpec> annotationSpecs) {
161       checkArgument(annotationSpecs != null, "annotationSpecs == null");
162       for (AnnotationSpec annotationSpec : annotationSpecs) {
163         this.annotations.add(annotationSpec);
164       }
165       return this;
166     }
167 
addAnnotation(AnnotationSpec annotationSpec)168     public Builder addAnnotation(AnnotationSpec annotationSpec) {
169       this.annotations.add(annotationSpec);
170       return this;
171     }
172 
addAnnotation(ClassName annotation)173     public Builder addAnnotation(ClassName annotation) {
174       this.annotations.add(AnnotationSpec.builder(annotation).build());
175       return this;
176     }
177 
addAnnotation(Class<?> annotation)178     public Builder addAnnotation(Class<?> annotation) {
179       return addAnnotation(ClassName.get(annotation));
180     }
181 
addModifiers(Modifier... modifiers)182     public Builder addModifiers(Modifier... modifiers) {
183       Collections.addAll(this.modifiers, modifiers);
184       return this;
185     }
186 
addModifiers(Iterable<Modifier> modifiers)187     public Builder addModifiers(Iterable<Modifier> modifiers) {
188       checkNotNull(modifiers, "modifiers == null");
189       for (Modifier modifier : modifiers) {
190         if (!modifier.equals(Modifier.FINAL)) {
191           throw new IllegalStateException("unexpected parameter modifier: " + modifier);
192         }
193         this.modifiers.add(modifier);
194       }
195       return this;
196     }
197 
build()198     public ParameterSpec build() {
199       return new ParameterSpec(this);
200     }
201   }
202 }
203