You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2011/09/27 23:17:12 UTC
svn commit: r1176625 - in /tapestry/tapestry5/trunk:
plastic/src/main/java/org/apache/tapestry5/internal/plastic/
plastic/src/main/java/org/apache/tapestry5/plastic/
plastic/src/test/groovy/org/apache/tapestry5/plastic/
plastic/src/test/java/testinterf...
Author: hlship
Date: Tue Sep 27 21:17:11 2011
New Revision: 1176625
URL: http://svn.apache.org/viewvc?rev=1176625&view=rev
Log:
TAP5-1673: Tapestry 5.2 supported references to public static fields of classes; this is not supported by 5.3
Added:
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/StaticFieldAccess.groovy
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/Access.java
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticFieldHolder.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PublicStaticFieldBean.java
Modified:
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAnnotationAccess.groovy
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java Tue Sep 27 21:17:11 2011
@@ -14,36 +14,26 @@
package org.apache.tapestry5.internal.plastic;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
import org.apache.tapestry5.internal.plastic.InstructionBuilderState.LVInfo;
import org.apache.tapestry5.internal.plastic.asm.Label;
import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
import org.apache.tapestry5.internal.plastic.asm.Opcodes;
import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.plastic.Condition;
-import org.apache.tapestry5.plastic.InstructionBuilder;
-import org.apache.tapestry5.plastic.InstructionBuilderCallback;
-import org.apache.tapestry5.plastic.LocalVariable;
-import org.apache.tapestry5.plastic.LocalVariableCallback;
-import org.apache.tapestry5.plastic.MethodDescription;
-import org.apache.tapestry5.plastic.PlasticField;
-import org.apache.tapestry5.plastic.PlasticMethod;
-import org.apache.tapestry5.plastic.PlasticUtils;
-import org.apache.tapestry5.plastic.SwitchCallback;
-import org.apache.tapestry5.plastic.TryCatchCallback;
-import org.apache.tapestry5.plastic.WhenCallback;
-import org.apache.tapestry5.plastic.WhileCallback;
+import org.apache.tapestry5.plastic.*;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
@SuppressWarnings("rawtypes")
public class InstructionBuilderImpl extends Lockable implements Opcodes, InstructionBuilder
{
private static final int[] DUPE_OPCODES = new int[]
- { DUP, DUP_X1, DUP_X2 };
+ {DUP, DUP_X1, DUP_X2};
- /** Maps from condition to opcode to jump to the false code block. */
+ /**
+ * Maps from condition to opcode to jump to the false code block.
+ */
private static final Map<Condition, Integer> conditionToOpcode = new HashMap<Condition, Integer>();
static
@@ -126,8 +116,7 @@ public class InstructionBuilderImpl exte
{
v.visitInsn(ACONST_NULL);
v.visitInsn(ARETURN);
- }
- else
+ } else
{
switch (type)
{
@@ -222,7 +211,7 @@ public class InstructionBuilderImpl exte
}
public InstructionBuilder invokeVirtual(String className, String returnType, String methodName,
- String... argumentTypes)
+ String... argumentTypes)
{
check();
@@ -232,7 +221,7 @@ public class InstructionBuilderImpl exte
}
public InstructionBuilder invokeInterface(String interfaceName, String returnType, String methodName,
- String... argumentTypes)
+ String... argumentTypes)
{
check();
@@ -337,6 +326,38 @@ public class InstructionBuilderImpl exte
return this;
}
+ public InstructionBuilder getStaticField(String className, String fieldName, String typeName)
+ {
+ check();
+
+ v.visitFieldInsn(GETSTATIC, cache.toInternalName(className), fieldName, cache.toDesc(typeName));
+
+ return this;
+ }
+
+ public InstructionBuilder getStaticField(String className, String fieldName, Class fieldType)
+ {
+ check();
+
+ return getStaticField(className, fieldName, cache.toTypeName(fieldType));
+ }
+
+ public InstructionBuilder putStaticField(String className, String fieldName, Class fieldType)
+ {
+ check();
+
+ return putStaticField(className, fieldName, cache.toTypeName(fieldType));
+ }
+
+ public InstructionBuilder putStaticField(String className, String fieldName, String typeName)
+ {
+ check();
+
+ v.visitFieldInsn(PUTSTATIC, cache.toInternalName(className), fieldName, cache.toDesc(typeName));
+
+ return this;
+ }
+
public InstructionBuilder getField(PlasticField field)
{
check();
@@ -378,8 +399,7 @@ public class InstructionBuilderImpl exte
if (type == null)
{
v.visitInsn(AALOAD);
- }
- else
+ } else
{
throw new RuntimeException("Access to non-object arrays is not yet supported.");
}
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java Tue Sep 27 21:17:11 2011
@@ -23,12 +23,20 @@ public class Lockable
{
private boolean locked;
+ /**
+ * Checks to see if the object has been locked.
+ *
+ * @throw IllegalStateException if {@link #lock()} has been invoked.
+ */
protected void check()
{
if (locked)
throw new IllegalStateException(toString() + " has been locked and can no longer be used.");
}
+ /**
+ * Invokes {@link #check()}, then sets the locked flag. Subsequent calls to {@link #check()} will fail.
+ */
protected void lock()
{
check();
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java Tue Sep 27 21:17:11 2011
@@ -21,9 +21,9 @@ import java.lang.reflect.Method;
* created with a friendlier API that focuses on Java type names (names as they would appear in Java source) rather than
* JVM descriptors or internal names. In some limited cases, types may be specified as Java Class instances as well.
* In addition, there is good support for primitive type boxing and unboxing.
- * <p>
+ * <p/>
* Most methods return the same instance of InstructionBuilder, allowing for a "fluid" API.
- * <p>
+ * <p/>
* More complex functionality, such as {@linkplain #startTryCatch(TryCatchCallback)
* try/catch blocks}, is more like a DSL (domain specific language), and is based on callbacks. This looks better in
* Groovy and will be more reasonable once JDK 1.8 closures are available; in the meantime, it means some deeply nested
@@ -33,7 +33,9 @@ import java.lang.reflect.Method;
@SuppressWarnings("rawtypes")
public interface InstructionBuilder
{
- /** Returns the default value for the method, which may be null, or a specific primitive value. */
+ /**
+ * Returns the default value for the method, which may be null, or a specific primitive value.
+ */
@Opcodes("ACONST_NULL, LCONST_0, FCONST_0, DCONST_0, ICONST_0, RETURN, ARETURN, IRETURN, FRETURN, LRETURN, DRETURN")
InstructionBuilder returnDefaultValue();
@@ -53,9 +55,8 @@ public interface InstructionBuilder
* Loads an argument onto the stack, using the opcode appropriate to the argument's type. In addition
* this automatically adjusts for arguments of primitive type long or double (which take up two
* local variable indexes, rather than one as for all other types)
- *
- * @param index
- * to argument (0 is the first argument, not this)
+ *
+ * @param index to argument (0 is the first argument, not this)
*/
@Opcodes("ALOAD, ILOAD, LLOAD, FLOAD, DLOAD")
InstructionBuilder loadArgument(int index);
@@ -71,11 +72,9 @@ public interface InstructionBuilder
/**
* Invokes an instance method of a base class, or a private method of a class, using the target object
* and parameters already on the stack. Leaves the result on the stack (unless its a void method).
- *
- * @param containingClassName
- * class name containing the method
- * @param description
- * describes the method name, parameters and return type
+ *
+ * @param containingClassName class name containing the method
+ * @param description describes the method name, parameters and return type
*/
@Opcodes("INVOKESPECIAL")
InstructionBuilder invokeSpecial(String containingClassName, MethodDescription description);
@@ -94,7 +93,7 @@ public interface InstructionBuilder
*/
@Opcodes("INVOKEINTERFACE")
InstructionBuilder invokeInterface(String interfaceName, String returnType, String methodName,
- String... argumentTypes);
+ String... argumentTypes);
/**
* Automatically invokes an interface or virtual method. Remember to use {@link #invokeConstructor(Class, Class...)}
@@ -132,9 +131,8 @@ public interface InstructionBuilder
/**
* Unboxes a wrapper type to a primitive type if typeName is a primitive type name (the value on the stack
* should be the corresponding wrapper type instance). Does nothing for non-primitive types.
- *
- * @param typeName
- * possibly primitive type name
+ *
+ * @param typeName possibly primitive type name
*/
@Opcodes("INVOKEVIRTUAL")
InstructionBuilder unboxPrimitive(String typeName);
@@ -142,23 +140,19 @@ public interface InstructionBuilder
/**
* Loads an instance field onto the stack. The object containing the field should already be loaded onto the stack
* (usually, via {@link #loadThis()}).
- *
- * @param className
- * name of class containing the field
- * @param fieldName
- * name of the field
- * @param typeName
- * type of field
+ *
+ * @param className name of class containing the field
+ * @param fieldName name of the field
+ * @param typeName type of field
*/
@Opcodes("GETFIELD")
InstructionBuilder getField(String className, String fieldName, String typeName);
/**
- * Loads an instance field onto the stack. The plastic class instance containing the field should already be loaded
+ * Loads an instance or static field onto the stack. The plastic class instance containing the field should already be loaded
* onto the stack (usually, via {@link #loadThis()}).
- *
- * @param field
- * identifies name, type and container of field to load
+ *
+ * @param field identifies name, type and container of field to load
*/
@Opcodes("GETFIELD")
InstructionBuilder getField(PlasticField field);
@@ -166,18 +160,60 @@ public interface InstructionBuilder
/**
* Loads a field onto the stack. This version is used when the
* field type is known at build time, rather than discovered at runtime.
- *
- * @param className
- * name of class containing the field
- * @param fieldName
- * name of the field
- * @param fieldType
- * type of field
+ *
+ * @param className name of class containing the field
+ * @param fieldName name of the field
+ * @param fieldType type of field
*/
@Opcodes("GETFIELD")
InstructionBuilder getField(String className, String fieldName, Class fieldType);
- /** Expects the stack to contain the instance to update, and the value to store into the field. */
+ /**
+ * Gets a static field; does not consume a value from the stack, but pushes the fields' value onto the stack.
+ *
+ * @param className name of class containing the field
+ * @param fieldName name of the field
+ * @param fieldType type of field
+ */
+ @Opcodes("GETSTATIC")
+ InstructionBuilder getStaticField(String className, String fieldName, Class fieldType);
+
+ /**
+ * Gets a static field; does not consume a value from the stack, but pushes the fields' value onto the stack.
+ *
+ * @param className name of class containing the field
+ * @param fieldName name of the field
+ * @param typeName type of field
+ */
+ @Opcodes("GETSTATIC")
+ InstructionBuilder getStaticField(String className, String fieldName,
+ String typeName);
+
+
+ /**
+ * Sets a static field; the new field value should be on top of the stack.
+ *
+ * @param className name of class containing the field
+ * @param fieldName name of the field
+ * @param fieldType type of field
+ */
+ @Opcodes("PUTSTATIC")
+ InstructionBuilder putStaticField(String className, String fieldName, Class fieldType);
+
+ /**
+ * Sets a static field; the new field value should be on top of the stack.
+ *
+ * @param className name of class containing the field
+ * @param fieldName name of the field
+ * @param typeName type of field
+ */
+ @Opcodes("PUTSTATIC")
+ InstructionBuilder putStaticField(String className, String fieldName,
+ String typeName);
+
+ /**
+ * Expects the stack to contain the instance to update, and the value to store into the field.
+ */
@Opcodes("PUTFIELD")
InstructionBuilder putField(String className, String fieldName, String typeName);
@@ -186,13 +222,11 @@ public interface InstructionBuilder
/**
* Loads a value from an array object, which must be the top element of the stack.
- *
- * @param index
- * constant index into the array
- * @param elementType
- * the type name of the elements of the array
- * <strong>Note: currently only reference types (objects and arrays) are supported, not
- * primitives</strong>
+ *
+ * @param index constant index into the array
+ * @param elementType the type name of the elements of the array
+ * <strong>Note: currently only reference types (objects and arrays) are supported, not
+ * primitives</strong>
*/
@Opcodes("LDC, AALOAD")
InstructionBuilder loadArrayElement(int index, String elementType);
@@ -206,9 +240,8 @@ public interface InstructionBuilder
/**
* Adds a check that the object on top of the stack is assignable to the indicated class.
- *
- * @param className
- * class to cast to
+ *
+ * @param className class to cast to
*/
@Opcodes("CHECKCAST")
InstructionBuilder checkcast(String className);
@@ -220,18 +253,16 @@ public interface InstructionBuilder
* Defines the start of a block that can have exception handlers and finally blocks applied.
* Continue using this InstructionBuilder to define code inside the block, then call
* methods on the InstructionBlock to define the end of the block and set up handlers.
- *
- * @param tryCatchCallback
- * allows generation of try, catch, and finally clauses
+ *
+ * @param tryCatchCallback allows generation of try, catch, and finally clauses
*/
InstructionBuilder startTryCatch(TryCatchCallback tryCatchCallback);
/**
* Creates a new, uninitialized instance of the indicated class. This should be followed
* by code to call the new instance's constructor.
- *
- * @param className
- * of class to instantiate
+ *
+ * @param className of class to instantiate
*/
@Opcodes("NEW")
InstructionBuilder newInstance(String className);
@@ -239,9 +270,8 @@ public interface InstructionBuilder
/**
* A convenience version of {@link #newInstance(String)} used when the class is known
* at build time.
- *
- * @param clazz
- * to instantiate
+ *
+ * @param clazz to instantiate
*/
@Opcodes("NEW")
InstructionBuilder newInstance(Class clazz);
@@ -251,11 +281,9 @@ public interface InstructionBuilder
* by the right number and type of parameters. Note that a constructor acts like a void method,
* so you will often follow the sequence: newInstance(), dupe(0), invokeConstructor() so that a reference
* to the instance is left on the stack.F
- *
- * @param className
- * the class containing the constructor
- * @param argumentTypes
- * java type names for each argument of the constructor
+ *
+ * @param className the class containing the constructor
+ * @param argumentTypes java type names for each argument of the constructor
*/
@Opcodes("INVOKESPECIAL")
InstructionBuilder invokeConstructor(String className, String... argumentTypes);
@@ -265,24 +293,27 @@ public interface InstructionBuilder
/**
* Duplicates the top object on the stack, placing the result at some depth.
- *
- * @param depth
- * 0 (DUP), 1 (DUP_X1) or 2 (DUP_X2)
+ *
+ * @param depth 0 (DUP), 1 (DUP_X1) or 2 (DUP_X2)
*/
@Opcodes("DUP, DUP_X1, DUP_X2")
InstructionBuilder dupe(int depth);
- /** Duplicates a wide value (a primitive long or double). */
+ /**
+ * Duplicates a wide value (a primitive long or double).
+ */
@Opcodes("DUP2")
InstructionBuilder dupeWide();
- /** Pops a wide value (a primitive long or double). */
+ /**
+ * Pops a wide value (a primitive long or double).
+ */
@Opcodes("POP2")
InstructionBuilder popWide();
/**
* Duplicates the top object on the stack. Commonly used with {@link #when(Condition, WhenCallback)}.
- *
+ *
* @see #dupe(int)
*/
@Opcodes("DUP")
@@ -304,9 +335,8 @@ public interface InstructionBuilder
/**
* Loads a constant value
- *
- * @param constant
- * Integer, Float, Double, Long, String or null
+ *
+ * @param constant Integer, Float, Double, Long, String or null
*/
@Opcodes("LDC, ICONST_*, LCONST_*, FCONST_*, DCONST_*, ACONST_NULL")
InstructionBuilder loadConstant(Object constant);
@@ -314,9 +344,8 @@ public interface InstructionBuilder
/**
* Loads a Java type (a Class instance) as a constant. This assumes the type name is the name of class (or array)
* but not a primitive type.
- *
- * @param typeName
- * Java class name
+ *
+ * @param typeName Java class name
*/
@Opcodes("LDC")
InstructionBuilder loadTypeConstant(String typeName);
@@ -324,9 +353,8 @@ public interface InstructionBuilder
/**
* Loads a Java type (a Class instance) as a constant. This assumes the type name is the name of class (or array)
* but not a primitive type.
- *
- * @param type
- * Java type to load as a constant
+ *
+ * @param type Java type to load as a constant
*/
@Opcodes("LDC")
InstructionBuilder loadTypeConstant(Class type);
@@ -334,9 +362,8 @@ public interface InstructionBuilder
/**
* Casts the object on top of the stack to the indicated type. For primitive types, casts to the wrapper type
* and invokes the appropriate unboxing static method call, leaving a primitive type value on the stack.
- *
- * @param typeName
- * to cast or unbox to
+ *
+ * @param typeName to cast or unbox to
*/
@Opcodes("CHECKCAST, INVOKEVIRTUAL")
InstructionBuilder castOrUnbox(String typeName);
@@ -344,11 +371,9 @@ public interface InstructionBuilder
/**
* Throws an exception with a fixed message. Assumes the exception class includes a constructor that takes a single
* string.
- *
- * @param className
- * name of exception class to instantiate
- * @param message
- * message (passed as first and only parameter to constructor)
+ *
+ * @param className name of exception class to instantiate
+ * @param message message (passed as first and only parameter to constructor)
*/
@Opcodes("NEW, DUP, LDC, INVOKESPECIAL, ATHROW")
InstructionBuilder throwException(String className, String message);
@@ -364,22 +389,18 @@ public interface InstructionBuilder
/**
* Starts a switch statement.
- *
- * @param min
- * the minimum value to match against
- * @param max
- * the maximum value to match against
+ *
+ * @param min the minimum value to match against
+ * @param max the maximum value to match against
*/
@Opcodes("TABLESWITCH")
InstructionBuilder startSwitch(int min, int max, SwitchCallback callback);
/**
* Starts a block where the given name is active.
- *
- * @param type
- * type of local variable
- * @param callback
- * generates code used when variable is in effect
+ *
+ * @param type type of local variable
+ * @param callback generates code used when variable is in effect
*/
InstructionBuilder startVariable(String type, LocalVariableCallback callback);
@@ -400,11 +421,9 @@ public interface InstructionBuilder
/**
* Executes conditional code based on a {@link Condition}. The testing opcodes all pop
* the value off the stack, so this is usually preceded by {@link #dupe(int) dupe(0)}.
- *
- * @param condition
- * defines true and false cases
- * @param callback
- * provides code for true and false blocks
+ *
+ * @param condition defines true and false cases
+ * @param callback provides code for true and false blocks
* @return this builder
*/
@Opcodes("IFEQ, etc., GOTO")
@@ -414,13 +433,11 @@ public interface InstructionBuilder
* Simplified version of {@link #when(Condition, WhenCallback)} that
* simply executes the callback code when the condition is true and does nothing
* if the condition is false (the more general case).
- * <p>
+ * <p/>
* The testing opcodes all pop the value off the stack, so this is usually preceded by {@link #dupe(int) dupe(0)}.
- *
- * @param condition
- * to evaluate
- * @param ifTrue
- * generates code for when condition is true
+ *
+ * @param condition to evaluate
+ * @param ifTrue generates code for when condition is true
* @return this builder
*/
@Opcodes("IFEQ, etc., GOTO")
@@ -431,7 +448,7 @@ public interface InstructionBuilder
* code is executed, then the condition is evaluated (which will consume at least the top value on the stack).
* When the condition is false, the loop is exited. When the condition is true, the code defined by
* {@link WhileCallback#buildBody(InstructionBuilder)} is executed, and then a GOTO back to the test code.
- *
+ *
* @param condition
* @param callback
* @return this builder
@@ -443,10 +460,9 @@ public interface InstructionBuilder
* Expects an array to be the top value on the stack. Iterates the array.
* The callback generates code that will have each successive value from the array
* as the top value on the stack. Creates a variable to store the loop index.
- *
- * @param callback
- * to invoke. The element will be the top value on the stack. The callback is responsible
- * for removing it from the stack.
+ *
+ * @param callback to invoke. The element will be the top value on the stack. The callback is responsible
+ * for removing it from the stack.
* @return this builder
*/
@Opcodes("IINC, ARRAYLENGTH, IFEQ, etc., GOTO")
@@ -454,13 +470,15 @@ public interface InstructionBuilder
/**
* Increments a local integer variable.
- *
+ *
* @return this builder
*/
@Opcodes("IINC")
InstructionBuilder increment(LocalVariable variable);
- /** Expects the top object on the stack to be an array. Replaces it with the length of that array. */
+ /**
+ * Expects the top object on the stack to be an array. Replaces it with the length of that array.
+ */
@Opcodes("ARRAYLENGTH")
InstructionBuilder arrayLength();
@@ -468,7 +486,7 @@ public interface InstructionBuilder
* Special comparison logic for primitive float, double and long. Expect two matching wide values
* on the stack. Reduces the two wide values to a single int value: -1, 0, or 1 depending on whether the deeper
* value is less than, equal to, or greater than the top value on the stack.
- *
+ *
* @param typeName
*/
@Opcodes("LCMP, FCMPL, DCMPL")
Modified: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAnnotationAccess.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAnnotationAccess.groovy?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAnnotationAccess.groovy (original)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAnnotationAccess.groovy Tue Sep 27 21:17:11 2011
@@ -1,15 +1,14 @@
package org.apache.tapestry5.plastic
-import org.apache.tapestry5.plastic.PlasticManager;
+import testannotations.Maybe
-import spock.lang.Specification
-import testannotations.Maybe;
+class FieldAnnotationAccess extends AbstractPlasticSpecification
+{
-class FieldAnnotationAccess extends AbstractPlasticSpecification {
-
- def "locate field by annotation"() {
+ def "read static field"()
+ {
setup:
- def pc = mgr.getPlasticClass("testsubjects.AnnotationSubject")
+ def pc = mgr.getPlasticClass("testsubjects.AnnotationSubject")
when:
def fields = pc.getFieldsWithAnnotation(Maybe.class)
Added: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/StaticFieldAccess.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/StaticFieldAccess.groovy?rev=1176625&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/StaticFieldAccess.groovy (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/StaticFieldAccess.groovy Tue Sep 27 21:17:11 2011
@@ -0,0 +1,38 @@
+package org.apache.tapestry5.plastic
+
+import testinterfaces.Access
+
+class StaticFieldAccess extends AbstractPlasticSpecification
+{
+ def "static fields are readable and writable"()
+ {
+ setup:
+ def pc = mgr.getPlasticClass("testsubjects.StaticFieldHolder")
+
+ pc.introduceInterface(Access.class)
+
+ pc.introduceMethod(new MethodDescription("java.lang.Object", "read")).changeImplementation({
+ InstructionBuilder b ->
+ b.getStaticField("testsubjects.StaticFieldHolder", "VALUE", String.class).returnResult()
+ } as InstructionBuilderCallback)
+
+ pc.introduceMethod(new MethodDescription("void", "write", "java.lang.Object")).changeImplementation({
+ InstructionBuilder b ->
+ b.loadArgument(0).checkcast(String.class)
+ b.putStaticField("testsubjects.StaticFieldHolder", "VALUE", String.class).returnResult()
+ } as InstructionBuilderCallback)
+
+ Access o = pc.createInstantiator().newInstance()
+
+ expect:
+
+ o.read().is(o.VALUE)
+
+ when:
+ o.write "newvalue"
+
+ then:
+
+ o.VALUE == "newvalue"
+ }
+}
Added: tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/Access.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/Access.java?rev=1176625&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/Access.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/Access.java Tue Sep 27 21:17:11 2011
@@ -0,0 +1,8 @@
+package testinterfaces;
+
+public interface Access
+{
+ Object read();
+
+ void write(Object newValue);
+}
Added: tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticFieldHolder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticFieldHolder.java?rev=1176625&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticFieldHolder.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticFieldHolder.java Tue Sep 27 21:17:11 2011
@@ -0,0 +1,6 @@
+package testsubjects;
+
+public class StaticFieldHolder
+{
+ public static String VALUE = "initial";
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java Tue Sep 27 21:17:11 2011
@@ -40,9 +40,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
+import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -502,13 +500,13 @@ public class PropertyConduitSourceImpl i
{
if (adapter.getWriteMethod() != null)
{
- implementSetter(activeType, adapter.getWriteMethod());
+ implementSetter(adapter.getWriteMethod());
return;
}
- if (adapter.getField() != null)
+ if (adapter.getField() != null && adapter.isUpdate())
{
- implementSetter(activeType, adapter.getField());
+ implementSetter(adapter.getField());
return;
}
@@ -516,8 +514,30 @@ public class PropertyConduitSourceImpl i
rootType.getName());
}
- private void implementSetter(Type activeType, final Field field)
+ private boolean isStatic(Member member)
+ {
+ return Modifier.isStatic(member.getModifiers());
+ }
+
+ private void implementSetter(final Field field)
{
+ if (isStatic(field))
+ {
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+ builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ builder.returnResult();
+ }
+ });
+
+ return;
+ }
+
plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
@@ -533,7 +553,7 @@ public class PropertyConduitSourceImpl i
});
}
- private void implementSetter(Type activeType, final Method writeMethod)
+ private void implementSetter(final Method writeMethod)
{
plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
{
@@ -557,13 +577,13 @@ public class PropertyConduitSourceImpl i
{
if (adapter.getReadMethod() != null)
{
- implementGetter(activeType, adapter.getReadMethod());
+ implementGetter(adapter.getReadMethod());
return;
}
if (adapter.getField() != null)
{
- implementGetter(activeType, adapter.getField());
+ implementGetter(adapter.getField());
return;
}
@@ -571,8 +591,27 @@ public class PropertyConduitSourceImpl i
rootType.getName());
}
- private void implementGetter(final Type activeType, final Field field)
+ private void implementGetter(final Field field)
{
+ if (isStatic(field))
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ // Cast not necessary here since the return type of get() is Object
+
+ boxIfPrimitive(builder, field.getType());
+
+ builder.returnResult();
+ }
+ });
+
+ return;
+ }
+
plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
@@ -590,7 +629,7 @@ public class PropertyConduitSourceImpl i
});
}
- private void implementGetter(final Type activeType, final Method readMethod)
+ private void implementGetter(final Method readMethod)
{
plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
{
@@ -598,8 +637,6 @@ public class PropertyConduitSourceImpl i
{
invokeNavigateMethod(builder);
- Type actualType = GenericsUtils.extractActualType(activeType, readMethod);
-
invokeMethod(builder, readMethod, null, 0);
boxIfPrimitive(builder, conduitPropertyType);
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java Tue Sep 27 21:17:11 2011
@@ -839,4 +839,35 @@ public class PropertyConduitSourceImplTe
assertSame(list.get(0), bean);
assertNull(list.get(1));
}
+
+ /**
+ * TAP5-1673
+ */
+ @Test
+ public void public_static_fields_are_accessible()
+ {
+ PropertyConduit pc = source.create(PublicStaticFieldBean.class, "value");
+
+ assertSame(pc.get(null), PublicStaticFieldBean.VALUE);
+
+ pc.set(null, "new-value");
+
+ assertEquals(PublicStaticFieldBean.VALUE, "new-value");
+ }
+
+ @Test
+ public void final_static_fields_are_read_only()
+ {
+ PropertyConduit pc = source.create(PublicStaticFieldBean.class, "read_only");
+
+ try
+ {
+ pc.set(null, "new-value");
+ unreachable();
+ } catch (RuntimeException ex)
+ {
+ assertEquals(ex.getMessage(),
+ "Expression 'read_only' for class org.apache.tapestry5.internal.services.PublicStaticFieldBean is read-only.");
+ }
+ }
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PublicStaticFieldBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PublicStaticFieldBean.java?rev=1176625&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PublicStaticFieldBean.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PublicStaticFieldBean.java Tue Sep 27 21:17:11 2011
@@ -0,0 +1,8 @@
+package org.apache.tapestry5.internal.services;
+
+public class PublicStaticFieldBean
+{
+ public static String VALUE = "initial value";
+
+ public static final String READ_ONLY = "read-only";
+}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java Tue Sep 27 21:17:11 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
package org.apache.tapestry5.ioc.internal.services;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
@@ -23,10 +22,11 @@ import org.apache.tapestry5.ioc.services
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
+import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
+
public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
{
private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
@@ -56,13 +56,10 @@ public class ClassPropertyAdapterImpl im
adapters.put(pa.getName(), pa);
}
- // Now, add any public fields that do not conflict
+ // Now, add any public fields (even if static) that do not conflict
for (Field f : beanType.getFields())
{
- if(Modifier.isStatic(f.getModifiers()))
- continue;
-
String name = f.getName();
if (!adapters.containsKey(name))
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java Tue Sep 27 21:17:11 2011
@@ -20,9 +20,7 @@ import org.apache.tapestry5.ioc.services
import org.apache.tapestry5.ioc.services.PropertyAdapter;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.lang.reflect.*;
import java.util.List;
public class PropertyAdapterImpl implements PropertyAdapter
@@ -39,6 +37,7 @@ public class PropertyAdapterImpl impleme
private final boolean castRequired;
+ // Synchronized by this; lazily initialized
private AnnotationProvider annotationProvider;
private final Field field;
@@ -46,7 +45,7 @@ public class PropertyAdapterImpl impleme
private final Class declaringClass;
PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod,
- Method writeMethod)
+ Method writeMethod)
{
this.classAdapter = classAdapter;
this.name = name;
@@ -105,7 +104,12 @@ public class PropertyAdapterImpl impleme
public boolean isUpdate()
{
- return field != null || writeMethod != null;
+ return writeMethod != null || (field != null && !isFinal(field));
+ }
+
+ private boolean isFinal(Member member)
+ {
+ return Modifier.isFinal(member.getModifiers());
}
public Object get(Object instance)
@@ -121,12 +125,10 @@ public class PropertyAdapterImpl impleme
return readMethod.invoke(instance);
else
return field.get(instance);
- }
- catch (InvocationTargetException ex)
+ } catch (InvocationTargetException ex)
{
fail = ex.getTargetException();
- }
- catch (Exception ex)
+ } catch (Exception ex)
{
fail = ex;
}
@@ -149,12 +151,10 @@ public class PropertyAdapterImpl impleme
field.set(instance, value);
return;
- }
- catch (InvocationTargetException ex)
+ } catch (InvocationTargetException ex)
{
fail = ex.getTargetException();
- }
- catch (Exception ex)
+ } catch (Exception ex)
{
fail = ex;
}
@@ -189,7 +189,8 @@ public class PropertyAdapterImpl impleme
Class cursor = getBeanType();
- out: while (cursor != null)
+ out:
+ while (cursor != null)
{
for (Field f : cursor.getDeclaredFields())
{
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java Tue Sep 27 21:17:11 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2011 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -26,7 +26,8 @@ import java.util.List;
public interface ClassPropertyAdapter
{
/**
- * Returns the names of all properties, sorted into alphabetic order.
+ * Returns the names of all properties, sorted into alphabetic order. This includes true properties
+ * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
*/
List<String> getPropertyNames();
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java Tue Sep 27 21:17:11 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008, 2010 The Apache Software Foundation
+// Copyright 2006, 2008, 2010, 2011 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@ import java.lang.reflect.Method;
* when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
* by the underlying field (when the property name matches the field name).
* <p/>
- * Starting in release 5.2, this property may actually be a public field.
- *
+ * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
+ *
* @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
*/
@SuppressWarnings("unchecked")
@@ -47,7 +47,7 @@ public interface PropertyAdapter extends
public Method getReadMethod();
/**
- * Returns true if the property is writeable (i.e., has a setter method or is a public field).
+ * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
*/
boolean isUpdate();
@@ -58,24 +58,19 @@ public interface PropertyAdapter extends
/**
* Reads the property value.
- *
- * @param instance
- * to read from
- * @throws UnsupportedOperationException
- * if the property is write only
+ *
+ * @param instance to read from
+ * @throws UnsupportedOperationException if the property is write only
*/
Object get(Object instance);
/**
* Updates the property value. The provided value must not be null if the property type is primitive, and must
* otherwise be of the proper type.
- *
- * @param instance
- * to update
- * @param value
- * new value for the property
- * @throws UnsupportedOperationException
- * if the property is read only
+ *
+ * @param instance to update
+ * @param value new value for the property
+ * @throws UnsupportedOperationException if the property is read only
*/
void set(Object instance, Object value);
@@ -104,22 +99,22 @@ public interface PropertyAdapter extends
Class getBeanType();
/**
- * Returns true if the property is actually a public field.
- *
+ * Returns true if the property is actually a public field (possibly, a public static field).
+ *
* @since 5.2
*/
boolean isField();
/**
* Returns the field if the property is a public field or null if the property is accessed via the read method.
- *
+ *
* @since 5.2
*/
Field getField();
/**
* The class in which the property (or public field) is defined.
- *
+ *
* @since 5.2
*/
Class getDeclaringClass();
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java?rev=1176625&r1=1176624&r2=1176625&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java Tue Sep 27 21:17:11 2011
@@ -41,8 +41,8 @@ public class PropertyAccessImplTest exte
public static class Bean
{
- public static Double PI = 3.14;
-
+ public static final Double PI = 3.14;
+
@DataType("fred")
@Validate("field-value-overridden")
private int value;
@@ -250,6 +250,7 @@ public class PropertyAccessImplTest exte
{
// abstract class implements method from interface
private String other;
+
public String getOtherValue()
{
return other;
@@ -266,19 +267,23 @@ public class PropertyAccessImplTest exte
private String value;
private int intValue;
- public ConcreteBean(int intValue) {
+ public ConcreteBean(int intValue)
+ {
this.intValue = intValue;
}
- public String getValue() {
+ public String getValue()
+ {
return value;
}
- public void setValue(String v) {
+ public void setValue(String v)
+ {
value = v;
}
- public int getIntValue() {
+ public int getIntValue()
+ {
return intValue;
}
}
@@ -341,8 +346,7 @@ public class PropertyAccessImplTest exte
access.get(b, "zaphod");
unreachable();
- }
- catch (IllegalArgumentException ex)
+ } catch (IllegalArgumentException ex)
{
assertEquals(ex.getMessage(), "Class " + CLASS_NAME + "$Bean does not "
+ "contain a property named 'zaphod'.");
@@ -358,8 +362,7 @@ public class PropertyAccessImplTest exte
{
access.set(b, "class", null);
unreachable();
- }
- catch (UnsupportedOperationException ex)
+ } catch (UnsupportedOperationException ex)
{
assertEquals(ex.getMessage(), "Class " + CLASS_NAME
+ "$Bean does not provide an mutator ('setter') method for property 'class'.");
@@ -375,8 +378,7 @@ public class PropertyAccessImplTest exte
{
access.get(b, "writeOnly");
unreachable();
- }
- catch (UnsupportedOperationException ex)
+ } catch (UnsupportedOperationException ex)
{
assertEquals(ex.getMessage(), "Class " + CLASS_NAME
+ "$Bean does not provide an accessor ('getter') method for property 'writeOnly'.");
@@ -392,8 +394,7 @@ public class PropertyAccessImplTest exte
{
access.get(b, "failure");
unreachable();
- }
- catch (RuntimeException ex)
+ } catch (RuntimeException ex)
{
assertEquals(ex.getMessage(), "Error reading property 'failure' of PropertyUtilsExceptionBean: getFailure");
}
@@ -408,8 +409,7 @@ public class PropertyAccessImplTest exte
{
access.set(b, "failure", false);
unreachable();
- }
- catch (RuntimeException ex)
+ } catch (RuntimeException ex)
{
assertEquals(ex.getMessage(), "Error updating property 'failure' of PropertyUtilsExceptionBean: setFailure");
}
@@ -424,8 +424,7 @@ public class PropertyAccessImplTest exte
{
access.get(b, "google");
unreachable();
- }
- catch (RuntimeException ex)
+ } catch (RuntimeException ex)
{
assertEquals(ex.getMessage(), "java.lang.RuntimeException: This is the UglyBean.");
}
@@ -455,7 +454,7 @@ public class PropertyAccessImplTest exte
ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
assertEquals(cpa.toString(), "<ClassPropertyAdaptor " + CLASS_NAME
- + "$Bean : class, readOnly, value, writeOnly>");
+ + "$Bean : PI, class, readOnly, value, writeOnly>");
}
@Test
@@ -508,7 +507,30 @@ public class PropertyAccessImplTest exte
{
ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
- assertEquals(cpa.getPropertyNames(), Arrays.asList("class", "readOnly", "value", "writeOnly"));
+ assertEquals(cpa.getPropertyNames(), Arrays.asList("PI", "class", "readOnly", "value", "writeOnly"));
+ }
+
+ @Test
+ public void read_static_field()
+ {
+ PropertyAdapter adapter = access.getAdapter(Bean.class).getPropertyAdapter("pi");
+
+ assertSame(adapter.get(null), Bean.PI);
+ }
+
+ @Test
+ public void static_final_fields_may_not_be_changed()
+ {
+ PropertyAdapter adapter = access.getAdapter(Bean.class).getPropertyAdapter("pi");
+
+ try
+ {
+ adapter.set(null, 3.0d);
+ unreachable();
+ } catch (RuntimeException ex)
+ {
+ assertMessageContains(ex, "Can not set static final", "org.apache.tapestry5.ioc.internal.services.PropertyAccessImplTest$Bean.PI");
+ }
}
@Test