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