1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.codemodel.internal;
  27 
  28 import java.lang.annotation.Annotation;
  29 import java.util.ArrayList;
  30 import java.util.Collection;
  31 import java.util.Collections;
  32 import java.util.Iterator;
  33 import java.util.LinkedHashMap;
  34 import java.util.List;
  35 import java.util.Map;
  36 import java.util.Set;
  37 import java.util.TreeMap;
  38 import java.util.TreeSet;
  39 
  40 /**
  41  * A generated Java class/interface/enum/....
  42  *
  43  * <p>
  44  * This class models a declaration, and since a declaration can be always
  45  * used as a reference, it inherits {@link JClass}.
  46  *
  47  * <h2>Where to go from here?</h2>
  48  * <p>
  49  * You'd want to generate fields and methods on a class.
  50  * See {@link #method(int, JType, String)} and {@link #field(int, JType, String)}.
  51  */
  52 public class JDefinedClass
  53     extends JClass
  54     implements JDeclaration, JClassContainer, JGenerifiable, JAnnotatable, JDocCommentable {
  55 
  56     /** Name of this class. Null if anonymous. */
  57     private String name = null;
  58 
  59     /** Modifiers for the class declaration */
  60     private JMods mods;
  61 
  62     /** Name of the super class of this class. */
  63     private JClass superClass;
  64 
  65     /** List of interfaces that this class implements */
  66     private final Set<JClass> interfaces = new TreeSet<JClass>();
  67 
  68     /** Fields keyed by their names. */
  69     /*package*/ final Map<String,JFieldVar> fields = new LinkedHashMap<String,JFieldVar>();
  70 
  71     /** Static initializer, if this class has one */
  72     private JBlock init = null;
  73 
  74     /** class javadoc */
  75     private JDocComment jdoc = null;
  76 
  77     /** Set of constructors for this class, if any */
  78     private final List<JMethod> constructors = new ArrayList<JMethod>();
  79 
  80     /** Set of methods that are members of this class */
  81     private final List<JMethod> methods = new ArrayList<JMethod>();
  82 
  83     /**
  84      * Nested classes as a map from name to JDefinedClass.
  85      * The name is all capitalized in a case sensitive file system
  86      * ({@link JCodeModel#isCaseSensitiveFileSystem}) to avoid conflicts.
  87      *
  88      * Lazily created to save footprint.
  89      *
  90      * @see #getClasses()
  91      */
  92     private Map<String,JDefinedClass> classes;
  93 
  94 
  95     /**
  96      * Flag that controls whether this class should be really generated or not.
  97      *
  98      * Sometimes it is useful to generate code that refers to class X,
  99      * without actually generating the code of X.
 100      * This flag is used to surpress X.java file in the output.
 101      */
 102     private boolean hideFile = false;
 103 
 104     /**
 105      * Client-app spcific metadata associated with this user-created class.
 106      */
 107     public Object metadata;
 108 
 109     /**
 110      * String that will be put directly inside the generated code.
 111      * Can be null.
 112      */
 113     private String directBlock;
 114 
 115     /**
 116      * If this is a package-member class, this is {@link JPackage}.
 117      * If this is a nested class, this is {@link JDefinedClass}.
 118      * If this is an anonymous class, this constructor shouldn't be used.
 119      */
 120     private JClassContainer outer = null;
 121 
 122 
 123     /** Default value is class or interface
 124      *  or annotationTypeDeclaration
 125      *  or enum
 126      *
 127      */
 128     private final ClassType classType;
 129 
 130     /** List containing the enum value declarations
 131      *
 132      */
 133 //    private List enumValues = new ArrayList();
 134 
 135     /**
 136      * Set of enum constants that are keyed by names.
 137      * In Java, enum constant order is actually significant,
 138      * because of order ID they get. So let's preserve the order.
 139      */
 140     private final Map<String,JEnumConstant> enumConstantsByName = new LinkedHashMap<String,JEnumConstant>();
 141 
 142     /**
 143      * Annotations on this variable. Lazily created.
 144      */
 145     private List<JAnnotationUse> annotations = null;
 146 
 147 
 148     /**
 149      * Helper class to implement {@link JGenerifiable}.
 150      */
 151     private final JGenerifiableImpl generifiable = new JGenerifiableImpl() {
 152         protected JCodeModel owner() {
 153             return JDefinedClass.this.owner();
 154         }
 155     };
 156 
 157     JDefinedClass(JClassContainer parent, int mods, String name, ClassType classTypeval) {
 158         this(mods, name, parent, parent.owner(), classTypeval);
 159     }
 160 
 161     /**
 162      * Constructor for creating anonymous inner class.
 163      */
 164     JDefinedClass(
 165         JCodeModel owner,
 166         int mods,
 167         String name) {
 168         this(mods, name, null, owner);
 169     }
 170 
 171     private JDefinedClass(
 172             int mods,
 173             String name,
 174             JClassContainer parent,
 175             JCodeModel owner) {
 176         this (mods,name,parent,owner,ClassType.CLASS);
 177     }
 178 
 179     /**
 180      * JClass constructor
 181      *
 182      * @param mods
 183      *        Modifiers for this class declaration
 184      *
 185      * @param name
 186      *        Name of this class
 187      */
 188     private JDefinedClass(
 189         int mods,
 190         String name,
 191         JClassContainer parent,
 192         JCodeModel owner,
 193                 ClassType classTypeVal) {
 194         super(owner);
 195 
 196         if(name!=null) {
 197             if (name.trim().length() == 0)
 198                 throw new IllegalArgumentException("JClass name empty");
 199 
 200             if (!Character.isJavaIdentifierStart(name.charAt(0))) {
 201                 String msg =
 202                     "JClass name "
 203                         + name
 204                         + " contains illegal character"
 205                         + " for beginning of identifier: "
 206                         + name.charAt(0);
 207                 throw new IllegalArgumentException(msg);
 208             }
 209             for (int i = 1; i < name.length(); i++) {
 210                 if (!Character.isJavaIdentifierPart(name.charAt(i))) {
 211                     String msg =
 212                         "JClass name "
 213                             + name
 214                             + " contains illegal character "
 215                             + name.charAt(i);
 216                     throw new IllegalArgumentException(msg);
 217                 }
 218             }
 219         }
 220 
 221         this.classType = classTypeVal;
 222         if (isInterface())
 223             this.mods = JMods.forInterface(mods);
 224         else
 225             this.mods = JMods.forClass(mods);
 226 
 227         this.name = name;
 228 
 229         this.outer = parent;
 230     }
 231 
 232     /**
 233      * Returns true if this is an anonymous class.
 234      */
 235     public final boolean isAnonymous() {
 236         return name == null;
 237     }
 238 
 239     /**
 240      * This class extends the specifed class.
 241      *
 242      * @param superClass
 243      *        Superclass for this class
 244      *
 245      * @return This class
 246      */
 247     public JDefinedClass _extends(JClass superClass) {
 248         if (this.classType==ClassType.INTERFACE)
 249                 if(superClass.isInterface()){
 250                         return this._implements(superClass);
 251                 } else throw new IllegalArgumentException("unable to set the super class for an interface");
 252         if (superClass == null)
 253             throw new NullPointerException();
 254 
 255         for( JClass o=superClass.outer(); o!=null; o=o.outer() ){
 256             if(this==o){
 257                 throw new IllegalArgumentException("Illegal class inheritance loop." +
 258                 "  Outer class " + this.name + " may not subclass from inner class: " + o.name());
 259             }
 260         }
 261 
 262         this.superClass = superClass;
 263         return this;
 264     }
 265 
 266     public JDefinedClass _extends(Class<?> superClass) {
 267         return _extends(owner().ref(superClass));
 268     }
 269 
 270     /**
 271      * Returns the class extended by this class.
 272      */
 273     public JClass _extends() {
 274         if(superClass==null)
 275             superClass = owner().ref(Object.class);
 276         return superClass;
 277     }
 278 
 279     /**
 280      * This class implements the specifed interface.
 281      *
 282      * @param iface
 283      *        Interface that this class implements
 284      *
 285      * @return This class
 286      */
 287     public JDefinedClass _implements(JClass iface) {
 288         interfaces.add(iface);
 289         return this;
 290     }
 291 
 292     public JDefinedClass _implements(Class<?> iface) {
 293         return _implements(owner().ref(iface));
 294     }
 295 
 296     /**
 297      * Returns an iterator that walks the nested classes defined in this
 298      * class.
 299      */
 300     public Iterator<JClass> _implements() {
 301         return interfaces.iterator();
 302     }
 303 
 304     /**
 305      * JClass name accessor.
 306      *
 307      * <p>
 308      * For example, for <code>java.util.List</code>, this method
 309      * returns <code>"List"</code>"
 310      *
 311      * @return Name of this class
 312      */
 313     public String name() {
 314         return name;
 315     }
 316 
 317     /**
 318      * If the named enum already exists, the reference to it is returned.
 319      * Otherwise this method generates a new enum reference with the given
 320      * name and returns it.
 321      *
 322      * @param name
 323      *          The name of the constant.
 324      * @return
 325      *      The generated type-safe enum constant.
 326      */
 327     public JEnumConstant enumConstant(String name){
 328         JEnumConstant ec = enumConstantsByName.get(name);
 329         if (null == ec) {
 330             ec = new JEnumConstant(this, name);
 331             enumConstantsByName.put(name, ec);
 332         }
 333         return ec;
 334     }
 335 
 336     /**
 337      * Gets the fully qualified name of this class.
 338      */
 339     public String fullName() {
 340         if (outer instanceof JDefinedClass)
 341             return ((JDefinedClass) outer).fullName() + '.' + name();
 342 
 343         JPackage p = _package();
 344         if (p.isUnnamed())
 345             return name();
 346         else
 347             return p.name() + '.' + name();
 348     }
 349 
 350     @Override
 351     public String binaryName() {
 352         if (outer instanceof JDefinedClass)
 353             return ((JDefinedClass) outer).binaryName() + '$' + name();
 354         else
 355             return fullName();
 356     }
 357 
 358     public boolean isInterface() {
 359         return this.classType==ClassType.INTERFACE;
 360     }
 361 
 362     public boolean isAbstract() {
 363         return mods.isAbstract();
 364     }
 365 
 366     /**
 367      * Adds a field to the list of field members of this JDefinedClass.
 368      *
 369      * @param mods
 370      *        Modifiers for this field
 371      *
 372      * @param type
 373      *        JType of this field
 374      *
 375      * @param name
 376      *        Name of this field
 377      *
 378      * @return Newly generated field
 379      */
 380     public JFieldVar field(int mods, JType type, String name) {
 381         return field(mods, type, name, null);
 382     }
 383 
 384     public JFieldVar field(int mods, Class<?> type, String name) {
 385         return field(mods, owner()._ref(type), name);
 386     }
 387 
 388     /**
 389      * Adds a field to the list of field members of this JDefinedClass.
 390      *
 391      * @param mods
 392      *        Modifiers for this field.
 393      * @param type
 394      *        JType of this field.
 395      * @param name
 396      *        Name of this field.
 397      * @param init
 398      *        Initial value of this field.
 399      *
 400      * @return Newly generated field
 401      */
 402     public JFieldVar field(
 403         int mods,
 404         JType type,
 405         String name,
 406         JExpression init) {
 407         JFieldVar f = new JFieldVar(this,JMods.forField(mods), type, name, init);
 408 
 409         if (fields.containsKey(name)) {
 410             throw new IllegalArgumentException("trying to create the same field twice: "+name);
 411         }
 412 
 413         fields.put(name, f);
 414         return f;
 415     }
 416 
 417     /**  This method indicates if the interface
 418      *   is an annotationTypeDeclaration
 419      *
 420      */
 421     public boolean isAnnotationTypeDeclaration() {
 422         return this.classType==ClassType.ANNOTATION_TYPE_DECL;
 423 
 424 
 425     }
 426 
 427     /**
 428      * Add an annotationType Declaration to this package
 429      * @param name
 430      *      Name of the annotation Type declaration to be added to this package
 431      * @return
 432      *      newly created Annotation Type Declaration
 433      * @exception JClassAlreadyExistsException
 434      *      When the specified class/interface was already created.
 435 
 436      */
 437     public JDefinedClass _annotationTypeDeclaration(String name) throws JClassAlreadyExistsException {
 438         return _class (JMod.PUBLIC,name,ClassType.ANNOTATION_TYPE_DECL);
 439     }
 440 
 441     /**
 442      * Add a public enum to this package
 443      * @param name
 444      *      Name of the enum to be added to this package
 445      * @return
 446      *      newly created Enum
 447      * @exception JClassAlreadyExistsException
 448      *      When the specified class/interface was already created.
 449 
 450      */
 451     public JDefinedClass _enum (String name) throws JClassAlreadyExistsException {
 452         return _class (JMod.PUBLIC,name,ClassType.ENUM);
 453     }
 454 
 455     /**
 456      * Add a public enum to this package
 457      * @param name
 458      *      Name of the enum to be added to this package
 459      * @param mods
 460      *          Modifiers for this enum declaration
 461      * @return
 462      *      newly created Enum
 463      * @exception JClassAlreadyExistsException
 464      *      When the specified class/interface was already created.
 465 
 466      */
 467     public JDefinedClass _enum (int mods,String name) throws JClassAlreadyExistsException {
 468         return _class (mods,name,ClassType.ENUM);
 469     }
 470 
 471 
 472 
 473 
 474 
 475     public ClassType getClassType(){
 476         return this.classType;
 477     }
 478 
 479     public JFieldVar field(
 480         int mods,
 481         Class<?> type,
 482         String name,
 483         JExpression init) {
 484         return field(mods, owner()._ref(type), name, init);
 485     }
 486 
 487     /**
 488      * Returns all the fields declred in this class.
 489      * The returned {@link Map} is a read-only live view.
 490      *
 491      * @return always non-null.
 492      */
 493     public Map<String,JFieldVar> fields() {
 494         return Collections.unmodifiableMap(fields);
 495     }
 496 
 497     /**
 498      * Removes a {@link JFieldVar} from this class.
 499      *
 500      * @throws IllegalArgumentException
 501      *      if the given field is not a field on this class.
 502      */
 503     public void removeField(JFieldVar field) {
 504         if(fields.remove(field.name())!=field)
 505             throw new IllegalArgumentException();
 506     }
 507 
 508     /**
 509      * Creates, if necessary, and returns the static initializer
 510      * for this class.
 511      *
 512      * @return JBlock containing initialization statements for this class
 513      */
 514     public JBlock init() {
 515         if (init == null)
 516             init = new JBlock();
 517         return init;
 518     }
 519 
 520     /**
 521      * Adds a constructor to this class.
 522      *
 523      * @param mods
 524      *        Modifiers for this constructor
 525      */
 526     public JMethod constructor(int mods) {
 527         JMethod c = new JMethod(mods, this);
 528         constructors.add(c);
 529         return c;
 530     }
 531 
 532     /**
 533      * Returns an iterator that walks the constructors defined in this class.
 534      */
 535     public Iterator<JMethod> constructors() {
 536         return constructors.iterator();
 537     }
 538 
 539     /**
 540      * Looks for a method that has the specified method signature
 541      * and return it.
 542      *
 543      * @return
 544      *      null if not found.
 545      */
 546     public JMethod getConstructor(JType[] argTypes) {
 547         for (JMethod m : constructors) {
 548             if (m.hasSignature(argTypes))
 549                 return m;
 550         }
 551         return null;
 552     }
 553 
 554     /**
 555      * Add a method to the list of method members of this JDefinedClass instance.
 556      *
 557      * @param mods
 558      *        Modifiers for this method
 559      *
 560      * @param type
 561      *        Return type for this method
 562      *
 563      * @param name
 564      *        Name of the method
 565      *
 566      * @return Newly generated JMethod
 567      */
 568     public JMethod method(int mods, JType type, String name) {
 569         // XXX problems caught in M constructor
 570         JMethod m = new JMethod(this, mods, type, name);
 571         methods.add(m);
 572         return m;
 573     }
 574 
 575     public JMethod method(int mods, Class<?> type, String name) {
 576         return method(mods, owner()._ref(type), name);
 577     }
 578 
 579     /**
 580      * Returns the set of methods defined in this class.
 581      */
 582     public Collection<JMethod> methods() {
 583         return methods;
 584     }
 585 
 586     /**
 587      * Looks for a method that has the specified method signature
 588      * and return it.
 589      *
 590      * @return
 591      *      null if not found.
 592      */
 593     public JMethod getMethod(String name, JType[] argTypes) {
 594         for (JMethod m : methods) {
 595             if (!m.name().equals(name))
 596                 continue;
 597 
 598             if (m.hasSignature(argTypes))
 599                 return m;
 600         }
 601         return null;
 602     }
 603 
 604     public boolean isClass() {
 605         return true;
 606     }
 607     public boolean isPackage() {
 608         return false;
 609     }
 610     public JPackage getPackage() { return parentContainer().getPackage(); }
 611 
 612     /**
 613      * Add a new nested class to this class.
 614      *
 615      * @param mods
 616      *        Modifiers for this class declaration
 617      *
 618      * @param name
 619      *        Name of class to be added to this package
 620      *
 621      * @return Newly generated class
 622      */
 623     public JDefinedClass _class(int mods, String name)
 624         throws JClassAlreadyExistsException {
 625         return _class(mods, name, ClassType.CLASS);
 626     }
 627 
 628     /**
 629      * {@inheritDoc}
 630      *
 631      * @deprecated
 632      */
 633     public JDefinedClass _class(int mods, String name, boolean isInterface) throws JClassAlreadyExistsException {
 634         return _class(mods,name,isInterface?ClassType.INTERFACE:ClassType.CLASS);
 635     }
 636 
 637     public JDefinedClass _class(int mods, String name, ClassType classTypeVal)
 638         throws JClassAlreadyExistsException {
 639 
 640         String NAME;
 641         if (JCodeModel.isCaseSensitiveFileSystem)
 642             NAME = name.toUpperCase();
 643         else
 644             NAME = name;
 645 
 646         if (getClasses().containsKey(NAME))
 647             throw new JClassAlreadyExistsException(getClasses().get(NAME));
 648         else {
 649             // XXX problems caught in the NC constructor
 650             JDefinedClass c = new JDefinedClass(this, mods, name, classTypeVal);
 651             getClasses().put(NAME,c);
 652             return c;
 653         }
 654     }
 655 
 656     /**
 657      * Add a new public nested class to this class.
 658      */
 659     public JDefinedClass _class(String name)
 660         throws JClassAlreadyExistsException {
 661         return _class(JMod.PUBLIC, name);
 662     }
 663 
 664     /**
 665      * Add an interface to this package.
 666      *
 667      * @param mods
 668      *        Modifiers for this interface declaration
 669      *
 670      * @param name
 671      *        Name of interface to be added to this package
 672      *
 673      * @return Newly generated interface
 674      */
 675     public JDefinedClass _interface(int mods, String name)
 676         throws JClassAlreadyExistsException {
 677         return _class(mods, name, ClassType.INTERFACE);
 678     }
 679 
 680     /**
 681      * Adds a public interface to this package.
 682      */
 683     public JDefinedClass _interface(String name)
 684         throws JClassAlreadyExistsException {
 685         return _interface(JMod.PUBLIC, name);
 686     }
 687 
 688     /**
 689      * Creates, if necessary, and returns the class javadoc for this
 690      * JDefinedClass
 691      *
 692      * @return JDocComment containing javadocs for this class
 693      */
 694     public JDocComment javadoc() {
 695         if (jdoc == null)
 696             jdoc = new JDocComment(owner());
 697         return jdoc;
 698     }
 699 
 700     /**
 701      * Mark this file as hidden, so that this file won't be
 702      * generated.
 703      *
 704      * <p>
 705      * This feature could be used to generate code that refers
 706      * to class X, without actually generating X.java.
 707      */
 708     public void hide() {
 709         hideFile = true;
 710     }
 711 
 712     public boolean isHidden() {
 713         return hideFile;
 714     }
 715 
 716     /**
 717      * Returns an iterator that walks the nested classes defined in this
 718      * class.
 719      */
 720     public final Iterator<JDefinedClass> classes() {
 721         if(classes==null)
 722             return Collections.<JDefinedClass>emptyList().iterator();
 723         else
 724             return classes.values().iterator();
 725     }
 726 
 727     private Map<String,JDefinedClass> getClasses() {
 728         if(classes==null)
 729             classes = new TreeMap<String,JDefinedClass>();
 730         return classes;
 731     }
 732 
 733 
 734     /**
 735      * Returns all the nested classes defined in this class.
 736      */
 737     public final JClass[] listClasses() {
 738         if(classes==null)
 739             return new JClass[0];
 740         else
 741             return classes.values().toArray(new JClass[classes.values().size()]);
 742     }
 743 
 744     @Override
 745     public JClass outer() {
 746         if (outer.isClass())
 747             return (JClass) outer;
 748         else
 749             return null;
 750     }
 751 
 752     public void declare(JFormatter f) {
 753         if (jdoc != null)
 754             f.nl().g(jdoc);
 755 
 756         if (annotations != null){
 757             for (JAnnotationUse annotation : annotations)
 758                 f.g(annotation).nl();
 759         }
 760 
 761         f.g(mods).p(classType.declarationToken).id(name).d(generifiable);
 762 
 763         if (superClass != null && superClass != owner().ref(Object.class))
 764             f.nl().i().p("extends").g(superClass).nl().o();
 765 
 766         if (!interfaces.isEmpty()) {
 767             if (superClass == null)
 768                 f.nl();
 769             f.i().p(classType==ClassType.INTERFACE ? "extends" : "implements");
 770             f.g(interfaces);
 771             f.nl().o();
 772         }
 773         declareBody(f);
 774     }
 775 
 776     /**
 777      * prints the body of a class.
 778      */
 779     protected void declareBody(JFormatter f) {
 780         f.p('{').nl().nl().i();
 781         boolean first = true;
 782 
 783         if (!enumConstantsByName.isEmpty()) {
 784             for (JEnumConstant c : enumConstantsByName.values()) {
 785                 if (!first) f.p(',').nl();
 786                 f.d(c);
 787                 first = false;
 788             }
 789                 f.p(';').nl();
 790         }
 791 
 792         for( JFieldVar field : fields.values() )
 793             f.d(field);
 794         if (init != null)
 795             f.nl().p("static").s(init);
 796         for (JMethod m : constructors) {
 797             f.nl().d(m);
 798         }
 799         for (JMethod m : methods) {
 800             f.nl().d(m);
 801         }
 802         if(classes!=null)
 803             for (JDefinedClass dc : classes.values())
 804                 f.nl().d(dc);
 805 
 806 
 807         if (directBlock != null)
 808             f.p(directBlock);
 809         f.nl().o().p('}').nl();
 810     }
 811 
 812     /**
 813      * Places the given string directly inside the generated class.
 814      *
 815      * This method can be used to add methods/fields that are not
 816      * generated by CodeModel.
 817      * This method should be used only as the last resort.
 818      */
 819     public void direct(String string) {
 820         if (directBlock == null)
 821             directBlock = string;
 822         else
 823             directBlock += string;
 824     }
 825 
 826     public final JPackage _package() {
 827         JClassContainer p = outer;
 828         while (!(p instanceof JPackage))
 829             p = p.parentContainer();
 830         return (JPackage) p;
 831     }
 832 
 833     public final JClassContainer parentContainer() {
 834         return outer;
 835     }
 836 
 837     public JTypeVar generify(String name) {
 838         return generifiable.generify(name);
 839     }
 840     public JTypeVar generify(String name, Class<?> bound) {
 841         return generifiable.generify(name, bound);
 842     }
 843     public JTypeVar generify(String name, JClass bound) {
 844         return generifiable.generify(name, bound);
 845     }
 846     @Override
 847     public JTypeVar[] typeParams() {
 848         return generifiable.typeParams();
 849     }
 850 
 851     protected JClass substituteParams(
 852         JTypeVar[] variables,
 853         List<JClass> bindings) {
 854         return this;
 855     }
 856 
 857     /** Adding ability to annotate a class
 858      * @param clazz
 859      *          The annotation class to annotate the class with
 860      */
 861     public JAnnotationUse annotate(Class <? extends Annotation> clazz){
 862         return annotate(owner().ref(clazz));
 863     }
 864 
 865     /** Adding ability to annotate a class
 866       * @param clazz
 867       *          The annotation class to annotate the class with
 868       */
 869      public JAnnotationUse annotate(JClass clazz){
 870         if(annotations==null)
 871            annotations = new ArrayList<JAnnotationUse>();
 872         JAnnotationUse a = new JAnnotationUse(clazz);
 873         annotations.add(a);
 874         return a;
 875     }
 876 
 877     public <W extends JAnnotationWriter> W annotate2(Class<W> clazz) {
 878         return TypedAnnotationWriter.create(clazz,this);
 879     }
 880 
 881     /**
 882      * {@link JAnnotatable#annotations()}
 883      */
 884     public Collection<JAnnotationUse> annotations() {
 885         if (annotations == null)
 886             annotations = new ArrayList<JAnnotationUse>();
 887         return Collections.unmodifiableCollection(annotations);
 888     }
 889 
 890     /**
 891      * @return
 892      *      the current modifiers of this class.
 893      *      Always return non-null valid object.
 894      */
 895     public JMods mods() {
 896         return mods;
 897     }
 898 }