You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2006/07/24 03:12:56 UTC
svn commit: r424872 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/internal/ioc/
main/java/org/apache/tapestry/internal/ioc/services/
main/java/org/apache/tapestry/ioc/services/
test/java/org/apache/tapestry/internal/io...
Author: hlship
Date: Sun Jul 23 18:12:55 2006
New Revision: 424872
URL: http://svn.apache.org/viewvc?rev=424872&view=rev
Log:
Add new methods to ClassFab to make it easier to add an implementation of toString(), or to proxy method invocations to a delegate.
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFabImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java?rev=424872&r1=424871&r2=424872&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java Sun Jul 23 18:12:55 2006
@@ -33,7 +33,6 @@
import org.apache.tapestry.ioc.services.ClassFab;
import org.apache.tapestry.ioc.services.ClassFabUtils;
import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.MethodIterator;
import org.apache.tapestry.ioc.services.MethodSignature;
import org.apache.tapestry.util.BodyBuilder;
@@ -291,41 +290,19 @@
ClassFab cf = factory.newClass(name, Object.class);
- addInfrastructure(cf, serviceInterface);
+ cf.addField("_creator", ServiceCreator.class);
+ cf.addField("_delegate", serviceInterface);
+
+ cf.addConstructor(new Class[]
+ { ServiceCreator.class }, null, "_creator = $1;");
addDelegateGetter(cf, serviceInterface);
- addServiceMethods(cf, serviceId, serviceInterface, proxyDescription);
+ cf.proxyMethodsToDelegate(serviceInterface, "_delegate()", proxyDescription);
return cf.createClass();
}
- private void addServiceMethods(ClassFab cf, String serviceId, Class serviceInterface,
- String proxyDescription)
- {
- MethodIterator mi = new MethodIterator(serviceInterface);
-
- while (mi.hasNext())
- {
- MethodSignature sig = mi.next();
-
- // Make each method in the proxy delegates to the service implementation (or outermost
- // interceptor). The "($r)" cast is magic for converting to the return type and
- // understands void methods. The "$$" is just the list of method arguments.
-
- String body = "return ($r) _delegate()." + sig.getName() + "($$);";
-
- cf.addMethod(Modifier.PUBLIC, sig, body);
- }
-
- // If toString() is not part of the service interface, then add a toString()
- // to the class. Objects visible to client code need a toString() to help
- // with debugging.
-
- if (!mi.getToString())
- ClassFabUtils.addToStringMethod(cf, proxyDescription);
- }
-
private void addDelegateGetter(ClassFab cf, Class serviceInterface)
{
BodyBuilder builder = new BodyBuilder();
@@ -345,19 +322,10 @@
MethodSignature sig = new MethodSignature(serviceInterface, "_delegate", null, null);
// Here's the rub, this _delegate() method has to be synchronized. But after the first
- // time through (when we create the service), the time inside the method is minimal.
+ // time through (when we create the service), the time inside the method is infintesmal.
// Let's hope that they aren't lying when they say that synchronized is now super cheap!
cf.addMethod(Modifier.PRIVATE | Modifier.SYNCHRONIZED, sig, builder.toString());
}
- private void addInfrastructure(ClassFab cf, Class serviceInterface)
- {
- cf.addInterface(serviceInterface);
- cf.addField("_delegate", serviceInterface);
- cf.addField("_creator", ServiceCreator.class);
-
- cf.addConstructor(new Class[]
- { ServiceCreator.class }, null, "_creator = $1;");
- }
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFabImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFabImpl.java?rev=424872&r1=424871&r2=424872&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFabImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFabImpl.java Sun Jul 23 18:12:55 2006
@@ -15,6 +15,7 @@
package org.apache.tapestry.internal.ioc.services;
import java.lang.reflect.Modifier;
+import java.util.Formatter;
import java.util.Set;
import javassist.CannotCompileException;
@@ -28,6 +29,7 @@
import org.apache.tapestry.internal.util.InternalUtils;
import org.apache.tapestry.ioc.services.ClassFab;
import org.apache.tapestry.ioc.services.ClassFabUtils;
+import org.apache.tapestry.ioc.services.MethodIterator;
import org.apache.tapestry.ioc.services.MethodSignature;
import org.apache.tapestry.util.Defense;
@@ -48,6 +50,8 @@
*/
private final StringBuffer _description = new StringBuffer();
+ private final Formatter _formatter = new Formatter(_description);
+
private final Set<MethodSignature> _addedSignatures = newSet();
public ClassFabImpl(CtClassSource source, CtClass ctClass)
@@ -140,7 +144,38 @@
}
_description
- .append(format("private %s %s;\n\n", ClassFabUtils.getJavaClassName(type), name));
+ .append(_formatter.format("private %s %s;\n\n", ClassFabUtils.getJavaClassName(type), name));
+ }
+
+ public void proxyMethodsToDelegate(Class serviceInterface, String delegateExpression, String toString)
+ {
+ addInterface(serviceInterface);
+
+ MethodIterator mi = new MethodIterator(serviceInterface);
+
+ while (mi.hasNext())
+ {
+ MethodSignature sig = mi.next();
+
+ // ($r) properly handles void methods for us, which keeps this simple.
+
+ String body = format("return ($r) %s.%s($$);", delegateExpression, sig.getName());
+
+ addMethod(Modifier.PUBLIC, sig, body);
+ }
+
+ if (!mi.getToString())
+ addToString(toString);
+ }
+
+ public void addToString(String toString)
+ {
+ MethodSignature sig = new MethodSignature(String.class, "toString", null, null);
+
+ // TODO: Very simple quoting here, will break down if the string itself contains
+ // double quotes or various other characters that need escaping.
+
+ addMethod(Modifier.PUBLIC, sig, format("return \"%s\";", toString));
}
public void addMethod(int modifiers, MethodSignature ms, String body)
@@ -172,7 +207,7 @@
// modifiers, return type, name
- _description.append(format("%s %s %s", Modifier.toString(modifiers), ClassFabUtils
+ _description.append(_formatter.format("%s %s %s", Modifier.toString(modifiers), ClassFabUtils
.getJavaClassName(ms.getReturnType()), ms.getName()));
// parameters, exceptions and body from this:
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java?rev=424872&r1=424871&r2=424872&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java Sun Jul 23 18:12:55 2006
@@ -95,9 +95,7 @@
}
if (!mi.getToString())
- ClassFabUtils.addToStringMethod(cf, ServiceMessages.loggingInterceptor(
- serviceId,
- serviceInterface));
+ cf.addToString(ServiceMessages.loggingInterceptor(serviceId, serviceInterface));
}
private void addMethod(ClassFab cf, MethodSignature signature)
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java?rev=424872&r1=424871&r2=424872&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java Sun Jul 23 18:12:55 2006
@@ -50,13 +50,12 @@
/**
* Adds the specified interface as an interface implemented by this class.
*/
- public void addInterface(Class interfaceClass);
+ void addInterface(Class interfaceClass);
/**
* Adds a new field with the given name and type. The field is added as a private field.
*/
-
- public void addField(String name, Class type);
+ void addField(String name, Class type);
/**
* Adds a method. The method is a public instance method.
@@ -72,8 +71,7 @@
* if a method with that signature has already been added, or if there is a
* Javassist compilation error
*/
-
- public void addMethod(int modifiers, MethodSignature signature, String body);
+ void addMethod(int modifiers, MethodSignature signature, String body);
/**
* Adds a constructor to the class. The constructor will be public.
@@ -85,11 +83,32 @@
* @param body
* The body of the constructor.
*/
- public void addConstructor(Class[] parameterTypes, Class[] exceptions, String body);
+ void addConstructor(Class[] parameterTypes, Class[] exceptions, String body);
+
+ /** Adds an implementation of toString, as a method that returns a fixed string. */
+ void addToString(String toString);
+
+ /**
+ * Makes the fabricated class implement the provided service interface. The interface will be
+ * added, and all methods in the interface will be delegate wrappers. If toString() is not part
+ * of the delegate interface, then an implementation will be supplied that returns the provided
+ * string. This method is used when creating objects that proxy their behavior to some other
+ * object.
+ *
+ * @param serviceInterface
+ * the interface to implement
+ * @param delegateExpression
+ * the expression used to find the delegate on which methods should be invoked.
+ * Typically a field name, such as "_delegate", or a method to invoke, such as
+ * "_service()".
+ * @param toString
+ * fixed value to be returned as the description of the resultant object
+ */
+ void proxyMethodsToDelegate(Class serviceInterface, String delegateExpression, String toString);
/**
* Invoked last to create the class. This will enforce that all abstract methods have been
* implemented in the (concrete) class.
*/
- public Class createClass();
+ Class createClass();
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java?rev=424872&r1=424871&r2=424872&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java Sun Jul 23 18:12:55 2006
@@ -15,7 +15,6 @@
package org.apache.tapestry.ioc.services;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import org.apache.tapestry.internal.annotations.Utility;
@@ -30,12 +29,6 @@
{
private static long _uid = System.currentTimeMillis();
- private static final char QUOTE = '"';
-
- private ClassFabUtils()
- {
- }
-
/**
* Generates a unique class name, which will be in the default package.
*/
@@ -85,68 +78,5 @@
return false;
return method.getReturnType().equals(String.class);
- }
-
- /**
- * Adds a <code>toString()</code> method to a class that returns a fixed, pre-computed value.
- *
- * @param classFab
- * ClassFab used to construct the new class.
- * @param toStringResult
- * fixed result to be returned by the method.
- */
- public static void addToStringMethod(ClassFab classFab, String toStringResult)
- {
- StringBuffer buffer = new StringBuffer("return ");
- buffer.append(QUOTE);
- buffer.append(toStringResult);
- buffer.append(QUOTE);
- buffer.append(";");
-
- classFab.addMethod(Modifier.PUBLIC, new MethodSignature(String.class, "toString", null,
- null), buffer.toString());
- }
-
- /**
- * Adds a method that does nothing. If the method returns a value, it will return null, 0 or
- * false (depending on the type).
- * <p>
- * TODO: Move this into ClassFab.
- */
-
- public static void addNoOpMethod(ClassFab cf, MethodSignature m)
- {
- StringBuffer body = new StringBuffer("{ ");
-
- Class returnType = m.getReturnType();
-
- if (returnType != void.class)
- {
- body.append("return");
-
- if (returnType.isPrimitive())
- {
- if (returnType == boolean.class)
- body.append(" false");
- else if (returnType == long.class)
- body.append(" 0L");
- else if (returnType == float.class)
- body.append(" 0.0f");
- else if (returnType == double.class)
- body.append(" 0.0d");
- else
- body.append(" 0");
- }
- else
- {
- body.append(" null");
- }
-
- body.append(";");
- }
-
- body.append(" }");
-
- cf.addMethod(Modifier.PUBLIC, m, body.toString());
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java?rev=424872&r1=424871&r2=424872&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java Sun Jul 23 18:12:55 2006
@@ -14,9 +14,6 @@
package org.apache.tapestry.internal.ioc.services;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
@@ -27,13 +24,16 @@
import javassist.CtClass;
import org.apache.hivemind.impl.BaseLocatable;
-import org.apache.hivemind.service.MethodFab;
import org.apache.hivemind.util.PropertyUtils;
+import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImplTest.ToStringService;
import org.apache.tapestry.ioc.services.ClassFab;
import org.apache.tapestry.ioc.services.MethodSignature;
import org.apache.tapestry.test.BaseTestCase;
import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
/**
* @author Howard M. Lewis Ship
*/
@@ -41,6 +41,20 @@
{
private final CtClassSource _source;
+ public interface SampleService
+ {
+ int primitiveMethod(int primitiveValue);
+
+ void voidMethod(String input);
+
+ String objectMethod(String input);
+ }
+
+ public interface SampleToStringService
+ {
+ String toString();
+ }
+
public ClassFabImplTest()
{
ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
@@ -88,6 +102,84 @@
String actual = (String) PropertyUtils.read(targetBean, "stringValue");
assertEquals(actual, "Fred");
+ }
+
+ @Test
+ public void add_to_string() throws Exception
+ {
+ ClassFab cf = newClassFab("ToString", Object.class);
+
+ cf.addToString("ToString Description");
+
+ Class clazz = cf.createClass();
+
+ Object instance = clazz.newInstance();
+
+ assertEquals(instance.toString(), "ToString Description");
+ }
+
+ @Test
+ public void proxy_methods_to_delegate() throws Exception
+ {
+ ClassFab cf = newClassFab("Delegator", Object.class);
+
+ cf.addField("_delegate", SampleService.class);
+ cf.addConstructor(new Class[]
+ { SampleService.class }, null, "_delegate = $1;");
+
+ cf.proxyMethodsToDelegate(SampleService.class, "_delegate", "<Delegator>");
+
+ SampleService delegate = newMock(SampleService.class);
+
+ Class clazz = cf.createClass();
+
+ SampleService proxy = (SampleService) clazz.getConstructors()[0].newInstance(delegate);
+
+ delegate.primitiveMethod(5);
+ setReturnValue(10);
+
+ delegate.voidMethod("fred");
+
+ delegate.objectMethod("barney");
+ setReturnValue("rubble");
+
+ replay();
+
+ assertEquals(proxy.primitiveMethod(5), 10);
+
+ proxy.voidMethod("fred");
+
+ assertEquals(proxy.objectMethod("barney"), "rubble");
+ assertEquals(proxy.toString(), "<Delegator>");
+
+ verify();
+ }
+
+ @Test
+ public void proxy_methods_to_delegate_with_to_string() throws Exception
+ {
+ ClassFab cf = newClassFab("ToStringDelegator", Object.class);
+
+ cf.addField("_delegate", ToStringService.class);
+ cf.addConstructor(new Class[]
+ { ToStringService.class }, null, "_delegate = $1;");
+
+ cf.proxyMethodsToDelegate(ToStringService.class, "_delegate", "<ToStringDelegator>");
+
+ ToStringService delegate = new ToStringService()
+ {
+ @Override
+ public String toString()
+ {
+ return "ACTUAL TO-STRING";
+ }
+ };
+
+ Class clazz = cf.createClass();
+
+ ToStringService proxy = (ToStringService) clazz.getConstructors()[0].newInstance(delegate);
+
+ assertEquals(proxy.toString(), "ACTUAL TO-STRING");
}
@Test