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