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();
- }
}