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