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;
17
18/**
19 * An instance of <code>CtMember</code> represents a field, a constructor,
20 * or a method.
21 */
22public abstract class CtMember {
23    CtMember next;          // for internal use
24    protected CtClass declaringClass;
25
26    /* Make a circular link of CtMembers declared in the
27     * same class so that they are garbage-collected together
28     * at the same time.
29     */
30    static class Cache extends CtMember {
31        protected void extendToString(StringBuffer buffer) {}
32        public boolean hasAnnotation(Class clz) { return false; }
33        public Object getAnnotation(Class clz)
34            throws ClassNotFoundException { return null; }
35        public Object[] getAnnotations()
36            throws ClassNotFoundException { return null; }
37        public byte[] getAttribute(String name) { return null; }
38        public Object[] getAvailableAnnotations() { return null; }
39        public int getModifiers() { return 0; }
40        public String getName() { return null; }
41        public String getSignature() { return null; }
42        public void setAttribute(String name, byte[] data) {}
43        public void setModifiers(int mod) {}
44
45        private CtMember methodTail;
46        private CtMember consTail;     // constructor tail
47        private CtMember fieldTail;
48
49        Cache(CtClassType decl) {
50            super(decl);
51            methodTail = this;
52            consTail = this;
53            fieldTail = this;
54            fieldTail.next = this;
55        }
56
57        CtMember methodHead() { return this; }
58        CtMember lastMethod() { return methodTail; }
59        CtMember consHead() { return methodTail; }      // may include a static initializer
60        CtMember lastCons() { return consTail; }
61        CtMember fieldHead() { return consTail; }
62        CtMember lastField() { return fieldTail; }
63
64        void addMethod(CtMember method) {
65            method.next = methodTail.next;
66            methodTail.next = method;
67            if (methodTail == consTail) {
68                consTail = method;
69                if (methodTail == fieldTail)
70                    fieldTail = method;
71            }
72
73            methodTail = method;
74        }
75
76        /* Both constructors and a class initializer.
77         */
78        void addConstructor(CtMember cons) {
79            cons.next = consTail.next;
80            consTail.next = cons;
81            if (consTail == fieldTail)
82                fieldTail = cons;
83
84            consTail = cons;
85        }
86
87        void addField(CtMember field) {
88            field.next = this; // or fieldTail.next
89            fieldTail.next = field;
90            fieldTail = field;
91        }
92
93        static int count(CtMember head, CtMember tail) {
94            int n = 0;
95            while (head != tail) {
96                n++;
97                head = head.next;
98            }
99
100            return n;
101        }
102
103        void remove(CtMember mem) {
104            CtMember m = this;
105            CtMember node;
106            while ((node = m.next) != this) {
107                if (node == mem) {
108                    m.next = node.next;
109                    if (node == methodTail)
110                        methodTail = m;
111
112                    if (node == consTail)
113                        consTail = m;
114
115                    if (node == fieldTail)
116                        fieldTail = m;
117
118                    break;
119                }
120                else
121                    m = m.next;
122            }
123        }
124    }
125
126    protected CtMember(CtClass clazz) {
127        declaringClass = clazz;
128        next = null;
129    }
130
131    final CtMember next() { return next; }
132
133    /**
134     * This method is invoked when setName() or replaceClassName()
135     * in CtClass is called.
136     *
137     * @see CtMethod#nameReplaced()
138     */
139    void nameReplaced() {}
140
141    public String toString() {
142        StringBuffer buffer = new StringBuffer(getClass().getName());
143        buffer.append("@");
144        buffer.append(Integer.toHexString(hashCode()));
145        buffer.append("[");
146        buffer.append(Modifier.toString(getModifiers()));
147        extendToString(buffer);
148        buffer.append("]");
149        return buffer.toString();
150    }
151
152    /**
153     * Invoked by {@link #toString()} to add to the buffer and provide the
154     * complete value.  Subclasses should invoke this method, adding a
155     * space before each token.  The modifiers for the member are
156     * provided first; subclasses should provide additional data such
157     * as return type, field or method name, etc.
158     */
159    protected abstract void extendToString(StringBuffer buffer);
160
161    /**
162     * Returns the class that declares this member.
163     */
164    public CtClass getDeclaringClass() { return declaringClass; }
165
166    /**
167     * Returns true if this member is accessible from the given class.
168     */
169    public boolean visibleFrom(CtClass clazz) {
170        int mod = getModifiers();
171        if (Modifier.isPublic(mod))
172            return true;
173        else if (Modifier.isPrivate(mod))
174            return clazz == declaringClass;
175        else {  // package or protected
176            String declName = declaringClass.getPackageName();
177            String fromName = clazz.getPackageName();
178            boolean visible;
179            if (declName == null)
180                visible = fromName == null;
181            else
182                visible = declName.equals(fromName);
183
184            if (!visible && Modifier.isProtected(mod))
185                return clazz.subclassOf(declaringClass);
186
187            return visible;
188        }
189    }
190
191    /**
192     * Obtains the modifiers of the member.
193     *
194     * @return          modifiers encoded with
195     *                  <code>javassist.Modifier</code>.
196     * @see Modifier
197     */
198    public abstract int getModifiers();
199
200    /**
201     * Sets the encoded modifiers of the member.
202     *
203     * @see Modifier
204     */
205    public abstract void setModifiers(int mod);
206
207    /**
208     * Returns true if the class has the specified annotation class.
209     *
210     * @param clz the annotation class.
211     * @return <code>true</code> if the annotation is found, otherwise <code>false</code>.
212     * @since 3.11
213     */
214    public abstract boolean hasAnnotation(Class clz);
215
216    /**
217     * Returns the annotation if the class has the specified annotation class.
218     * For example, if an annotation <code>@Author</code> is associated
219     * with this member, an <code>Author</code> object is returned.
220     * The member values can be obtained by calling methods on
221     * the <code>Author</code> object.
222     *
223     * @param clz the annotation class.
224     * @return the annotation if found, otherwise <code>null</code>.
225     * @since 3.11
226     */
227    public abstract Object getAnnotation(Class clz) throws ClassNotFoundException;
228
229    /**
230     * Returns the annotations associated with this member.
231     * For example, if an annotation <code>@Author</code> is associated
232     * with this member, the returned array contains an <code>Author</code>
233     * object.  The member values can be obtained by calling methods on
234     * the <code>Author</code> object.
235     *
236     * @return an array of annotation-type objects.
237     * @see CtClass#getAnnotations()
238     */
239    public abstract Object[] getAnnotations() throws ClassNotFoundException;
240
241    /**
242     * Returns the annotations associated with this member.
243     * This method is equivalent to <code>getAnnotations()</code>
244     * except that, if any annotations are not on the classpath,
245     * they are not included in the returned array.
246     *
247     * @return an array of annotation-type objects.
248     * @see #getAnnotations()
249     * @see CtClass#getAvailableAnnotations()
250     * @since 3.3
251     */
252    public abstract Object[] getAvailableAnnotations();
253
254    /**
255     * Obtains the name of the member.
256     *
257     * <p>As for constructor names, see <code>getName()</code>
258     * in <code>CtConstructor</code>.
259     *
260     * @see CtConstructor#getName()
261     */
262    public abstract String getName();
263
264    /**
265     * Returns the character string representing the signature of the member.
266     * If two members have the same signature (parameter types etc.),
267     * <code>getSignature()</code> returns the same string.
268     */
269    public abstract String getSignature();
270
271    /**
272     * Obtains a user-defined attribute with the given name.
273     * If that attribute is not found in the class file, this
274     * method returns null.
275     *
276     * <p>Note that an attribute is a data block specified by
277     * the class file format.
278     * See {@link javassist.bytecode.AttributeInfo}.
279     *
280     * @param name              attribute name
281     */
282    public abstract byte[] getAttribute(String name);
283
284    /**
285     * Adds a user-defined attribute. The attribute is saved in the class file.
286     *
287     * <p>Note that an attribute is a data block specified by
288     * the class file format.
289     * See {@link javassist.bytecode.AttributeInfo}.
290     *
291     * @param name      attribute name
292     * @param data      attribute value
293     */
294    public abstract void setAttribute(String name, byte[] data);
295}
296