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