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 
  29 import java.lang.annotation.Annotation;
  30 import java.util.Collections;
  31 import java.util.LinkedHashMap;
  32 import java.util.Map;
  33 
  34 /**
  35  * Represents an annotation on a program element.
  36  *
  37  * TODO
  38  *    How to add enums to the annotations
  39  * @author
  40  *     Bhakti Mehta (bhakti.mehta@sun.com)
  41  */
  42 public final class JAnnotationUse extends JAnnotationValue {
  43 
  44     /**
  45      * The {@link Annotation} class
  46      */
  47     private final JClass clazz;
  48 
  49     /**
  50      * Map of member values.
  51      */
  52     private Map<String,JAnnotationValue> memberValues;
  53 
  54     JAnnotationUse(JClass clazz){
  55         this.clazz = clazz;
  56     }
  57 
  58     public JClass getAnnotationClass() {
  59         return clazz;
  60     }
  61 
  62     public Map<String, JAnnotationValue> getAnnotationMembers() {
  63         return Collections.unmodifiableMap(memberValues);
  64     }
  65 
  66     private JCodeModel owner() {
  67         return clazz.owner();
  68     }
  69 
  70     private void addValue(String name, JAnnotationValue annotationValue) {
  71         // Use ordered map to keep the code generation the same on any JVM.
  72         // Lazily created.
  73         if(memberValues==null)
  74             memberValues = new LinkedHashMap<String, JAnnotationValue>();
  75         memberValues.put(name,annotationValue);
  76     }
  77 
  78     /**
  79      * Adds a member value pair to this annotation
  80      *
  81      * @param name
  82      *        The simple name for this annotation
  83      *
  84      * @param value
  85      *        The boolean value for this annotation
  86      * @return
  87      *         The JAnnotationUse. More member value pairs can
  88      *         be added to it using the same or the overloaded methods.
  89      *
  90      */
  91     public JAnnotationUse param(String name, boolean value){
  92         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
  93         return this;
  94     }
  95 
  96     /**
  97      * Adds a member value pair to this annotation
  98      * @param name
  99      *        The simple name for this annotation
 100      *
 101      * @param value
 102      *        The byte member value for this annotation
 103      * @return
 104      *         The JAnnotationUse. More member value pairs can
 105      *         be added to it using the same or the overloaded methods.
 106      *
 107      */
 108     public JAnnotationUse param(String name, byte value){
 109         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 110         return this;
 111     }
 112 
 113     /**
 114      * Adds a member value pair to this annotation
 115      * @param name
 116      *        The simple name for this annotation
 117      *
 118      * @param value
 119      *        The char member value for this annotation
 120      * @return
 121      *         The JAnnotationUse. More member value pairs can
 122      *         be added to it using the same or the overloaded methods.
 123      *
 124      */
 125     public JAnnotationUse param(String name, char value){
 126         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 127         return this;
 128     }
 129 
 130     /**
 131      * Adds a member value pair to this annotation
 132      * @param name
 133      *        The simple name for this annotation
 134      *
 135      * @param value
 136      *        The double member value for this annotation
 137      * @return
 138      *         The JAnnotationUse. More member value pairs can
 139      *         be added to it using the same or the overloaded methods.
 140      *
 141      */
 142     public JAnnotationUse param(String name, double value){
 143         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 144         return this;
 145     }
 146 
 147     /**
 148      * Adds a member value pair to this annotation
 149      * @param name
 150      *        The simple name for this annotation
 151      *
 152      * @param value
 153      *        The float member value for this annotation
 154      * @return
 155      *         The JAnnotationUse. More member value pairs can
 156      *         be added to it using the same or the overloaded methods.
 157      *
 158      */
 159     public JAnnotationUse param(String name, float value){
 160         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 161         return this;
 162     }
 163 
 164     /**
 165      * Adds a member value pair to this annotation
 166      * @param name
 167      *        The simple name for this annotation
 168      *
 169      * @param value
 170      *        The long member value for this annotation
 171      * @return
 172      *         The JAnnotationUse. More member value pairs can
 173      *         be added to it using the same or the overloaded methods.
 174      *
 175      */
 176     public JAnnotationUse param(String name, long value){
 177         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 178         return this;
 179     }
 180 
 181     /**
 182      * Adds a member value pair to this annotation
 183      * @param name
 184      *        The simple name for this annotation
 185      *
 186      * @param value
 187      *        The short member value for this annotation
 188      * @return
 189      *         The JAnnotationUse. More member value pairs can
 190      *         be added to it using the same or the overloaded methods.
 191      *
 192      */
 193     public JAnnotationUse param(String name, short value){
 194         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 195         return this;
 196     }
 197 
 198     /**
 199      * Adds a member value pair to this annotation
 200      * @param name
 201      *        The simple name for this annotation
 202      *
 203      * @param value
 204      *        The int member value for this annotation
 205      * @return
 206      *         The JAnnotationUse. More member value pairs can
 207      *         be added to it using the same or the overloaded methods.
 208      *
 209      */
 210     public JAnnotationUse param(String name, int value){
 211         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 212         return this;
 213     }
 214 
 215     /**
 216      * Adds a member value pair to this annotation
 217      * @param name
 218      *        The simple name for this annotation
 219      *
 220      * @param value
 221      *        The String member value for this annotation
 222      * @return
 223      *         The JAnnotationUse. More member value pairs can
 224      *         be added to it using the same or the overloaded methods.
 225      *
 226      */
 227     public JAnnotationUse param(String name, String value){
 228         //Escape string values with quotes so that they can
 229         //be generated accordingly
 230         addValue(name, new JAnnotationStringValue(JExpr.lit(value)));
 231         return this;
 232     }
 233 
 234     /**
 235      * Adds a member value pair to this annotation
 236      * For adding class values as param
 237      * @see #param(String, Class)
 238      * @param name
 239      *        The simple name for this annotation
 240      *
 241      * @param value
 242      *        The annotation class which is member value for this annotation
 243      * @return
 244      *         The JAnnotationUse. More member value pairs can
 245      *         be added to it using the same or the overloaded methods.
 246      *
 247      */
 248     public JAnnotationUse annotationParam(String name, Class<? extends Annotation> value) {
 249         JAnnotationUse annotationUse = new JAnnotationUse(owner().ref(value));
 250         addValue(name, annotationUse);
 251         return annotationUse;
 252     }
 253 
 254     /**
 255      * Adds a member value pair to this annotation
 256      * @param name
 257      *        The simple name for this annotation
 258      *
 259      * @param value
 260      *        The enum class which is member value for this annotation
 261      * @return
 262      *         The JAnnotationUse. More member value pairs can
 263      *         be added to it using the same or the overloaded methods.
 264      *
 265      */
 266     public JAnnotationUse param(String name, final Enum<?> value) {
 267         addValue(name, new JAnnotationValue() {
 268                     public void generate(JFormatter f) {
 269                         f.t(owner().ref(value.getDeclaringClass())).p('.').p(value.name());
 270                     }
 271                 });
 272         return this;
 273     }
 274 
 275     /**
 276      * Adds a member value pair to this annotation
 277      * @param name
 278      *        The simple name for this annotation
 279      *
 280      * @param value
 281      *        The JEnumConstant which is member value for this annotation
 282      * @return
 283      *         The JAnnotationUse. More member value pairs can
 284      *         be added to it using the same or the overloaded methods.
 285      *
 286      */
 287     public JAnnotationUse param(String name, JEnumConstant value){
 288         addValue(name, new JAnnotationStringValue(value));
 289         return this;
 290     }
 291 
 292      /**
 293       * Adds a member value pair to this annotation
 294       *  This can be used for e.g to specify
 295       * <pre>
 296       *        @XmlCollectionItem(type=Integer.class);
 297       * <pre>
 298       * For adding a value of Class<? extends Annotation>
 299       * @link
 300       * #annotationParam(java.lang.String, java.lang.Class<? extends java.lang.annotation.Annotation>)
 301       * @param name
 302       *        The simple name for this annotation param
 303       *
 304       * @param value
 305       *        The class type of the param
 306       * @return
 307       *         The JAnnotationUse. More member value pairs can
 308       *         be added to it using the same or the overloaded methods.
 309       *
 310       *
 311       *
 312       */
 313      public JAnnotationUse param(String name, final Class<?> value){
 314          addValue(name, new JAnnotationStringValue(
 315                          new JExpressionImpl() {
 316                                  public void generate(JFormatter f) {
 317                                          f.p(value.getName().replace('$', '.'));
 318                                          f.p(".class");
 319                                 }
 320                          }));
 321          return this;
 322     }
 323 
 324     /**
 325      * Adds a member value pair to this annotation based on the
 326      * type represented by the given JType
 327      *
 328      * @param name The simple name for this annotation param
 329      * @param type the JType representing the actual type
 330      * @return The JAnnotationUse. More member value pairs can
 331      *         be added to it using the same or the overloaded methods.
 332      */
 333     public JAnnotationUse param(String name, JType type){
 334         JClass c = type.boxify();
 335         addValue(name, new JAnnotationStringValue ( c.dotclass() ));
 336         return this;
 337     }
 338 
 339     /**
 340      * Adds a member value pair to this annotation.
 341      * @param name
 342      *        The simple name for this annotation
 343      *
 344      * @param value
 345      *        The JExpression which provides the contant value for this annotation
 346      * @return
 347      *         The JAnnotationUse. More member value pairs can
 348      *         be added to it using the same or the overloaded methods.
 349      *
 350      */
 351     public JAnnotationUse param(String name, JExpression value){
 352         addValue(name, new JAnnotationStringValue(value));
 353         return this;
 354     }
 355 
 356     /**
 357      * Adds a member value pair which is of type array to this annotation
 358      * @param name
 359      *        The simple name for this annotation
 360      *
 361      * @return
 362      *         The JAnnotationArrayMember. For adding array values
 363      *         @see JAnnotationArrayMember
 364      *
 365      */
 366     public JAnnotationArrayMember paramArray(String name){
 367         JAnnotationArrayMember arrayMember = new JAnnotationArrayMember(owner());
 368         addValue(name, arrayMember);
 369         return arrayMember;
 370     }
 371 
 372 
 373 //    /**
 374 //     * This can be used to add annotations inside annotations
 375 //     * for e.g  @XmlCollection(values= @XmlCollectionItem(type=Foo.class))
 376 //     * @param className
 377 //     *         The classname of the annotation to be included
 378 //     * @return
 379 //     *         The JAnnotationUse that can be used as a member within this JAnnotationUse
 380 //     * @deprecated
 381 //     *      use {@link JAnnotationArrayMember#annotate}
 382 //     */
 383 //    public JAnnotationUse annotate(String className) {
 384 //        JAnnotationUse annotationUse = new JAnnotationUse(owner().ref(className));
 385 //        return annotationUse;
 386 //    }
 387 
 388     /**
 389      * This can be used to add annotations inside annotations
 390      * for e.g  @XmlCollection(values= @XmlCollectionItem(type=Foo.class))
 391      * @param clazz
 392      *         The annotation class to be included
 393      * @return
 394      *     The JAnnotationUse that can be used as a member within this JAnnotationUse
 395      * @deprecated
 396      *      use {@link JAnnotationArrayMember#annotate}
 397      */
 398     public JAnnotationUse annotate(Class <? extends Annotation> clazz) {
 399          JAnnotationUse annotationUse = new JAnnotationUse(owner().ref(clazz));
 400          return annotationUse;
 401     }
 402 
 403     public void generate(JFormatter f) {
 404         f.p('@').g(clazz);
 405         if(memberValues!=null) {
 406             f.p('(');
 407             boolean first = true;
 408 
 409             if(isOptimizable()) {
 410                 // short form
 411                 f.g(memberValues.get("value"));
 412             } else {
 413                 for (Map.Entry<String, JAnnotationValue> mapEntry : memberValues.entrySet()) {
 414                     if (!first) f.p(',');
 415                     f.p(mapEntry.getKey()).p('=').g(mapEntry.getValue());
 416                     first = false;
 417                 }
 418             }
 419             f.p(')');
 420         }
 421     }
 422 
 423     private boolean isOptimizable() {
 424         return memberValues.size()==1 && memberValues.containsKey("value");
 425     }
 426 }