1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.bytecode;
17
18import java.util.HashMap;
19import java.util.Map;
20import java.io.IOException;
21import java.io.DataInputStream;
22import java.io.ByteArrayOutputStream;
23
24import javassist.bytecode.AnnotationsAttribute.Copier;
25import javassist.bytecode.AnnotationsAttribute.Parser;
26import javassist.bytecode.AnnotationsAttribute.Renamer;
27import javassist.bytecode.annotation.*;
28
29/**
30 * A class representing <code>RuntimeVisibleAnnotations_attribute</code> and
31 * <code>RuntimeInvisibleAnnotations_attribute</code>.
32 *
33 * <p>To obtain an ParameterAnnotationAttribute object, invoke
34 * <code>getAttribute(ParameterAnnotationsAttribute.invisibleTag)</code>
35 * in <code>MethodInfo</code>.
36 * The obtained attribute is a
37 * runtime invisible annotations attribute.
38 * If the parameter is
39 * <code>ParameterAnnotationAttribute.visibleTag</code>, then the obtained
40 * attribute is a runtime visible one.
41 */
42public class ParameterAnnotationsAttribute extends AttributeInfo {
43    /**
44     * The name of the <code>RuntimeVisibleParameterAnnotations</code>
45     * attribute.
46     */
47    public static final String visibleTag
48        = "RuntimeVisibleParameterAnnotations";
49
50    /**
51     * The name of the <code>RuntimeInvisibleParameterAnnotations</code>
52     * attribute.
53     */
54    public static final String invisibleTag
55        = "RuntimeInvisibleParameterAnnotations";
56    /**
57     * Constructs
58     * a <code>Runtime(In)VisibleParameterAnnotations_attribute</code>.
59     *
60     * @param cp            constant pool
61     * @param attrname      attribute name (<code>visibleTag</code> or
62     *                      <code>invisibleTag</code>).
63     * @param info          the contents of this attribute.  It does not
64     *                      include <code>attribute_name_index</code> or
65     *                      <code>attribute_length</code>.
66     */
67    public ParameterAnnotationsAttribute(ConstPool cp, String attrname,
68                                         byte[] info) {
69        super(cp, attrname, info);
70    }
71
72    /**
73     * Constructs an empty
74     * <code>Runtime(In)VisibleParameterAnnotations_attribute</code>.
75     * A new annotation can be later added to the created attribute
76     * by <code>setAnnotations()</code>.
77     *
78     * @param cp            constant pool
79     * @param attrname      attribute name (<code>visibleTag</code> or
80     *                      <code>invisibleTag</code>).
81     * @see #setAnnotations(Annotation[][])
82     */
83    public ParameterAnnotationsAttribute(ConstPool cp, String attrname) {
84        this(cp, attrname, new byte[] { 0 });
85    }
86
87    /**
88     * @param n     the attribute name.
89     */
90    ParameterAnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
91        throws IOException
92    {
93        super(cp, n, in);
94    }
95
96    /**
97     * Returns <code>num_parameters</code>.
98     */
99    public int numParameters() {
100        return info[0] & 0xff;
101    }
102
103    /**
104     * Copies this attribute and returns a new copy.
105     */
106    public AttributeInfo copy(ConstPool newCp, Map classnames) {
107        Copier copier = new Copier(info, constPool, newCp, classnames);
108        try {
109            copier.parameters();
110            return new ParameterAnnotationsAttribute(newCp, getName(),
111                                                     copier.close());
112        }
113        catch (Exception e) {
114            throw new RuntimeException(e.toString());
115        }
116    }
117
118    /**
119     * Parses the annotations and returns a data structure representing
120     * that parsed annotations.  Note that changes of the node values of the
121     * returned tree are not reflected on the annotations represented by
122     * this object unless the tree is copied back to this object by
123     * <code>setAnnotations()</code>.
124     *
125     * @return Each element of the returned array represents an array of
126     * annotations that are associated with each method parameter.
127     *
128     * @see #setAnnotations(Annotation[][])
129     */
130    public Annotation[][] getAnnotations() {
131        try {
132            return new Parser(info, constPool).parseParameters();
133        }
134        catch (Exception e) {
135            throw new RuntimeException(e.toString());
136        }
137    }
138
139    /**
140     * Changes the annotations represented by this object according to
141     * the given array of <code>Annotation</code> objects.
142     *
143     * @param params        the data structure representing the
144     *                      new annotations. Every element of this array
145     *                      is an array of <code>Annotation</code> and
146     *                      it represens annotations of each method parameter.
147     */
148    public void setAnnotations(Annotation[][] params) {
149        ByteArrayOutputStream output = new ByteArrayOutputStream();
150        AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
151        try {
152            int n = params.length;
153            writer.numParameters(n);
154            for (int i = 0; i < n; ++i) {
155                Annotation[] anno = params[i];
156                writer.numAnnotations(anno.length);
157                for (int j = 0; j < anno.length; ++j)
158                    anno[j].write(writer);
159            }
160
161            writer.close();
162        }
163        catch (IOException e) {
164            throw new RuntimeException(e);      // should never reach here.
165        }
166
167        set(output.toByteArray());
168    }
169
170    /**
171     * @param oldname       a JVM class name.
172     * @param newname       a JVM class name.
173     */
174    void renameClass(String oldname, String newname) {
175        HashMap map = new HashMap();
176        map.put(oldname, newname);
177        renameClass(map);
178    }
179
180    void renameClass(Map classnames) {
181        Renamer renamer = new Renamer(info, getConstPool(), classnames);
182        try {
183            renamer.parameters();
184        } catch (Exception e) {
185            throw new RuntimeException(e);
186        }
187    }
188
189    void getRefClasses(Map classnames) { renameClass(classnames); }
190
191    /**
192     * Returns a string representation of this object.
193     */
194    public String toString() {
195        Annotation[][] aa = getAnnotations();
196        StringBuilder sbuf = new StringBuilder();
197        int k = 0;
198        while (k < aa.length) {
199            Annotation[] a = aa[k++];
200            int i = 0;
201            while (i < a.length) {
202                sbuf.append(a[i++].toString());
203                if (i != a.length)
204                    sbuf.append(" ");
205            }
206
207            if (k != aa.length)
208                sbuf.append(", ");
209        }
210
211        return sbuf.toString();
212
213    }
214}
215