001 // Copyright 2011 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.plastic;
016
017 import java.lang.annotation.Annotation;
018 import java.lang.reflect.Method;
019 import java.util.List;
020 import java.util.Set;
021
022 /**
023 * The representation of a class while it is being instrumented and transformed. PlasticClass allows
024 * for an imperative style of development: the PlasticClass is provided to other objects; they can query it
025 * for relevant fields or methods, and invoke methods that modify the class in various ways. Ultimately, the
026 * end result is a {@link ClassInstantiator} used to create instances of the fully instrumented and transformed class.
027 * <p/>
028 * The terminology is that a class that is being transformed is "plastic", but the end result is a normal concrete class
029 * (albeit in a different class loader).
030 * <p/>
031 * Implements {@link AnnotationAccess} to provide access to annotations on the type itself.
032 * <p/>
033 * This class is expressly <em>not thread safe</em>; only a single thread should be responsible for operating on a
034 * PlasticClass.
035 * <p/>
036 * TODO: what about annotation inheritance?
037 */
038 @SuppressWarnings("rawtypes")
039 public interface PlasticClass extends AnnotationAccess
040 {
041 /**
042 * Returns the fully qualified class name of the class being transformed.
043 */
044 String getClassName();
045
046 /**
047 * Matches all fields (claimed or not) that have the given annotation. Returns the fields in sorted order.
048 *
049 * @return Unmodifiable List of fields.
050 */
051 <T extends Annotation> List<PlasticField> getFieldsWithAnnotation(Class<T> annotationType);
052
053 /**
054 * Returns all non-introduced fields, in sorted order by name.
055 *
056 * @return Unmodifiable list of fields.
057 */
058 List<PlasticField> getAllFields();
059
060 /**
061 * Returns all unclaimed fields, in sorted order by name. This does not include introduced fields.
062 *
063 * @return Unmodifiable list of fields.
064 * @see PlasticField#claim(Object)
065 */
066 List<PlasticField> getUnclaimedFields();
067
068 /**
069 * Introduces a new private field into the class.
070 *
071 * @param typeName the Java class name for the field, or (possibly) a primitive type name or an array
072 * @param suggestedName the suggested name for the field, which may be modified to ensure that the field name
073 * is unique
074 * @return PlasticField for the introduced field
075 */
076 PlasticField introduceField(String typeName, String suggestedName);
077
078 /**
079 * Convenience method that uses a Java class rather than a type name.
080 */
081 PlasticField introduceField(Class fieldType, String suggestedName);
082
083 /**
084 * Introduces a new private method into the class, ensuring that the method name is unique.
085 *
086 * @param typeName return type of method
087 * @param suggestedName suggested name for the method; the actual method name may be modified to ensure uniqueness
088 * @param argumentTypes types of any arguments (may be null)
089 * @param exceptionTypes type of any checked exceptions (may be null)
090 * @return new method, with default implementation
091 */
092 PlasticMethod introducePrivateMethod(String typeName, String suggestedName, String[] argumentTypes,
093 String[] exceptionTypes);
094
095 /**
096 * Matches methods with the given annotation.
097 *
098 * @return Unmodifiable list of methods, in sorted order.
099 */
100 <T extends Annotation> List<PlasticMethod> getMethodsWithAnnotation(Class<T> annotationType);
101
102 /**
103 * Returns all methods of the class, in sorted order. This does not include static methods,
104 * or any {@linkplain #introduceMethod(MethodDescription) introduced methods}.
105 *
106 * @return Unmodifiable list of methods.
107 */
108 List<PlasticMethod> getMethods();
109
110 /**
111 * Returns an existing method declared in this class, or introduces a new method into this class.
112 * The method is created with default behavior. If the method overrides a non-private, non-abstract method
113 * implemented in a <em>transformed</em> super class, the the default behavior is to invoke that method and return
114 * its value. Otherwise, the default behavior is to ignore parameters and return 0, false, or null. Void methods
115 * will invoke the super-class implementation (if it exists) and return no value.
116 * <p/>
117 * It is allowed for the method description to indicate an abstract method; however the abstract flag will be
118 * removed, and a non-abstract method will be created.
119 *
120 * @param description describes the method name, visibility, return value, etc.
121 * @return a new (or previously created) PlasticMethod for the method
122 * @throws IllegalArgumentException if the method is abstract or static
123 */
124 PlasticMethod introduceMethod(MethodDescription description);
125
126 /**
127 * Returns an existing method declared in this class, or introduces a new method into this class.
128 * The method is created with default behavior.
129 * <p/>
130 * It is allowed for the method description to indicate an abstract method; however the abstract flag will be
131 * removed, and a non-abstract method will be created.
132 *
133 * @param description describes the method name, visibility, return value, etc.
134 * @param callback used to create the implementation of the method
135 * @return a new (or previously created) PlasticMethod for the method
136 * @throws IllegalArgumentException if the method is abstract or static
137 */
138 PlasticMethod introduceMethod(MethodDescription description, InstructionBuilderCallback callback);
139
140 /**
141 * A convenience that creates a {@link MethodDescription} from the Method and introduces that. This is often
142 * invoked when walking the methods of an interface and introducing each of those methods.
143 * <p/>
144 * Introduced methods are always concrete, not abstract. The abstract flag on the method modifiers will always be
145 * stripped off, which is handy when {@linkplain #introduceInterface(Class) introducing methods from an interface}.
146 *
147 * @param method to introduce
148 * @return new (or previously created) PlasticMethod
149 */
150 PlasticMethod introduceMethod(Method method);
151
152 /**
153 * Introduces each method defined by the interface into the class. Determines which new methods must
154 * be introduced in order to ensure that all methods of the interface are implemented. The newly introduced methods,
155 * if any, are returned.
156 */
157 Set<PlasticMethod> introduceInterface(Class interfaceType);
158
159 /**
160 * Introduces the interface, and then invokes {@link PlasticMethod#delegateTo(PlasticField)} on each method
161 * defined by the interface.
162 *
163 * @param interfaceType defines the interface to proxy
164 * @param field field containing an object to delegate to
165 * @return this plastic class, for further configuration
166 */
167 PlasticClass proxyInterface(Class interfaceType, PlasticField field);
168
169 /**
170 * Conditionally adds an implementation of <code>toString()</code> to the class, but only if it is not already
171 * present in the class, or in a (transformed) super-class.
172 *
173 * @param toStringValue the fixed value to be returned from invoking toString()
174 * @return this plastic class, for further configuration
175 */
176 PlasticClass addToString(String toStringValue);
177
178 /**
179 * Returns true if this class has an implementation of the indicated method, or a super-class provides
180 * a non-abstract implementation.
181 */
182 boolean isMethodImplemented(MethodDescription description);
183
184 /**
185 * Returns true if this class, or a super-class, implements the indicated interface.
186 *
187 * @param interfaceType
188 * @return true if the interface is implemented
189 */
190 boolean isInterfaceImplemented(Class interfaceType);
191
192 /**
193 * Returns the name of the super-class of the class being transformed.
194 */
195 String getSuperClassName();
196
197 /**
198 * Adds the callback for execution when an instance of the class is instantiated.
199 *
200 * @param callback to execute at instance construction time
201 */
202 PlasticClass onConstruct(ConstructorCallback callback);
203 }