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    }