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.ParameterizedType; 20 import java.lang.reflect.Type; 21 import java.util.ArrayList; 22 import java.util.Arrays; 23 import java.util.Collections; 24 import java.util.EnumSet; 25 import java.util.HashSet; 26 import java.util.Iterator; 27 import java.util.LinkedHashMap; 28 import java.util.LinkedHashSet; 29 import java.util.List; 30 import java.util.Locale; 31 import java.util.Map; 32 import java.util.Set; 33 import javax.lang.model.SourceVersion; 34 import javax.lang.model.element.Element; 35 import javax.lang.model.element.Modifier; 36 import javax.lang.model.element.TypeElement; 37 import javax.lang.model.type.DeclaredType; 38 import javax.lang.model.type.NoType; 39 import javax.lang.model.type.TypeMirror; 40 import javax.lang.model.util.ElementFilter; 41 42 import static com.squareup.javapoet.Util.checkArgument; 43 import static com.squareup.javapoet.Util.checkNotNull; 44 import static com.squareup.javapoet.Util.checkState; 45 import static com.squareup.javapoet.Util.requireExactlyOneOf; 46 47 /** A generated class, interface, or enum declaration. */ 48 public final class TypeSpec { 49 public final Kind kind; 50 public final String name; 51 public final CodeBlock anonymousTypeArguments; 52 public final CodeBlock javadoc; 53 public final List<AnnotationSpec> annotations; 54 public final Set<Modifier> modifiers; 55 public final List<TypeVariableName> typeVariables; 56 public final TypeName superclass; 57 public final List<TypeName> superinterfaces; 58 public final Map<String, TypeSpec> enumConstants; 59 public final List<FieldSpec> fieldSpecs; 60 public final CodeBlock staticBlock; 61 public final CodeBlock initializerBlock; 62 public final List<MethodSpec> methodSpecs; 63 public final List<TypeSpec> typeSpecs; 64 final Set<String> nestedTypesSimpleNames; 65 public final List<Element> originatingElements; 66 public final Set<String> alwaysQualifiedNames; 67 TypeSpec(Builder builder)68 private TypeSpec(Builder builder) { 69 this.kind = builder.kind; 70 this.name = builder.name; 71 this.anonymousTypeArguments = builder.anonymousTypeArguments; 72 this.javadoc = builder.javadoc.build(); 73 this.annotations = Util.immutableList(builder.annotations); 74 this.modifiers = Util.immutableSet(builder.modifiers); 75 this.typeVariables = Util.immutableList(builder.typeVariables); 76 this.superclass = builder.superclass; 77 this.superinterfaces = Util.immutableList(builder.superinterfaces); 78 this.enumConstants = Util.immutableMap(builder.enumConstants); 79 this.fieldSpecs = Util.immutableList(builder.fieldSpecs); 80 this.staticBlock = builder.staticBlock.build(); 81 this.initializerBlock = builder.initializerBlock.build(); 82 this.methodSpecs = Util.immutableList(builder.methodSpecs); 83 this.typeSpecs = Util.immutableList(builder.typeSpecs); 84 this.alwaysQualifiedNames = Util.immutableSet(builder.alwaysQualifiedNames); 85 86 nestedTypesSimpleNames = new HashSet<>(builder.typeSpecs.size()); 87 List<Element> originatingElementsMutable = new ArrayList<>(); 88 originatingElementsMutable.addAll(builder.originatingElements); 89 for (TypeSpec typeSpec : builder.typeSpecs) { 90 nestedTypesSimpleNames.add(typeSpec.name); 91 originatingElementsMutable.addAll(typeSpec.originatingElements); 92 } 93 94 this.originatingElements = Util.immutableList(originatingElementsMutable); 95 } 96 97 /** 98 * Creates a dummy type spec for type-resolution only (in CodeWriter) 99 * while emitting the type declaration but before entering the type body. 100 */ TypeSpec(TypeSpec type)101 private TypeSpec(TypeSpec type) { 102 assert type.anonymousTypeArguments == null; 103 this.kind = type.kind; 104 this.name = type.name; 105 this.anonymousTypeArguments = null; 106 this.javadoc = type.javadoc; 107 this.annotations = Collections.emptyList(); 108 this.modifiers = Collections.emptySet(); 109 this.typeVariables = Collections.emptyList(); 110 this.superclass = null; 111 this.superinterfaces = Collections.emptyList(); 112 this.enumConstants = Collections.emptyMap(); 113 this.fieldSpecs = Collections.emptyList(); 114 this.staticBlock = type.staticBlock; 115 this.initializerBlock = type.initializerBlock; 116 this.methodSpecs = Collections.emptyList(); 117 this.typeSpecs = Collections.emptyList(); 118 this.originatingElements = Collections.emptyList(); 119 this.nestedTypesSimpleNames = Collections.emptySet(); 120 this.alwaysQualifiedNames = Collections.emptySet(); 121 } 122 hasModifier(Modifier modifier)123 public boolean hasModifier(Modifier modifier) { 124 return modifiers.contains(modifier); 125 } 126 classBuilder(String name)127 public static Builder classBuilder(String name) { 128 return new Builder(Kind.CLASS, checkNotNull(name, "name == null"), null); 129 } 130 classBuilder(ClassName className)131 public static Builder classBuilder(ClassName className) { 132 return classBuilder(checkNotNull(className, "className == null").simpleName()); 133 } 134 interfaceBuilder(String name)135 public static Builder interfaceBuilder(String name) { 136 return new Builder(Kind.INTERFACE, checkNotNull(name, "name == null"), null); 137 } 138 interfaceBuilder(ClassName className)139 public static Builder interfaceBuilder(ClassName className) { 140 return interfaceBuilder(checkNotNull(className, "className == null").simpleName()); 141 } 142 enumBuilder(String name)143 public static Builder enumBuilder(String name) { 144 return new Builder(Kind.ENUM, checkNotNull(name, "name == null"), null); 145 } 146 enumBuilder(ClassName className)147 public static Builder enumBuilder(ClassName className) { 148 return enumBuilder(checkNotNull(className, "className == null").simpleName()); 149 } 150 anonymousClassBuilder(String typeArgumentsFormat, Object... args)151 public static Builder anonymousClassBuilder(String typeArgumentsFormat, Object... args) { 152 return anonymousClassBuilder(CodeBlock.of(typeArgumentsFormat, args)); 153 } 154 anonymousClassBuilder(CodeBlock typeArguments)155 public static Builder anonymousClassBuilder(CodeBlock typeArguments) { 156 return new Builder(Kind.CLASS, null, typeArguments); 157 } 158 annotationBuilder(String name)159 public static Builder annotationBuilder(String name) { 160 return new Builder(Kind.ANNOTATION, checkNotNull(name, "name == null"), null); 161 } 162 annotationBuilder(ClassName className)163 public static Builder annotationBuilder(ClassName className) { 164 return annotationBuilder(checkNotNull(className, "className == null").simpleName()); 165 } 166 toBuilder()167 public Builder toBuilder() { 168 Builder builder = new Builder(kind, name, anonymousTypeArguments); 169 builder.javadoc.add(javadoc); 170 builder.annotations.addAll(annotations); 171 builder.modifiers.addAll(modifiers); 172 builder.typeVariables.addAll(typeVariables); 173 builder.superclass = superclass; 174 builder.superinterfaces.addAll(superinterfaces); 175 builder.enumConstants.putAll(enumConstants); 176 builder.fieldSpecs.addAll(fieldSpecs); 177 builder.methodSpecs.addAll(methodSpecs); 178 builder.typeSpecs.addAll(typeSpecs); 179 builder.initializerBlock.add(initializerBlock); 180 builder.staticBlock.add(staticBlock); 181 builder.originatingElements.addAll(originatingElements); 182 builder.alwaysQualifiedNames.addAll(alwaysQualifiedNames); 183 return builder; 184 } 185 emit(CodeWriter codeWriter, String enumName, Set<Modifier> implicitModifiers)186 void emit(CodeWriter codeWriter, String enumName, Set<Modifier> implicitModifiers) 187 throws IOException { 188 // Nested classes interrupt wrapped line indentation. Stash the current wrapping state and put 189 // it back afterwards when this type is complete. 190 int previousStatementLine = codeWriter.statementLine; 191 codeWriter.statementLine = -1; 192 193 try { 194 if (enumName != null) { 195 codeWriter.emitJavadoc(javadoc); 196 codeWriter.emitAnnotations(annotations, false); 197 codeWriter.emit("$L", enumName); 198 if (!anonymousTypeArguments.formatParts.isEmpty()) { 199 codeWriter.emit("("); 200 codeWriter.emit(anonymousTypeArguments); 201 codeWriter.emit(")"); 202 } 203 if (fieldSpecs.isEmpty() && methodSpecs.isEmpty() && typeSpecs.isEmpty()) { 204 return; // Avoid unnecessary braces "{}". 205 } 206 codeWriter.emit(" {\n"); 207 } else if (anonymousTypeArguments != null) { 208 TypeName supertype = !superinterfaces.isEmpty() ? superinterfaces.get(0) : superclass; 209 codeWriter.emit("new $T(", supertype); 210 codeWriter.emit(anonymousTypeArguments); 211 codeWriter.emit(") {\n"); 212 } else { 213 // Push an empty type (specifically without nested types) for type-resolution. 214 codeWriter.pushType(new TypeSpec(this)); 215 216 codeWriter.emitJavadoc(javadoc); 217 codeWriter.emitAnnotations(annotations, false); 218 codeWriter.emitModifiers(modifiers, Util.union(implicitModifiers, kind.asMemberModifiers)); 219 if (kind == Kind.ANNOTATION) { 220 codeWriter.emit("$L $L", "@interface", name); 221 } else { 222 codeWriter.emit("$L $L", kind.name().toLowerCase(Locale.US), name); 223 } 224 codeWriter.emitTypeVariables(typeVariables); 225 226 List<TypeName> extendsTypes; 227 List<TypeName> implementsTypes; 228 if (kind == Kind.INTERFACE) { 229 extendsTypes = superinterfaces; 230 implementsTypes = Collections.emptyList(); 231 } else { 232 extendsTypes = superclass.equals(ClassName.OBJECT) 233 ? Collections.emptyList() 234 : Collections.singletonList(superclass); 235 implementsTypes = superinterfaces; 236 } 237 238 if (!extendsTypes.isEmpty()) { 239 codeWriter.emit(" extends"); 240 boolean firstType = true; 241 for (TypeName type : extendsTypes) { 242 if (!firstType) codeWriter.emit(","); 243 codeWriter.emit(" $T", type); 244 firstType = false; 245 } 246 } 247 248 if (!implementsTypes.isEmpty()) { 249 codeWriter.emit(" implements"); 250 boolean firstType = true; 251 for (TypeName type : implementsTypes) { 252 if (!firstType) codeWriter.emit(","); 253 codeWriter.emit(" $T", type); 254 firstType = false; 255 } 256 } 257 258 codeWriter.popType(); 259 260 codeWriter.emit(" {\n"); 261 } 262 263 codeWriter.pushType(this); 264 codeWriter.indent(); 265 boolean firstMember = true; 266 for (Iterator<Map.Entry<String, TypeSpec>> i = enumConstants.entrySet().iterator(); 267 i.hasNext(); ) { 268 Map.Entry<String, TypeSpec> enumConstant = i.next(); 269 if (!firstMember) codeWriter.emit("\n"); 270 enumConstant.getValue().emit(codeWriter, enumConstant.getKey(), Collections.emptySet()); 271 firstMember = false; 272 if (i.hasNext()) { 273 codeWriter.emit(",\n"); 274 } else if (!fieldSpecs.isEmpty() || !methodSpecs.isEmpty() || !typeSpecs.isEmpty()) { 275 codeWriter.emit(";\n"); 276 } else { 277 codeWriter.emit("\n"); 278 } 279 } 280 281 // Static fields. 282 for (FieldSpec fieldSpec : fieldSpecs) { 283 if (!fieldSpec.hasModifier(Modifier.STATIC)) continue; 284 if (!firstMember) codeWriter.emit("\n"); 285 fieldSpec.emit(codeWriter, kind.implicitFieldModifiers); 286 firstMember = false; 287 } 288 289 if (!staticBlock.isEmpty()) { 290 if (!firstMember) codeWriter.emit("\n"); 291 codeWriter.emit(staticBlock); 292 firstMember = false; 293 } 294 295 // Non-static fields. 296 for (FieldSpec fieldSpec : fieldSpecs) { 297 if (fieldSpec.hasModifier(Modifier.STATIC)) continue; 298 if (!firstMember) codeWriter.emit("\n"); 299 fieldSpec.emit(codeWriter, kind.implicitFieldModifiers); 300 firstMember = false; 301 } 302 303 // Initializer block. 304 if (!initializerBlock.isEmpty()) { 305 if (!firstMember) codeWriter.emit("\n"); 306 codeWriter.emit(initializerBlock); 307 firstMember = false; 308 } 309 310 // Constructors. 311 for (MethodSpec methodSpec : methodSpecs) { 312 if (!methodSpec.isConstructor()) continue; 313 if (!firstMember) codeWriter.emit("\n"); 314 methodSpec.emit(codeWriter, name, kind.implicitMethodModifiers); 315 firstMember = false; 316 } 317 318 // Methods (static and non-static). 319 for (MethodSpec methodSpec : methodSpecs) { 320 if (methodSpec.isConstructor()) continue; 321 if (!firstMember) codeWriter.emit("\n"); 322 methodSpec.emit(codeWriter, name, kind.implicitMethodModifiers); 323 firstMember = false; 324 } 325 326 // Types. 327 for (TypeSpec typeSpec : typeSpecs) { 328 if (!firstMember) codeWriter.emit("\n"); 329 typeSpec.emit(codeWriter, null, kind.implicitTypeModifiers); 330 firstMember = false; 331 } 332 333 codeWriter.unindent(); 334 codeWriter.popType(); 335 codeWriter.popTypeVariables(typeVariables); 336 337 codeWriter.emit("}"); 338 if (enumName == null && anonymousTypeArguments == null) { 339 codeWriter.emit("\n"); // If this type isn't also a value, include a trailing newline. 340 } 341 } finally { 342 codeWriter.statementLine = previousStatementLine; 343 } 344 } 345 equals(Object o)346 @Override public boolean equals(Object o) { 347 if (this == o) return true; 348 if (o == null) return false; 349 if (getClass() != o.getClass()) return false; 350 return toString().equals(o.toString()); 351 } 352 hashCode()353 @Override public int hashCode() { 354 return toString().hashCode(); 355 } 356 toString()357 @Override public String toString() { 358 StringBuilder out = new StringBuilder(); 359 try { 360 CodeWriter codeWriter = new CodeWriter(out); 361 emit(codeWriter, null, Collections.emptySet()); 362 return out.toString(); 363 } catch (IOException e) { 364 throw new AssertionError(); 365 } 366 } 367 368 public enum Kind { 369 CLASS( 370 Collections.emptySet(), 371 Collections.emptySet(), 372 Collections.emptySet(), 373 Collections.emptySet()), 374 375 INTERFACE( 376 Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)), 377 Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.ABSTRACT)), 378 Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC)), 379 Util.immutableSet(Collections.singletonList(Modifier.STATIC))), 380 381 ENUM( 382 Collections.emptySet(), 383 Collections.emptySet(), 384 Collections.emptySet(), 385 Collections.singleton(Modifier.STATIC)), 386 387 ANNOTATION( 388 Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)), 389 Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.ABSTRACT)), 390 Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC)), 391 Util.immutableSet(Collections.singletonList(Modifier.STATIC))); 392 393 private final Set<Modifier> implicitFieldModifiers; 394 private final Set<Modifier> implicitMethodModifiers; 395 private final Set<Modifier> implicitTypeModifiers; 396 private final Set<Modifier> asMemberModifiers; 397 Kind(Set<Modifier> implicitFieldModifiers, Set<Modifier> implicitMethodModifiers, Set<Modifier> implicitTypeModifiers, Set<Modifier> asMemberModifiers)398 Kind(Set<Modifier> implicitFieldModifiers, 399 Set<Modifier> implicitMethodModifiers, 400 Set<Modifier> implicitTypeModifiers, 401 Set<Modifier> asMemberModifiers) { 402 this.implicitFieldModifiers = implicitFieldModifiers; 403 this.implicitMethodModifiers = implicitMethodModifiers; 404 this.implicitTypeModifiers = implicitTypeModifiers; 405 this.asMemberModifiers = asMemberModifiers; 406 } 407 } 408 409 public static final class Builder { 410 private final Kind kind; 411 private final String name; 412 private final CodeBlock anonymousTypeArguments; 413 414 private final CodeBlock.Builder javadoc = CodeBlock.builder(); 415 private TypeName superclass = ClassName.OBJECT; 416 private final CodeBlock.Builder staticBlock = CodeBlock.builder(); 417 private final CodeBlock.Builder initializerBlock = CodeBlock.builder(); 418 419 public final Map<String, TypeSpec> enumConstants = new LinkedHashMap<>(); 420 public final List<AnnotationSpec> annotations = new ArrayList<>(); 421 public final List<Modifier> modifiers = new ArrayList<>(); 422 public final List<TypeVariableName> typeVariables = new ArrayList<>(); 423 public final List<TypeName> superinterfaces = new ArrayList<>(); 424 public final List<FieldSpec> fieldSpecs = new ArrayList<>(); 425 public final List<MethodSpec> methodSpecs = new ArrayList<>(); 426 public final List<TypeSpec> typeSpecs = new ArrayList<>(); 427 public final List<Element> originatingElements = new ArrayList<>(); 428 public final Set<String> alwaysQualifiedNames = new LinkedHashSet<>(); 429 Builder(Kind kind, String name, CodeBlock anonymousTypeArguments)430 private Builder(Kind kind, String name, 431 CodeBlock anonymousTypeArguments) { 432 checkArgument(name == null || SourceVersion.isName(name), "not a valid name: %s", name); 433 this.kind = kind; 434 this.name = name; 435 this.anonymousTypeArguments = anonymousTypeArguments; 436 } 437 addJavadoc(String format, Object... args)438 public Builder addJavadoc(String format, Object... args) { 439 javadoc.add(format, args); 440 return this; 441 } 442 addJavadoc(CodeBlock block)443 public Builder addJavadoc(CodeBlock block) { 444 javadoc.add(block); 445 return this; 446 } 447 addAnnotations(Iterable<AnnotationSpec> annotationSpecs)448 public Builder addAnnotations(Iterable<AnnotationSpec> annotationSpecs) { 449 checkArgument(annotationSpecs != null, "annotationSpecs == null"); 450 for (AnnotationSpec annotationSpec : annotationSpecs) { 451 this.annotations.add(annotationSpec); 452 } 453 return this; 454 } 455 addAnnotation(AnnotationSpec annotationSpec)456 public Builder addAnnotation(AnnotationSpec annotationSpec) { 457 checkNotNull(annotationSpec, "annotationSpec == null"); 458 this.annotations.add(annotationSpec); 459 return this; 460 } 461 addAnnotation(ClassName annotation)462 public Builder addAnnotation(ClassName annotation) { 463 return addAnnotation(AnnotationSpec.builder(annotation).build()); 464 } 465 addAnnotation(Class<?> annotation)466 public Builder addAnnotation(Class<?> annotation) { 467 return addAnnotation(ClassName.get(annotation)); 468 } 469 addModifiers(Modifier... modifiers)470 public Builder addModifiers(Modifier... modifiers) { 471 Collections.addAll(this.modifiers, modifiers); 472 return this; 473 } 474 addTypeVariables(Iterable<TypeVariableName> typeVariables)475 public Builder addTypeVariables(Iterable<TypeVariableName> typeVariables) { 476 checkArgument(typeVariables != null, "typeVariables == null"); 477 for (TypeVariableName typeVariable : typeVariables) { 478 this.typeVariables.add(typeVariable); 479 } 480 return this; 481 } 482 addTypeVariable(TypeVariableName typeVariable)483 public Builder addTypeVariable(TypeVariableName typeVariable) { 484 typeVariables.add(typeVariable); 485 return this; 486 } 487 superclass(TypeName superclass)488 public Builder superclass(TypeName superclass) { 489 checkState(this.kind == Kind.CLASS, "only classes have super classes, not " + this.kind); 490 checkState(this.superclass == ClassName.OBJECT, 491 "superclass already set to " + this.superclass); 492 checkArgument(!superclass.isPrimitive(), "superclass may not be a primitive"); 493 this.superclass = superclass; 494 return this; 495 } 496 superclass(Type superclass)497 public Builder superclass(Type superclass) { 498 return superclass(superclass, true); 499 } 500 superclass(Type superclass, boolean avoidNestedTypeNameClashes)501 public Builder superclass(Type superclass, boolean avoidNestedTypeNameClashes) { 502 superclass(TypeName.get(superclass)); 503 if (avoidNestedTypeNameClashes) { 504 Class<?> clazz = getRawType(superclass); 505 if (clazz != null) { 506 avoidClashesWithNestedClasses(clazz); 507 } 508 } 509 return this; 510 } 511 superclass(TypeMirror superclass)512 public Builder superclass(TypeMirror superclass) { 513 return superclass(superclass, true); 514 } 515 superclass(TypeMirror superclass, boolean avoidNestedTypeNameClashes)516 public Builder superclass(TypeMirror superclass, boolean avoidNestedTypeNameClashes) { 517 superclass(TypeName.get(superclass)); 518 if (avoidNestedTypeNameClashes && superclass instanceof DeclaredType) { 519 TypeElement superInterfaceElement = 520 (TypeElement) ((DeclaredType) superclass).asElement(); 521 avoidClashesWithNestedClasses(superInterfaceElement); 522 } 523 return this; 524 } 525 addSuperinterfaces(Iterable<? extends TypeName> superinterfaces)526 public Builder addSuperinterfaces(Iterable<? extends TypeName> superinterfaces) { 527 checkArgument(superinterfaces != null, "superinterfaces == null"); 528 for (TypeName superinterface : superinterfaces) { 529 addSuperinterface(superinterface); 530 } 531 return this; 532 } 533 addSuperinterface(TypeName superinterface)534 public Builder addSuperinterface(TypeName superinterface) { 535 checkArgument(superinterface != null, "superinterface == null"); 536 this.superinterfaces.add(superinterface); 537 return this; 538 } 539 addSuperinterface(Type superinterface)540 public Builder addSuperinterface(Type superinterface) { 541 return addSuperinterface(superinterface, true); 542 } 543 addSuperinterface(Type superinterface, boolean avoidNestedTypeNameClashes)544 public Builder addSuperinterface(Type superinterface, boolean avoidNestedTypeNameClashes) { 545 addSuperinterface(TypeName.get(superinterface)); 546 if (avoidNestedTypeNameClashes) { 547 Class<?> clazz = getRawType(superinterface); 548 if (clazz != null) { 549 avoidClashesWithNestedClasses(clazz); 550 } 551 } 552 return this; 553 } 554 getRawType(Type type)555 private Class<?> getRawType(Type type) { 556 if (type instanceof Class<?>) { 557 return (Class<?>) type; 558 } else if (type instanceof ParameterizedType) { 559 return getRawType(((ParameterizedType) type).getRawType()); 560 } else { 561 return null; 562 } 563 } 564 addSuperinterface(TypeMirror superinterface)565 public Builder addSuperinterface(TypeMirror superinterface) { 566 return addSuperinterface(superinterface, true); 567 } 568 addSuperinterface(TypeMirror superinterface, boolean avoidNestedTypeNameClashes)569 public Builder addSuperinterface(TypeMirror superinterface, 570 boolean avoidNestedTypeNameClashes) { 571 addSuperinterface(TypeName.get(superinterface)); 572 if (avoidNestedTypeNameClashes && superinterface instanceof DeclaredType) { 573 TypeElement superInterfaceElement = 574 (TypeElement) ((DeclaredType) superinterface).asElement(); 575 avoidClashesWithNestedClasses(superInterfaceElement); 576 } 577 return this; 578 } 579 addEnumConstant(String name)580 public Builder addEnumConstant(String name) { 581 return addEnumConstant(name, anonymousClassBuilder("").build()); 582 } 583 addEnumConstant(String name, TypeSpec typeSpec)584 public Builder addEnumConstant(String name, TypeSpec typeSpec) { 585 enumConstants.put(name, typeSpec); 586 return this; 587 } 588 addFields(Iterable<FieldSpec> fieldSpecs)589 public Builder addFields(Iterable<FieldSpec> fieldSpecs) { 590 checkArgument(fieldSpecs != null, "fieldSpecs == null"); 591 for (FieldSpec fieldSpec : fieldSpecs) { 592 addField(fieldSpec); 593 } 594 return this; 595 } 596 addField(FieldSpec fieldSpec)597 public Builder addField(FieldSpec fieldSpec) { 598 fieldSpecs.add(fieldSpec); 599 return this; 600 } 601 addField(TypeName type, String name, Modifier... modifiers)602 public Builder addField(TypeName type, String name, Modifier... modifiers) { 603 return addField(FieldSpec.builder(type, name, modifiers).build()); 604 } 605 addField(Type type, String name, Modifier... modifiers)606 public Builder addField(Type type, String name, Modifier... modifiers) { 607 return addField(TypeName.get(type), name, modifiers); 608 } 609 addStaticBlock(CodeBlock block)610 public Builder addStaticBlock(CodeBlock block) { 611 staticBlock.beginControlFlow("static").add(block).endControlFlow(); 612 return this; 613 } 614 addInitializerBlock(CodeBlock block)615 public Builder addInitializerBlock(CodeBlock block) { 616 if ((kind != Kind.CLASS && kind != Kind.ENUM)) { 617 throw new UnsupportedOperationException(kind + " can't have initializer blocks"); 618 } 619 initializerBlock.add("{\n") 620 .indent() 621 .add(block) 622 .unindent() 623 .add("}\n"); 624 return this; 625 } 626 addMethods(Iterable<MethodSpec> methodSpecs)627 public Builder addMethods(Iterable<MethodSpec> methodSpecs) { 628 checkArgument(methodSpecs != null, "methodSpecs == null"); 629 for (MethodSpec methodSpec : methodSpecs) { 630 addMethod(methodSpec); 631 } 632 return this; 633 } 634 addMethod(MethodSpec methodSpec)635 public Builder addMethod(MethodSpec methodSpec) { 636 methodSpecs.add(methodSpec); 637 return this; 638 } 639 addTypes(Iterable<TypeSpec> typeSpecs)640 public Builder addTypes(Iterable<TypeSpec> typeSpecs) { 641 checkArgument(typeSpecs != null, "typeSpecs == null"); 642 for (TypeSpec typeSpec : typeSpecs) { 643 addType(typeSpec); 644 } 645 return this; 646 } 647 addType(TypeSpec typeSpec)648 public Builder addType(TypeSpec typeSpec) { 649 typeSpecs.add(typeSpec); 650 return this; 651 } 652 addOriginatingElement(Element originatingElement)653 public Builder addOriginatingElement(Element originatingElement) { 654 originatingElements.add(originatingElement); 655 return this; 656 } 657 alwaysQualify(String... simpleNames)658 public Builder alwaysQualify(String... simpleNames) { 659 checkArgument(simpleNames != null, "simpleNames == null"); 660 for (String name : simpleNames) { 661 checkArgument( 662 name != null, 663 "null entry in simpleNames array: %s", 664 Arrays.toString(simpleNames) 665 ); 666 alwaysQualifiedNames.add(name); 667 } 668 return this; 669 } 670 671 /** 672 * Call this to always fully qualify any types that would conflict with possibly nested types of 673 * this {@code typeElement}. For example - if the following type was passed in as the 674 * typeElement: 675 * 676 * <pre><code> 677 * class Foo { 678 * class NestedTypeA { 679 * 680 * } 681 * class NestedTypeB { 682 * 683 * } 684 * } 685 * </code></pre> 686 * 687 * <p> 688 * Then this would add {@code "NestedTypeA"} and {@code "NestedTypeB"} as names that should 689 * always be qualified via {@link #alwaysQualify(String...)}. This way they would avoid 690 * possible import conflicts when this JavaFile is written. 691 * 692 * @param typeElement the {@link TypeElement} with nested types to avoid clashes with. 693 * @return this builder instance. 694 */ avoidClashesWithNestedClasses(TypeElement typeElement)695 public Builder avoidClashesWithNestedClasses(TypeElement typeElement) { 696 checkArgument(typeElement != null, "typeElement == null"); 697 for (TypeElement nestedType : ElementFilter.typesIn(typeElement.getEnclosedElements())) { 698 alwaysQualify(nestedType.getSimpleName().toString()); 699 } 700 TypeMirror superclass = typeElement.getSuperclass(); 701 if (!(superclass instanceof NoType) && superclass instanceof DeclaredType) { 702 TypeElement superclassElement = (TypeElement) ((DeclaredType) superclass).asElement(); 703 avoidClashesWithNestedClasses(superclassElement); 704 } 705 for (TypeMirror superinterface : typeElement.getInterfaces()) { 706 if (superinterface instanceof DeclaredType) { 707 TypeElement superinterfaceElement 708 = (TypeElement) ((DeclaredType) superinterface).asElement(); 709 avoidClashesWithNestedClasses(superinterfaceElement); 710 } 711 } 712 return this; 713 } 714 715 /** 716 * Call this to always fully qualify any types that would conflict with possibly nested types of 717 * this {@code typeElement}. For example - if the following type was passed in as the 718 * typeElement: 719 * 720 * <pre><code> 721 * class Foo { 722 * class NestedTypeA { 723 * 724 * } 725 * class NestedTypeB { 726 * 727 * } 728 * } 729 * </code></pre> 730 * 731 * <p> 732 * Then this would add {@code "NestedTypeA"} and {@code "NestedTypeB"} as names that should 733 * always be qualified via {@link #alwaysQualify(String...)}. This way they would avoid 734 * possible import conflicts when this JavaFile is written. 735 * 736 * @param clazz the {@link Class} with nested types to avoid clashes with. 737 * @return this builder instance. 738 */ avoidClashesWithNestedClasses(Class<?> clazz)739 public Builder avoidClashesWithNestedClasses(Class<?> clazz) { 740 checkArgument(clazz != null, "clazz == null"); 741 for (Class<?> nestedType : clazz.getDeclaredClasses()) { 742 alwaysQualify(nestedType.getSimpleName()); 743 } 744 Class<?> superclass = clazz.getSuperclass(); 745 if (superclass != null && !Object.class.equals(superclass)) { 746 avoidClashesWithNestedClasses(superclass); 747 } 748 for (Class<?> superinterface : clazz.getInterfaces()) { 749 avoidClashesWithNestedClasses(superinterface); 750 } 751 return this; 752 } 753 build()754 public TypeSpec build() { 755 for (AnnotationSpec annotationSpec : annotations) { 756 checkNotNull(annotationSpec, "annotationSpec == null"); 757 } 758 759 if (!modifiers.isEmpty()) { 760 checkState(anonymousTypeArguments == null, "forbidden on anonymous types."); 761 for (Modifier modifier : modifiers) { 762 checkArgument(modifier != null, "modifiers contain null"); 763 } 764 } 765 766 checkArgument(kind != Kind.ENUM || !enumConstants.isEmpty(), 767 "at least one enum constant is required for %s", name); 768 769 for (TypeName superinterface : superinterfaces) { 770 checkArgument(superinterface != null, "superinterfaces contains null"); 771 } 772 773 if (!typeVariables.isEmpty()) { 774 checkState(anonymousTypeArguments == null, 775 "typevariables are forbidden on anonymous types."); 776 for (TypeVariableName typeVariableName : typeVariables) { 777 checkArgument(typeVariableName != null, "typeVariables contain null"); 778 } 779 } 780 781 for (Map.Entry<String, TypeSpec> enumConstant : enumConstants.entrySet()) { 782 checkState(kind == Kind.ENUM, "%s is not enum", this.name); 783 checkArgument(enumConstant.getValue().anonymousTypeArguments != null, 784 "enum constants must have anonymous type arguments"); 785 checkArgument(SourceVersion.isName(name), "not a valid enum constant: %s", name); 786 } 787 788 for (FieldSpec fieldSpec : fieldSpecs) { 789 if (kind == Kind.INTERFACE || kind == Kind.ANNOTATION) { 790 requireExactlyOneOf(fieldSpec.modifiers, Modifier.PUBLIC, Modifier.PRIVATE); 791 Set<Modifier> check = EnumSet.of(Modifier.STATIC, Modifier.FINAL); 792 checkState(fieldSpec.modifiers.containsAll(check), "%s %s.%s requires modifiers %s", 793 kind, name, fieldSpec.name, check); 794 } 795 } 796 797 for (MethodSpec methodSpec : methodSpecs) { 798 if (kind == Kind.INTERFACE) { 799 requireExactlyOneOf(methodSpec.modifiers, Modifier.ABSTRACT, Modifier.STATIC, 800 Modifier.DEFAULT); 801 requireExactlyOneOf(methodSpec.modifiers, Modifier.PUBLIC, Modifier.PRIVATE); 802 } else if (kind == Kind.ANNOTATION) { 803 checkState(methodSpec.modifiers.equals(kind.implicitMethodModifiers), 804 "%s %s.%s requires modifiers %s", 805 kind, name, methodSpec.name, kind.implicitMethodModifiers); 806 } 807 if (kind != Kind.ANNOTATION) { 808 checkState(methodSpec.defaultValue == null, "%s %s.%s cannot have a default value", 809 kind, name, methodSpec.name); 810 } 811 if (kind != Kind.INTERFACE) { 812 checkState(!methodSpec.hasModifier(Modifier.DEFAULT), "%s %s.%s cannot be default", 813 kind, name, methodSpec.name); 814 } 815 } 816 817 for (TypeSpec typeSpec : typeSpecs) { 818 checkArgument(typeSpec.modifiers.containsAll(kind.implicitTypeModifiers), 819 "%s %s.%s requires modifiers %s", kind, name, typeSpec.name, 820 kind.implicitTypeModifiers); 821 } 822 823 boolean isAbstract = modifiers.contains(Modifier.ABSTRACT) || kind != Kind.CLASS; 824 for (MethodSpec methodSpec : methodSpecs) { 825 checkArgument(isAbstract || !methodSpec.hasModifier(Modifier.ABSTRACT), 826 "non-abstract type %s cannot declare abstract method %s", name, methodSpec.name); 827 } 828 829 boolean superclassIsObject = superclass.equals(ClassName.OBJECT); 830 int interestingSupertypeCount = (superclassIsObject ? 0 : 1) + superinterfaces.size(); 831 checkArgument(anonymousTypeArguments == null || interestingSupertypeCount <= 1, 832 "anonymous type has too many supertypes"); 833 834 return new TypeSpec(this); 835 } 836 } 837 } 838