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 2010/01/22 17:29:35 UTC
svn commit: r902145 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/internal/services/
main/java/org/apache/tapestry5/services/
test/java/org/apache/tapestry5/internal/services/
Author: hlship
Date: Fri Jan 22 16:29:34 2010
New Revision: 902145
URL: http://svn.apache.org/viewvc?rev=902145&view=rev
Log:
Add ability to inject the value of a component field from indirectly via ComponentValueProvider
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetInjectionProvider.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetInjectionProviderTest.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetInjectionProvider.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetInjectionProvider.java?rev=902145&r1=902144&r2=902145&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetInjectionProvider.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetInjectionProvider.java Fri Jan 22 16:29:34 2010
@@ -1,10 +1,10 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2010 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.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +14,10 @@
package org.apache.tapestry5.internal.services;
+import java.util.Locale;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.ioc.ObjectLocator;
import org.apache.tapestry5.ioc.Resource;
@@ -21,13 +25,13 @@
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.services.AssetSource;
import org.apache.tapestry5.services.ClassTransformation;
+import org.apache.tapestry5.services.ComponentValueProvider;
import org.apache.tapestry5.services.InjectionProvider;
-import static java.lang.String.format;
-
/**
- * Performs injection of assets, based on the presence of the {@link Path} annotation. This is more useful than the
- * general {@link AssetObjectProvider}, becase relative assets are supported.
+ * Performs injection of assets, based on the presence of the {@link Path} annotation. This is more
+ * useful than the
+ * general {@link AssetObjectProvider}, because relative assets are supported.
*/
public class AssetInjectionProvider implements InjectionProvider
{
@@ -42,28 +46,30 @@
}
public boolean provideInjection(String fieldName, Class fieldType, ObjectLocator locator,
- ClassTransformation transformation, MutableComponentModel componentModel)
+ ClassTransformation transformation, MutableComponentModel componentModel)
{
Path path = transformation.getFieldAnnotation(fieldName, Path.class);
- if (path == null) return false;
-
- String expanded = symbolSource.expandSymbols(path.value());
-
- String sourceFieldName = transformation.addInjectedField(AssetSource.class, "assetSource", assetSource);
-
- String baseResourceFieldName = transformation.addInjectedField(Resource.class, "baseResource",
- componentModel.getBaseResource());
-
- String resourcesFieldName = transformation.getResourcesFieldName();
-
- String statement = format("%s = (%s) %s.getAsset(%s, \"%s\", %s.getLocale());", fieldName, fieldType.getName(),
- sourceFieldName, baseResourceFieldName, expanded, resourcesFieldName);
+ if (path == null)
+ return false;
- transformation.extendConstructor(statement);
+ final String expanded = symbolSource.expandSymbols(path.value());
- transformation.makeReadOnly(fieldName);
+ final Resource baseResource = componentModel.getBaseResource();
+
+ ComponentValueProvider<Asset> provider = new ComponentValueProvider<Asset>()
+ {
+ @Override
+ public Asset get(ComponentResources resources)
+ {
+ Locale locale = resources.getLocale();
+
+ return assetSource.getAsset(baseResource, expanded, locale);
+ }
+ };
+ transformation.injectFieldIndirect(fieldName, provider);
+
return true;
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java?rev=902145&r1=902144&r2=902145&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalClassTransformationImpl.java Fri Jan 22 16:29:34 2010
@@ -14,9 +14,29 @@
package org.apache.tapestry5.internal.services;
-import javassist.*;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtBehavior;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtField;
+import javassist.CtMember;
+import javassist.CtMethod;
+import javassist.CtNewConstructor;
+import javassist.CtNewMethod;
+import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.FieldAccess;
+
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.internal.InternalComponentResources;
import org.apache.tapestry5.ioc.internal.services.CtClassSource;
@@ -32,14 +52,14 @@
import org.apache.tapestry5.model.ComponentModel;
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.runtime.Component;
-import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.services.ComponentMethodAdvice;
+import org.apache.tapestry5.services.ComponentValueProvider;
+import org.apache.tapestry5.services.FieldFilter;
+import org.apache.tapestry5.services.MethodFilter;
+import org.apache.tapestry5.services.TransformMethodSignature;
+import org.apache.tapestry5.services.TransformUtils;
import org.slf4j.Logger;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.Inherited;
-import java.lang.reflect.Modifier;
-import java.util.*;
-
/**
* Implementation of the {@link org.apache.tapestry5.internal.services.InternalClassTransformation}
* interface.
@@ -60,6 +80,8 @@
private final IdAllocator idAllocator;
+ private final CtClass providerType;
+
/**
* Map, keyed on InjectKey, of field name. Injections are always added as protected (not
* private) fields to support
@@ -146,6 +168,8 @@
parentTransformation = null;
this.componentModel = componentModel;
+ providerType = toCtClass(ComponentValueProvider.class);
+
idAllocator = new IdAllocator();
logger = componentModel.getLogger();
@@ -186,6 +210,8 @@
this.parentTransformation = parentTransformation;
this.componentModel = componentModel;
+ providerType = toCtClass(ComponentValueProvider.class);
+
resourcesFieldName = parentTransformation.getResourcesFieldName();
idAllocator = parentTransformation.getIdAllocator();
@@ -1261,19 +1287,15 @@
String fieldName = addField(Modifier.PRIVATE | Modifier.FINAL, type.getName(),
suggestedName);
- // TODO: This shouldn't have to be constantly recomputed
-
- CtClass providerType = toCtClass(ComponentValueProvider.class);
-
- constructorArgs.add(new ConstructorArg(providerType, provider));
+ String argName = addConstructorArg(providerType, provider);
// Inside the constructor,
// pass the resources to the provider's get() method, cast to the
// field type and assign. This will likely not work with
// primitives and arrays, but that's ok for now.
- extendConstructor(String.format(" %s = (%s) $%d.get(%s);", fieldName, type.getName(),
- constructorArgs.size(), resourcesFieldName));
+ extendConstructor(String.format(" %s = (%s) %s.get(%s);", fieldName, type.getName(),
+ argName, resourcesFieldName));
return fieldName;
}
@@ -1389,14 +1411,13 @@
*/
private void addInjectToConstructor(String fieldName, CtClass fieldType, Object value)
{
- constructorArgs.add(new ConstructorArg(fieldType, value));
-
- extendConstructor(String.format(" %s = $%d;", fieldName, constructorArgs.size()));
+ extendConstructor(String.format(" %s = %s;", fieldName,
+ addConstructorArg(fieldType, value)));
}
public void injectField(String fieldName, Object value)
{
- Defense.notNull(fieldName, "fieldName");
+ Defense.notBlank(fieldName, "fieldName");
failIfFrozen();
@@ -1407,6 +1428,26 @@
makeReadOnly(fieldName);
}
+ @Override
+ public <T> void injectFieldIndirect(String fieldName, ComponentValueProvider<T> provider)
+ {
+ Defense.notBlank(fieldName, "fieldName");
+ Defense.notNull(provider, "provider");
+
+ failIfFrozen();
+
+ CtClass type = getFieldCtType(fieldName);
+
+ String argName = addConstructorArg(providerType, provider);
+
+ extendConstructor(String.format(" %s = (%s) %s.get(%s);", fieldName, type.getName(),
+ argName, resourcesFieldName));
+
+ // Add the provider to the constructor
+
+ makeReadOnly(fieldName);
+ }
+
private CtClass convertNameToCtType(String type) throws NotFoundException
{
return classPool.get(type);
@@ -1928,4 +1969,20 @@
{
return parentTransformation == null;
}
+
+ /**
+ * Adds a new constructor argument to the transformed constructor.
+ *
+ * @param parameterType
+ * type of parameter
+ * @param value
+ * value of parameter
+ * @return psuedo-name of parameter (i.e., "$2", "$3", etc.)
+ */
+ private String addConstructorArg(CtClass parameterType, Object value)
+ {
+ constructorArgs.add(new ConstructorArg(parameterType, value));
+
+ return "$" + constructorArgs.size();
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java?rev=902145&r1=902144&r2=902145&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java Fri Jan 22 16:29:34 2010
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -249,18 +249,24 @@
* Like {@link #addInjectedField(Class, String, Object)}, but instead of specifying the value,
* a provider for the value is specified. In the generated class' constructor, the provider
* will be passed the {@link ComponentResources} and will return the final value; thus
- * each component <em>instance</em> will receive a unique
+ * each component <em>instance</em> will receive a unique
+ *
* @param <T>
- * @param type type of value to inject
- * @param suggestedName suggested name for the new field
- * @param provider injected into the component to provide the value
+ * @param type
+ * type of value to inject
+ * @param suggestedName
+ * suggested name for the new field
+ * @param provider
+ * injected into the component to provide the value
* @return the actual name of the injected field
* @since 5.2
*/
- <T> String addIndirectInjectedField(Class<T> type, String suggestedName, ComponentValueProvider<T> provider);
-
+ <T> String addIndirectInjectedField(Class<T> type, String suggestedName,
+ ComponentValueProvider<T> provider);
+
/**
- * Converts and <em>existing</em> field into a read only field whose value is the provided value. This is used
+ * Converts and <em>existing</em> field into a read only field whose value is the provided
+ * value. This is used
* when converting an
* existing field into a read-only injected value.
*
@@ -272,6 +278,22 @@
void injectField(String fieldName, Object value);
/**
+ * Like {@link #injectField(String, Object)}, except that the value to be injected is obtained
+ * from
+ * a {@link ComponentValueProvider}. It is assumed that the provider will return an object
+ * assignable to the field.
+ *
+ * @param <T>
+ * type of field
+ * @param fieldName
+ * name of field to convert
+ * @param provider
+ * provides the value to be assigned to the field
+ * @since 5.2.0
+ */
+ <T> void injectFieldIndirect(String fieldName, ComponentValueProvider<T> provider);
+
+ /**
* Transforms the class to implement the indicated interface. If the class (or its super class)
* does not already
* implement the interface, then the interface is added, and default implementations of any
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetInjectionProviderTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetInjectionProviderTest.java?rev=902145&r1=902144&r2=902145&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetInjectionProviderTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetInjectionProviderTest.java Fri Jan 22 16:29:34 2010
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2010 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.
@@ -17,7 +17,6 @@
import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.internal.test.InternalBaseTestCase;
import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.services.SymbolSource;
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.services.AssetSource;
@@ -48,51 +47,4 @@
verify();
}
-
- @Test
- public void path_annotation_present()
- {
- SymbolSource symbolSource = mockSymbolSource();
- AssetSource assetSource = mockAssetSource();
- ObjectLocator locator = mockObjectLocator();
- ClassTransformation ct = mockClassTransformation();
- MutableComponentModel model = mockMutableComponentModel();
- Path annotation = mockPath();
- Resource baseResource = mockResource();
-
- String fieldName = "myField";
- Class fieldType = Object.class;
- String value = "${foo}";
- String expanded = "foo.gif";
-
- train_getFieldAnnotation(ct, fieldName, Path.class, annotation);
-
- train_value(annotation, value);
- train_expandSymbols(symbolSource, value, expanded);
-
- train_addInjectedField(ct, AssetSource.class, "assetSource", assetSource, "as");
-
- train_getBaseResource(model, baseResource);
-
- train_addInjectedField(ct, Resource.class, "baseResource", baseResource, "br");
-
- train_getResourcesFieldName(ct, "rez");
-
- // This only tests that the code is generated as expected (which is a bit brittle), it
- // doesn't prove that the generated code actually works, but we have lots of integration
- // tests for that.
-
- ct
- .extendConstructor("myField = (java.lang.Object) as.getAsset(br, \"foo.gif\", rez.getLocale());");
-
- ct.makeReadOnly(fieldName);
-
- replay();
-
- InjectionProvider provider = new AssetInjectionProvider(symbolSource, assetSource);
-
- assertTrue(provider.provideInjection(fieldName, fieldType, locator, ct, model));
-
- verify();
- }
}