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 
16 package javassist;
17 
18 /**
19  * An instance of <code>CtMember</code> represents a field, a constructor,
20  * or a method.
21  */
22 public 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 {
extendToString(StringBuffer buffer)31         protected void extendToString(StringBuffer buffer) {}
hasAnnotation(Class clz)32         public boolean hasAnnotation(Class clz) { return false; }
getAnnotation(Class clz)33         public Object getAnnotation(Class clz)
34             throws ClassNotFoundException { return null; }
getAnnotations()35         public Object[] getAnnotations()
36             throws ClassNotFoundException { return null; }
getAttribute(String name)37         public byte[] getAttribute(String name) { return null; }
getAvailableAnnotations()38         public Object[] getAvailableAnnotations() { return null; }
getModifiers()39         public int getModifiers() { return 0; }
getName()40         public String getName() { return null; }
getSignature()41         public String getSignature() { return null; }
setAttribute(String name, byte[] data)42         public void setAttribute(String name, byte[] data) {}
setModifiers(int mod)43         public void setModifiers(int mod) {}
44 
45         private CtMember methodTail;
46         private CtMember consTail;     // constructor tail
47         private CtMember fieldTail;
48 
Cache(CtClassType decl)49         Cache(CtClassType decl) {
50             super(decl);
51             methodTail = this;
52             consTail = this;
53             fieldTail = this;
54             fieldTail.next = this;
55         }
56 
methodHead()57         CtMember methodHead() { return this; }
lastMethod()58         CtMember lastMethod() { return methodTail; }
consHead()59         CtMember consHead() { return methodTail; }      // may include a static initializer
lastCons()60         CtMember lastCons() { return consTail; }
fieldHead()61         CtMember fieldHead() { return consTail; }
lastField()62         CtMember lastField() { return fieldTail; }
63 
addMethod(CtMember method)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          */
addConstructor(CtMember cons)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 
addField(CtMember field)87         void addField(CtMember field) {
88             field.next = this; // or fieldTail.next
89             fieldTail.next = field;
90             fieldTail = field;
91         }
92 
count(CtMember head, CtMember tail)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 
remove(CtMember mem)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 
CtMember(CtClass clazz)126     protected CtMember(CtClass clazz) {
127         declaringClass = clazz;
128         next = null;
129     }
130 
next()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      */
nameReplaced()139     void nameReplaced() {}
140 
toString()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      */
extendToString(StringBuffer buffer)159     protected abstract void extendToString(StringBuffer buffer);
160 
161     /**
162      * Returns the class that declares this member.
163      */
getDeclaringClass()164     public CtClass getDeclaringClass() { return declaringClass; }
165 
166     /**
167      * Returns true if this member is accessible from the given class.
168      */
visibleFrom(CtClass clazz)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      */
getModifiers()198     public abstract int getModifiers();
199 
200     /**
201      * Sets the encoded modifiers of the member.
202      *
203      * @see Modifier
204      */
setModifiers(int mod)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      */
hasAnnotation(Class clz)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      */
getAnnotation(Class clz)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      */
getAnnotations()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      */
getAvailableAnnotations()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      */
getName()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      */
getSignature()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      */
getAttribute(String name)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      */
setAttribute(String name, byte[] data)294     public abstract void setAttribute(String name, byte[] data);
295 }
296