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
017/**
018 * Represents a field of a class being {@linkplain PlasticClass transformed}.
019 * <p>
020 * No methods of this object should be invoked after the class transformation is completed.
021 */
022public interface PlasticField extends AnnotationAccess
023{
024    /** Returns the class containing this field. */
025    PlasticClass getPlasticClass();
026
027    /**
028     * Returns a handle that can be used to directly access a private field of a
029     * transformed class instance.
030     */
031    FieldHandle getHandle();
032
033    /**
034     * Returns the name of the field.
035     */
036    String getName();
037
038    /**
039     * Returns the fully qualified class name for the field's type or (for a primitive type)
040     * the primitive type name ("int", "char", etc.). For array types, the returned name includes
041     * a "[]" suffix.
042     */
043    String getTypeName();
044
045    /**
046     * Claims the field, used to indicate that the field is "processed". A field may only
047     * be claimed once. Claiming a field is intended as a mechanism to detect or prevent
048     * conflicts between different isolated transformations of the field. The tag value used does not matter, and is
049     * typically either an annotation (that drove the transformation) or the instance of {@link PlasticClassTransformer}
050     * that performed the transformation. That tag value is only used when generating the error message for the case
051     * where a field is claimed for than once.
052     * 
053     * @throws RuntimeException
054     *             if the field is claimed a second time
055     * @throws AssertionError
056     *             if tag is null
057     * @see PlasticClass#getUnclaimedFields()
058     * @return the field for further manipulation
059     */
060    PlasticField claim(Object tag);
061
062    /**
063     * Returns true if the field has already been {@linkplain #claim(Object) claimed}.
064     * 
065     * @see PlasticClass#getUnclaimedFields()
066     */
067    boolean isClaimed();
068
069    /**
070     * Converts the field to be read-only, and provide the indicated value. The field's value will be
071     * set inside the class' constructor.
072     * 
073     * @param value
074     *            to inject, which must be type compatible with the field (possibly, a wrapper type if the field is
075     *            a primitive value). The value may not be null.
076     * @return the field for further manipulation
077     * @throws IllegalStateException
078     *             if the field already has an injection, or the field has a conduit
079     */
080    PlasticField inject(Object value);
081
082    /**
083     * Converts the field to be read-only, and provide the value, which is computed
084     * indirectly inside the class' constructor.
085     * 
086     * @param computedValue
087     *            provides the actual value to be injected, and must return a value type compatible
088     *            with the field (possibly a wrapper type if the field is a primitive value). The computedValue may not
089     *            be null.
090     * @return the field for further manipulation
091     * @throws IllegalStateException
092     *             if the field already has an injection, or the field has a conduit
093     */
094    PlasticField injectComputed(ComputedValue<?> computedValue);
095
096    /**
097     * As with {@link #inject(Object)}, but the value is extracted from the {@link InstanceContext}.
098     * 
099     * @return this field for further manipulation
100     */
101    PlasticField injectFromInstanceContext();
102
103    /**
104     * Intercepts all access to the field, replacing such access with calls on the conduit. Even access via
105     * the FieldHandle will instead delegate to the conduit. Once a conduit is provided, it is not possible
106     * to inject a value into the field.
107     * <p>
108     * Normally, once a conduit is in place, the field will never be actually read or written. This is problematic for
109     * debugging, so {@link TransformationOption#FIELD_WRITEBEHIND} is useful when operating in a non-production mode.
110     *
111     * @return the field for further manipulation
112     * @throws IllegalStateException
113     *             if the field already has an injection or a conduit
114     * @return this field for further manipulation
115     */
116    <F> PlasticField setConduit(FieldConduit<F> conduit);
117
118    /**
119     * Sets the conduit for the field to a value computed when the class is instantiated
120     * 
121     * @param computedConduit
122     *            object that will compute the actual conduit to be used
123     * @return this field for further manipulation
124     */
125   <F>  PlasticField setComputedConduit(ComputedValue<FieldConduit<F>> computedConduit);
126
127    /**
128     * Creates access to the field, using the default property name derived from the name of the field.
129     * The default property name is the same as the name of the field, but with any leading or trailing underscore
130     * characters removed (a common convention among some programmers). Also, strips leading "m_" from the field name
131     * (another common convention).
132     * 
133     * @param accessType
134     *            which methods to create
135     * @return the field for further manipulation
136     * @throws IllegalArgumentException
137     *             if an accessor method to be created already exists (possibly inherited from a base class)
138     */
139    PlasticField createAccessors(PropertyAccessType accessType);
140
141    /**
142     * Creates accessors, possibly replacing existing methods (or overriding methods from a super class).
143     * The method names consist of the property name, with its first character converted to upper-case, prefixed
144     * with "get" or "set". The accessor methods must not already exist.
145     * 
146     * @param accessType
147     *            which methods to create
148     * @param propertyName
149     *            the name of the property (from which the names of the methods are generated)
150     * @return the field for further manipulation
151     * @throws IllegalArgumentException
152     *             if an accessor method to be created already exists (possibly inherited from a base class)
153     */
154    PlasticField createAccessors(PropertyAccessType accessType, String propertyName);
155
156    /** Returns the field's fully qualified generic type, or null if not defined. */
157    String getGenericSignature();
158
159    /** Returns the modifiers on the field. */
160    int getModifiers();
161}