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.util.List;
016
017/**
018 * A method of a {@linkplain PlasticClass transformed class}.
019 * <p/>
020 * No methods of this object should be invoked after the class transformation is
021 * {@linkplain PlasticClassTransformation#createInstantiator() completed}.
022 */
023public interface PlasticMethod extends AnnotationAccess
024{
025    /**
026     * Returns the PlasticClass containing this method.
027     */
028    PlasticClass getPlasticClass();
029
030    /**
031     * Returns a representation of the method's name, return value, argument types, etc.
032     */
033    MethodDescription getDescription();
034
035    /**
036     * Returns a handle that can be used to invoke a method of a transformed class instance.
037     */
038    MethodHandle getHandle();
039
040    /**
041     * Clears the instructions for this method, and creates a new empty InstructionBuilder so that the implementation of
042     * the method can be specified. This may be considered a kind of last resort when no other approach is sufficient.
043     * <p/>
044     * If the method is currently abstract, it will have its abstract flag cleared.
045     * <p/>
046     * If the method has advice, the advice is <em>not</em> lost but will instead wrap around the new method
047     * implementation.
048     *
049     * @param callback
050     *         passed the InstructionBuilder so that an implementation of the method can be created
051     * @return this method, for further configuration
052     */
053    PlasticMethod changeImplementation(InstructionBuilderCallback callback);
054
055    /**
056     * Adds advice to the method. Adding advice implicitly rewrites the implementation of the method (this occurs
057     * inside at the end of the class transformation). When the method is invoked, control will flow
058     * through the MethodAdvice <em>in the order they are added</em>. Each piece of advice will receive the
059     * {@link MethodInvocation} and should invoke {@link MethodInvocation#proceed()} to pass control to the next piece
060     * of advice (and ultimately, to the actual method invocation).
061     * <p/>
062     * If a method implementation is changed, using {@link #changeImplementation(InstructionBuilderCallback)}, that
063     * change will be honored, but the logic will only be invoked at the end of the chain of MethodAdvice. Internally, a
064     * new method is created with the same parameters, exceptions, return type and implementation (bytecode) as the
065     * advised method, <em>then</em> the advised method's implementation is changed.
066     * <p/>
067     * Note additionally that a recursive method invocation will still invoke the MethodAdvice chain on each recursive
068     * call (this is an intended side-effect of copying the exact bytecode of the method implementation.
069     *
070     * @param advice
071     *         advice to add to the method
072     * @return this method, for further configuration
073     */
074    PlasticMethod addAdvice(MethodAdvice advice);
075
076    /**
077     * Changes the implementation of the method to delegate to the provided field. The field must implement the
078     * correct interface (or extend the correct class). The original implementation of the method is lost,
079     * though (as with {@link #changeImplementation(InstructionBuilderCallback)}), method advice is retained.
080     *
081     * @param field
082     *         to delegate to
083     * @return this method, for further configuration
084     */
085    PlasticMethod delegateTo(PlasticField field);
086
087    /**
088     * Much like {@link #delegateTo(PlasticField)}, but the object to delegate to
089     * is dynamically computed by another method of the class. The method should take no parameters
090     * and must not return null, or throw any exceptions not compatible with the method being proxied.
091     *
092     * @param method
093     *         to provide the dynamic delegate
094     * @return this method, for further configuration
095     */
096    PlasticMethod delegateTo(PlasticMethod method);
097
098    /**
099     * Returns access to the parameters of the method and, in particular,
100     * the visible annotations on those parameters.
101     */
102    List<MethodParameter> getParameters();
103
104    /**
105     * Returns true if the method is an override of a method from the parent class.
106     *
107     * @return true if the parent class contains a method with the name signature
108     */
109    boolean isOverride();
110
111    /**
112     * Returns true if the method is abstract.
113     *
114     * @since 5.4
115     */
116    boolean isAbstract();
117
118    /**
119     * Returns a short identifier for the method that includes the class name, the method name,
120     * and the types of all parameters. This is often used when producing debugging output
121     * about the method.
122     *
123     * @return short identifier
124     * @see org.apache.tapestry5.plastic.MethodDescription#toShortString()
125     */
126    String getMethodIdentifier();
127
128    /**
129     * Returns true if this method is type void.
130     *
131     * @return true for void methods.
132     */
133    boolean isVoid();
134}