Revision: 315
Author: tfenne
Date: 2006-05-13 07:14:09 -0700 (Sat, 13 May 2006)
ViewCVS: http://svn.sourceforge.net/stripes/?rev=315&view=rev
Log Message:
-----------
Major refactoring of the SpringHelper injection functionality, and the addition
of tests for it.
Modified Paths:
--------------
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringBean.java
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringHelper.java
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringInterceptor.java
trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java
trunk/stripes/stripes.iml
trunk/tests/build.xml
trunk/tests/tests.iml
Added Paths:
-----------
trunk/stripes/lib/test/spring.jar
trunk/tests/lib/testng-4.6-jdk15.jar
trunk/tests/src/net/sourceforge/stripes/integration/
trunk/tests/src/net/sourceforge/stripes/integration/spring/
trunk/tests/src/net/sourceforge/stripes/integration/spring/SpringHelperTests.java
Removed Paths:
-------------
trunk/stripes/lib/build/spring.jar
trunk/tests/lib/testng-4.4.7-jdk15.jar
Deleted: trunk/stripes/lib/build/spring.jar
===================================================================
(Binary files differ)
Copied: trunk/stripes/lib/test/spring.jar (from rev 294,
trunk/stripes/lib/build/spring.jar)
===================================================================
(Binary files differ)
Modified:
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringBean.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringBean.java
2006-05-13 02:11:11 UTC (rev 314)
+++
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringBean.java
2006-05-13 14:14:09 UTC (rev 315)
@@ -21,15 +21,24 @@
import java.lang.annotation.Documented;
/**
- * <p>Annotation used for injecting Spring managed beans into an ActionBean.
The value
- * represents the name of the bean in the Spring application context to
inject. Please
- * see the SpringDispatcherServlet for strategies used in the event the bean
was not
- * found in the application context.</p>
+ * <p>Annotation used for injecting Spring managed beans into objects within
Stripes
+ * (usually ActionBeans). The value of the annotation represents the name of
the bean
+ * in the Spring application context to inject. If the value is omitted then
Stripes
+ * will attempt to auto-wire first by property/field name and then by type.</p>
*
+ * <p>Both methods and fields can be annotated. If a field is annotated
Stripes will use
+ * field access to attempt to inject the bean into the field. If a method is
annotated Stripes
+ * will attempt to invoke the method and supply it the value to inject. In
both cases
+ * non-public fields/methods are supported (i.e. values can be injected into
private fields
+ * and through private methods).</p>
+ *
+ * <p>For a more details description of the injection process and how
auto-wiring occurs
+ * when explicit bean names are omitted see the [EMAIL PROTECTED]
SpringHelper} class.</p>
+ *
* @author Dan Hayes
*/
@Retention(RetentionPolicy.RUNTIME)
[EMAIL PROTECTED](ElementType.METHOD)
[EMAIL PROTECTED]({ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface SpringBean {
String value() default "";
Modified:
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringHelper.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringHelper.java
2006-05-13 02:11:11 UTC (rev 314)
+++
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringHelper.java
2006-05-13 14:14:09 UTC (rev 315)
@@ -15,102 +15,292 @@
package net.sourceforge.stripes.integration.spring;
import net.sourceforge.stripes.action.ActionBeanContext;
-import net.sourceforge.stripes.exception.StripesServletException;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
import net.sourceforge.stripes.util.Log;
-import org.springframework.beans.BeanUtils;
+import net.sourceforge.stripes.util.ReflectUtil;
import org.springframework.context.ApplicationContext;
+import org.springframework.core.NestedRuntimeException;
import org.springframework.web.context.support.WebApplicationContextUtils;
-import javax.servlet.http.HttpServletRequest;
-import java.beans.PropertyDescriptor;
+import javax.servlet.ServletContext;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* <p>Static helper class that is used to lookup Spring beans and inject them
into objects
- * (usually ActionBeans). Setter methods must be annotated using the [EMAIL
PROTECTED] @SpringBean annotation}.
- * The value of the annotation should be the bean name in the Spring
application context. If value
- * is left blank, an attempt is made to auto-wire the bean; first by method
name then by type. If
- * the value is left blank and more than one bean of the same type is found,
an exception will be
- * raised.</p>
+ * (often ActionBeans). Is capable of injecting beans through setter methods
(property access)
+ * and also through direct field access if the security policy allows it.
Methods and fields
+ * must be annotated using the [EMAIL PROTECTED] @SpringBean} annotation.</p>
*
+ * <p>Methods and fields may be public, protected, package-access or private.
If they are not
+ * public an attempt is made to call [EMAIL PROTECTED]
Method#setAccessible(boolean)} in order to make
+ * them accessible from this class. If the attempt fails, an exception will
be thrown.</p>
+ *
+ * <p>Method names can take any form. For example [EMAIL PROTECTED]
setSomeBean(Bean b)} or
+ * [EMAIL PROTECTED] someBean(bean b)}. In both cases, if a specific
SpringBean name is not supplied,
+ * the default name of [EMAIL PROTECTED] someBean} will be used.</p>
+ *
+ * <p>The value of the [EMAIL PROTECTED] @SpringBean} annotation should be the
bean name in the Spring
+ * application context if it is different from the field/property name. If
the value
+ * is left blank, an attempt is made to auto-wire the bean; first by
field/property name and
+ * then by type. If the value is left blank and more than one bean of the same
type is found,
+ * an exception will be raised.</p>
+ *
+ * <p>The first time that any of the injection methods in this class is called
with a specific type
+ * of object, the object's class is examined for annotated fields and methods.
The discovered
+ * fields and methods are then cached for future usage.</p>
+ *
* @see SpringBean
* @author Dan Hayes, Tim Fennell
*/
public class SpringHelper {
private static Log log = Log.getInstance(SpringHelper.class);
+ /** Lazily filled in map of Class to methods annotated with SpringBean. */
+ private static Map<Class<?>, Collection<Method>> methodMap =
+ new ConcurrentHashMap<Class<?>, Collection<Method>>();
+
+ /** Lazily filled in map of Class to fields annotated with SpringBean. */
+ private static Map<Class<?>, Collection<Field>> fieldMap =
+ new ConcurrentHashMap<Class<?>, Collection<Field>>();
+
/**
- * Injects Spring managed beans into ActionBeans via the SpringBean
annotation.
- * It first looks for the value attribute of the annotation for the name
of the
- * Spring managed bean to inject. If this is empty, it will attempt to
"auto-wire"
- * the bean from the method name (i.e. "setSomeBean()" will resolve to
"someBean").
- * Finally, it will try to look for a bean of the type expected by the
method. In
- * the event that more than one Spring managed bean meets this criteria,
an exception
- * will be logged and thrown.
+ * Injects Spring managed beans into using a Web Application Context that
is
+ * derived from the ServletContext, which is in turn looked up using the
+ * ActionBeanContext.
*
* @param bean the object into which to inject spring managed bean
* @param context the ActionBeanContext represented by the current request
- * @throws Exception
*/
- public static void injectBeans(Object bean, ActionBeanContext context)
throws Exception {
- HttpServletRequest request = context.getRequest();
- ApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(
- request.getSession().getServletContext());
+ public static void injectBeans(Object bean, ActionBeanContext context) {
+ injectBeans(bean,
context.getRequest().getSession().getServletContext());
+ }
- for (Method m : bean.getClass().getMethods()) {
+ /**
+ * Injects Spring managed beans using a Web Application Context derived
from
+ * the ServletContext.
+ *
+ * @param bean the object to have beans injected into
+ * @param ctx the ServletContext to use to find the Spring
ApplicationContext
+ */
+ public static void injectBeans(Object bean, ServletContext ctx) {
+ ApplicationContext ac =
WebApplicationContextUtils.getWebApplicationContext(ctx);
+ injectBeans(bean, ac);
+ }
- if (m.isAnnotationPresent(SpringBean.class)) {
+ /**
+ * Looks for all methods and fields annotated with [EMAIL PROTECTED]
@SpringBean} and attempts
+ * to lookup and inject a managed bean into the field/property. If any
annotated
+ * element cannot be injected an exception is thrown.
+ *
+ * @param bean the bean into which to inject spring beans
+ * @param ctx the Spring application context
+ */
+ public static void injectBeans(Object bean, ApplicationContext ctx) {
+ // First inject any values using annotated methods
+ for (Method m : getMethods(bean.getClass())) {
+ try {
+ SpringBean springBean = m.getAnnotation(SpringBean.class);
+ boolean nameSupplied = !"".equals(springBean.value());
+ String name = nameSupplied ? springBean.value() :
methodToPropertyName(m);
+ Class<?> beanType = m.getParameterTypes()[0];
+ Object managedBean = findSpringBean(ctx, name, beanType,
!nameSupplied);
+ m.invoke(bean, managedBean);
+ }
+ catch (Exception e) {
+ throw new StripesRuntimeException("Exception while trying to
lookup and inject " +
+ "a Spring bean into a bean of type " +
bean.getClass().getSimpleName() +
+ " using method " + m.toString(), e);
+ }
+ }
- String beanName = m.getAnnotation(SpringBean.class).value();
- if (beanName != null && !beanName.equals("")) {
- // use the value to lookup the bean
- m.invoke(bean, springContext.getBean(beanName));
- log.debug("Injected ActionBean [",
bean.getClass().getName(), "] property [",
- m.getName(), "] with Spring bean [", beanName,
"].");
+ // And then inject any properties that are annotated
+ for (Field f : getFields(bean.getClass())) {
+ try {
+ SpringBean springBean = f.getAnnotation(SpringBean.class);
+ boolean nameSupplied = !"".equals(springBean.value());
+ String name = nameSupplied ? springBean.value() : f.getName();
+ Object managedBean = findSpringBean(ctx, name, f.getType(),
!nameSupplied);
+ f.set(bean, managedBean);
+ }
+ catch (Exception e) {
+ throw new StripesRuntimeException("Exception while trying to
lookup and inject " +
+ "a Spring bean into a bean of type " +
bean.getClass().getSimpleName() +
+ " using field access on field " + f.toString(), e);
+ }
+ }
+ }
+
+ /**
+ * Fetches the methods on a class that are annotated with SpringBean. The
first time it
+ * is called for a particular class it will introspect the class and cache
the results.
+ * All non-overridden methods are examined, including protected and
private methods.
+ * If a method is not public an attempt it made to make it accessible - if
it fails
+ * it is removed from the collection and an error is logged.
+ *
+ * @param clazz the class on which to look for SpringBean annotated methods
+ * @return the collection of methods with the annotation
+ */
+ protected static Collection<Method> getMethods(Class<?> clazz) {
+ Collection<Method> methods = methodMap.get(clazz);
+ if (methods == null) {
+ methods = ReflectUtil.getMethods(clazz);
+ Iterator<Method> iterator = methods.iterator();
+
+ while (iterator.hasNext()) {
+ Method method = iterator.next();
+ if (!method.isAnnotationPresent(SpringBean.class)) {
+ iterator.remove();
}
else {
- // else, try to auto-wire by property name
- PropertyDescriptor pd = BeanUtils.findPropertyForMethod(m);
- if ( springContext.containsBean(pd.getName()) ) {
- m.invoke( bean, springContext.getBean(pd.getName()) );
- log.debug("Injected ActionBean [",
bean.getClass().getName(),
- "] property [", pd.getName(), "] with
Spring bean [",
- pd.getName(), "]");
- }
- else {
- // or try to find by type
- String[] beanNames =
springContext.getBeanNamesForType(pd.getPropertyType());
- if (beanNames == null || beanNames.length == 0) {
- // didn't find any beans of that type
- StripesServletException sse = new
StripesServletException(
- "Unable to inject ActionBean [" +
bean.getClass().getName() +
- "] property [" + pd.getName() + "]. No
matching Spring beans " +
- "could be found with the name [" +
pd.getName() + "] or type [" +
- pd.getPropertyType().getName() + "].");
- log.error(sse);
- throw sse;
+ // If the method isn't public, try to make it accessible
+ if (!method.isAccessible()) {
+ try {
+ method.setAccessible(true);
}
- else if (beanNames.length > 1) {
- // more than one bean found of this type
- StripesServletException sse = new
StripesServletException(
- "Unable to inject ActionBean [" +
bean.getClass().getName() +
- "] property [" + pd.getName() + "]. No
matching Spring beans " +
- "could be found with the name [" +
pd.getName() + "]. " +
- beanNames.length + " found with type [" +
- pd.getPropertyType().getName() + "].");
- log.error(sse);
- throw sse;
+ catch (SecurityException se) {
+ throw new StripesRuntimeException(
+ "Method " + clazz.getName() + "." +
method.getName() + "is marked " +
+ "with @SpringBean and is not public. An
attempt to call " +
+ "setAccessible(true) resulted in a
SecurityException. Please " +
+ "either make the method public or modify your
JVM security " +
+ "policy to allow Stripes to
setAccessible(true).", se);
}
- else {
- m.invoke(bean,
springContext.getBean(beanNames[0]));
- log.warn("Injecting ActionBean [",
bean.getClass().getName(),
- "] property [", pd.getName(),"] with
Spring bean name [",
- beanNames[0], "] based upon type match.
Matching on type is ",
- "a little risky so watch out!");
- }
}
+
+ // Ensure the method has only the one parameter
+ if (method.getParameterTypes().length != 1) {
+ throw new StripesRuntimeException(
+ "A method marked with @SpringBean must have
exactly one parameter: " +
+ "the bean to be injected. Method [" +
method.toGenericString() + "] has " +
+ method.getParameterTypes().length + " parameters."
+ );
+ }
}
}
+
+ methodMap.put(clazz, methods);
}
+
+ return methods;
}
+
+ /**
+ * Fetches the fields on a class that are annotated with SpringBean. The
first time it
+ * is called for a particular class it will introspect the class and cache
the results.
+ * All non-overridden fields are examined, including protected and private
fields.
+ * If a field is not public an attempt it made to make it accessible - if
it fails
+ * it is removed from the collection and an error is logged.
+ *
+ * @param clazz the class on which to look for SpringBean annotated fields
+ * @return the collection of methods with the annotation
+ */
+ protected static Collection<Field> getFields(Class<?> clazz) {
+ Collection<Field> fields = fieldMap.get(clazz);
+ if (fields == null) {
+ fields = ReflectUtil.getFields(clazz);
+ Iterator<Field> iterator = fields.iterator();
+
+ while (iterator.hasNext()) {
+ Field field = iterator.next();
+ if (!field.isAnnotationPresent(SpringBean.class)) {
+ iterator.remove();
+ }
+ else if (!field.isAccessible()) {
+ // If the field isn't public, try to make it accessible
+ try {
+ field.setAccessible(true);
+ }
+ catch (SecurityException se) {
+ throw new StripesRuntimeException(
+ "Field " + clazz.getName() + "." + field.getName()
+ "is marked " +
+ "with @SpringBean and is not public. An attempt to
call " +
+ "setAccessible(true) resulted in a
SecurityException. Please " +
+ "either make the field public, annotate a public
setter instead " +
+ "or modify your JVM security policy to allow
Stripes to " +
+ "setAccessible(true).", se);
+ }
+ }
+ }
+
+ fieldMap.put(clazz, fields);
+ }
+
+ return fields;
+ }
+
+ /**
+ * Looks up a Spring managed bean from an Application Context. First looks
for a bean
+ * with name specified. If no such bean exists, looks for a bean by type.
If there is
+ * only one bean of the appropriate type, it is returned. If zero or more
than one bean
+ * of the correct type exists, an exception is thrown.
+ *
+ * @param ctx the Spring Application Context
+ * @param name the name of the spring bean to look for
+ * @param type the type of bean to look for
+ * @param allowFindByType true to indicate that finding a bean by type is
acceptable
+ * if find by name fails.
+ * @exception RuntimeException various subclasses of RuntimeException are
thrown if it
+ * is not possible to find a unique matching bean in the spring
context given
+ * the constraints supplied.
+ */
+ protected static Object findSpringBean(ApplicationContext ctx,
+ String name,
+ Class<?> type,
+ boolean allowFindByType) {
+ // First try to lookup using the name provided
+ try {
+ Object bean = ctx.getBean(name, type);
+ log.debug("Found spring bean with name [", name, "] and type [",
+ bean.getClass().getName(), "]");
+ return bean;
+ }
+ catch (NestedRuntimeException nre) {
+ if (!allowFindByType) throw nre;
+ }
+
+ // If we got here then we didn't find a bean yet, try by type
+ String[] beanNames = ctx.getBeanNamesForType(type);
+ if (beanNames.length == 0) {
+ throw new StripesRuntimeException(
+ "Unable to find SpringBean with name [" + name + "] or type ["
+
+ type.getName() + "] in the Spring application context.");
+ }
+ else if (beanNames.length > 1) {
+ throw new StripesRuntimeException(
+ "Unable to find SpringBean with name [" + name + "] or unique
bean with type [" +
+ type.getName() + "] in the Spring application context. Found "
+ beanNames.length +
+ "beans of matching type.");
+ }
+ else {
+ log.warn("Found unique SpringBean with type [" + type.getName() +
"]. Matching on ",
+ "type is a little risky so watch out!");
+ return ctx.getBean(beanNames[0], type);
+ }
+ }
+
+ /**
+ * A slightly unusual, and somewhat "loose" conversion of a method name to
a property
+ * name. Assumes that the name is in fact a mutator for a property and
will do the
+ * usual [EMAIL PROTECTED] setFoo} to [EMAIL PROTECTED] foo} conversion if
the method follows the normal
+ * syntax, otherwise will just return the method name.
+ *
+ * @param m the method to determine the property name of
+ * @return a String property name
+ */
+ protected static String methodToPropertyName(Method m) {
+ String name = m.getName();
+ if (name.startsWith("set") && name.length() > 3) {
+ String ret = name.substring(3,4).toLowerCase();
+ if (name.length() > 4) ret += name.substring(4);
+ return ret;
+ }
+ else {
+ return name;
+ }
+ }
}
Modified:
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringInterceptor.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringInterceptor.java
2006-05-13 02:11:11 UTC (rev 314)
+++
trunk/stripes/src/net/sourceforge/stripes/integration/spring/SpringInterceptor.java
2006-05-13 14:14:09 UTC (rev 315)
@@ -24,10 +24,9 @@
/**
* <p>An [EMAIL PROTECTED] Interceptor} that uses a Spring context to inject
Spring beans into newly created
- * ActionBeans immediatley following ActionBeanResolution. For more
information on how the injection
+ * ActionBeans immediateley following ActionBeanResolution. For more
information on how the injection
* is performed see [EMAIL PROTECTED] SpringHelper#injectBeans(Object,
- * net.sourceforge.stripes.action.ActionBeanContext)}</p>
- * them back for processing.</p>
+ * net.sourceforge.stripes.action.ActionBeanContext)}.</p>
*
* <p>To configure the SpringInterceptor for use you will need to add the
following to your
* web.xml (assuming no other interceptors are yet configured):</p>
@@ -35,7 +34,10 @@
* <pre>
* <init-param>
* <param-name>Interceptor.Classes</param-name>
- *
<param-value>net.sourceforge.stripes.integration.spring.SpringInterceptor</param-value>
+ * <param-value>
+ * net.sourceforge.stripes.integration.spring.SpringInterceptor,
+ * net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor
+ * </param-value>
* </init-param>
* </pre>
*
Modified: trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java
2006-05-13 02:11:11 UTC (rev 314)
+++ trunk/stripes/src/net/sourceforge/stripes/util/ReflectUtil.java
2006-05-13 14:14:09 UTC (rev 315)
@@ -30,6 +30,7 @@
import java.util.Arrays;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
+import java.lang.reflect.Field;
/**
* Common utilty methods that are useful when working with reflection.
@@ -224,4 +225,27 @@
return found;
}
+
+ /**
+ * Fetches all fields of all access types from the supplied class and super
+ * classes. Fieldss that have been overridden in the inheritance hierachy
are
+ * only returned once, using the instance lowest down the hierarchy.
+ *
+ * @param clazz the class to inspect
+ * @return a collection of fields
+ */
+ public static Collection<Field> getFields(Class<?> clazz) {
+ Map<String,Field> fields = new HashMap<String, Field>();
+ while (clazz != null) {
+ for (Field field : clazz.getDeclaredFields()) {
+ if ( !fields.containsKey(field.getName()) ) {
+ fields.put(field.getName(), field);
+ }
+ }
+
+ clazz = clazz.getSuperclass();
+ }
+
+ return fields.values();
+ }
}
Modified: trunk/stripes/stripes.iml
===================================================================
--- trunk/stripes/stripes.iml 2006-05-13 02:11:11 UTC (rev 314)
+++ trunk/stripes/stripes.iml 2006-05-13 14:14:09 UTC (rev 315)
@@ -5,6 +5,7 @@
<output url="file://$MODULE_DIR$/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
@@ -15,7 +16,9 @@
<root url="jar://$MODULE_DIR$/lib/deploy/ognl-2.6.7.jar!/" />
</CLASSES>
<JAVADOC />
- <SOURCES />
+ <SOURCES>
+ <root url="file:///Downloads/ognl-2.6.7-dist Folder/java" />
+ </SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library" exported="">
@@ -67,24 +70,33 @@
<SOURCES />
</library>
</orderEntry>
- <orderEntry type="module-library">
+ <orderEntry type="module-library" exported="">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/lib/build/spring.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/build/mail.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
- <orderEntry type="module-library">
+ <orderEntry type="module-library" exported="">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/lib/build/mail.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/build/freemarker.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
+ <orderEntry type="module-library" exported="">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/test/spring.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
<orderEntryProperties />
<javadoc-paths>
<root url="file://$MODULE_DIR$/docs" />
Modified: trunk/tests/build.xml
===================================================================
--- trunk/tests/build.xml 2006-05-13 02:11:11 UTC (rev 314)
+++ trunk/tests/build.xml 2006-05-13 14:14:09 UTC (rev 315)
@@ -101,7 +101,7 @@
<testng classpathref="class.path" outputdir="${test.out.dir}">
<classfileset dir="${classes.dir}">
- <include name="**/*Test.class"/>
+ <include name="**/*.class"/>
</classfileset>
</testng>
</target>
Deleted: trunk/tests/lib/testng-4.4.7-jdk15.jar
===================================================================
(Binary files differ)
Added: trunk/tests/lib/testng-4.6-jdk15.jar
===================================================================
(Binary files differ)
Property changes on: trunk/tests/lib/testng-4.6-jdk15.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added:
trunk/tests/src/net/sourceforge/stripes/integration/spring/SpringHelperTests.java
===================================================================
---
trunk/tests/src/net/sourceforge/stripes/integration/spring/SpringHelperTests.java
(rev 0)
+++
trunk/tests/src/net/sourceforge/stripes/integration/spring/SpringHelperTests.java
2006-05-13 14:14:09 UTC (rev 315)
@@ -0,0 +1,262 @@
+package net.sourceforge.stripes.integration.spring;
+
+import net.sourceforge.stripes.test.TestBean;
+import net.sourceforge.stripes.test.TestActionBean;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
+import org.springframework.context.support.StaticApplicationContext;
+import org.testng.annotations.Configuration;
+import org.testng.annotations.Test;
+import org.testng.annotations.ExpectedExceptions;
+import org.testng.Assert;
+
+/**
+ * Unit tests for the SpringHelper class that injects spring managed beans
+ * into objects.
+ *
+ * @author Tim Fennell
+ */
+public class SpringHelperTests {
+ StaticApplicationContext ctx;
+
+ @Configuration(beforeTestClass=true)
+ protected void setupSpringContext() {
+ ctx = new StaticApplicationContext();
+ ctx.registerSingleton("test/TestBean", TestBean.class);
+ ctx.registerSingleton("testActionBean", TestActionBean.class);
+ ctx.registerPrototype("test/testActionBean", TestActionBean.class);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ExplicitPublicSetterTarget {
+ private TestBean bean;
+ @SpringBean("test/TestBean")
+ public void setBean(TestBean bean) { this.bean = bean; }
+ public TestBean getBean() { return bean; }
+ }
+
+ @Test(groups="fast")
+ public void testExplicitSetterInjection() {
+ ExplicitPublicSetterTarget target = new ExplicitPublicSetterTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ExplicitPrivateSetterTarget {
+ private TestBean bean;
+ @SpringBean("test/TestBean")
+ private void setBean(TestBean bean) { this.bean = bean; }
+ TestBean getBean() { return bean; }
+ }
+
+ @Test(groups="fast")
+ public void testPrivateSetterInjection() {
+ ExplicitPrivateSetterTarget target = new ExplicitPrivateSetterTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ExplicitPrivateFieldTarget {
+ @SpringBean("test/TestBean") private TestBean bean;
+ TestBean getBean() { return bean; }
+ }
+
+ @Test(groups="fast")
+ public void testPrivateFieldInjection() {
+ ExplicitPrivateFieldTarget target = new ExplicitPrivateFieldTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ExplicitNonStandardSetterTarget {
+ private TestBean bean;
+ @SpringBean("test/TestBean")
+ protected void injectHere(TestBean bean) { this.bean = bean; }
+ TestBean getBean() { return bean; }
+ }
+
+ @Test(groups="fast")
+ public void testExplicitNonStandardSetterInjection() {
+ ExplicitNonStandardSetterTarget target = new
ExplicitNonStandardSetterTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ImplicitNonStandardSetterTarget {
+ private TestActionBean bean;
+ @SpringBean protected void testActionBean(TestActionBean bean) {
this.bean = bean; }
+ TestActionBean getBean() { return bean; }
+ }
+
+ @Test(groups="fast")
+ public void testImplicitNonStandardSetterInjection() {
+ ImplicitNonStandardSetterTarget target = new
ImplicitNonStandardSetterTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ImplicitStandardSetterTarget {
+ private TestActionBean bean;
+ @SpringBean protected void setTestActionBean(TestActionBean bean) {
this.bean = bean; }
+ TestActionBean getBean() { return bean; }
+ }
+
+ @Test(groups="fast")
+ public void testImplicitStandardSetterInjection() {
+ ImplicitStandardSetterTarget target = new
ImplicitStandardSetterTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ImplicitFieldTarget {
+ @SpringBean private TestActionBean testActionBean;
+ TestActionBean getBean() { return testActionBean; }
+ }
+
+ @Test(groups="fast")
+ public void testImplicitFieldInjection() {
+ ImplicitFieldTarget target = new ImplicitFieldTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ByTypeTarget {
+ @SpringBean private TestBean someBeanOrOther;
+ TestBean getBean() { return someBeanOrOther; }
+ }
+
+ @Test(groups="fast")
+ public void testByTypeInjection() {
+ ByTypeTarget target = new ByTypeTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.getBean());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class MultipleInjectionTarget {
+ @SpringBean TestBean someBeanOrOther; // by type
+ @SpringBean TestActionBean testActionBean; // by field name
+ TestActionBean number3; // explicit private method
+ TestActionBean number4; // explicit public method
+
+ @SpringBean("test/testActionBean")
+ private void setNumber3(TestActionBean value) { this.number3 = value; }
+
+ @SpringBean("testActionBean")
+ public void whee(TestActionBean value) { this.number4 = value; }
+ }
+
+ @Test(groups="fast")
+ public void testMultipleInjection() {
+ MultipleInjectionTarget target = new MultipleInjectionTarget();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.someBeanOrOther);
+ Assert.assertNotNull(target.testActionBean);
+ Assert.assertNotNull(target.number3);
+ Assert.assertNotNull(target.number4);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class AmbiguousByTypeTarget {
+ @SpringBean TestActionBean someBeanOrOther;
+ }
+
+ @Test(groups="fast") @ExpectedExceptions(StripesRuntimeException.class)
+ public void testAmbiguousByTypeInjection() {
+ AmbiguousByTypeTarget target = new AmbiguousByTypeTarget();
+ SpringHelper.injectBeans(target, ctx);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ExplicitMisNamedTarget {
+ @SpringBean("nonExistentBean") TestActionBean someBeanOrOther;
+ }
+
+ @Test(groups="fast") @ExpectedExceptions(StripesRuntimeException.class)
+ public void testExplicitMisNamedTargetInjection() {
+ ExplicitMisNamedTarget target = new ExplicitMisNamedTarget();
+ SpringHelper.injectBeans(target, ctx);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class ImplicitMisNamedTarget {
+ @SpringBean TestActionBean tstActionBea;
+ }
+
+ @Test(groups="fast") @ExpectedExceptions(StripesRuntimeException.class)
+ public void testImplicitMisNamedTargetInjection() {
+ ImplicitMisNamedTarget target = new ImplicitMisNamedTarget();
+ SpringHelper.injectBeans(target, ctx);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class NoBeanOfTypeTarget {
+ @SpringBean SpringHelperTests noBeansOfType;
+ }
+
+ @Test(groups="fast") @ExpectedExceptions(StripesRuntimeException.class)
+ public void testNoBeansOfTargetTypeInjection() {
+ NoBeanOfTypeTarget target = new NoBeanOfTypeTarget();
+ SpringHelper.injectBeans(target, ctx);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class InvalidSetterSignatureTarget {
+ TestActionBean testActionBean;
+ @SpringBean
+ public void setTestActionBean(TestActionBean bean, TestActionBean
other) {
+ this.testActionBean = bean;
+ }
+ }
+
+ @Test(groups="fast") @ExpectedExceptions(StripesRuntimeException.class)
+ public void testInvalidSetterSignatureInjection() {
+ InvalidSetterSignatureTarget target = new
InvalidSetterSignatureTarget();
+ SpringHelper.injectBeans(target, ctx);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class MultipleInjectionTarget2 {
+ @SpringBean TestBean someBeanOrOther; // by type
+ @SpringBean TestActionBean testActionBean; // by field name
+ TestActionBean number3; // explicit private method
+ TestActionBean number4; // explicit public method
+
+ @SpringBean("test/testActionBean")
+ private void setNumber3(TestActionBean value) { this.number3 = value; }
+
+ @SpringBean("testActionBean")
+ public void whee(TestActionBean value) { this.number4 = value; }
+ }
+
+ @Test(groups="slow", threadPoolSize=10, invocationCount=1000)
+ public void testConcurrentInjection() {
+ MultipleInjectionTarget2 target = new MultipleInjectionTarget2();
+ SpringHelper.injectBeans(target, ctx);
+ Assert.assertNotNull(target.someBeanOrOther);
+ Assert.assertNotNull(target.testActionBean);
+ Assert.assertNotNull(target.number3);
+ Assert.assertNotNull(target.number4);
+ }
+}
\ No newline at end of file
Modified: trunk/tests/tests.iml
===================================================================
--- trunk/tests/tests.iml 2006-05-13 02:11:11 UTC (rev 314)
+++ trunk/tests/tests.iml 2006-05-13 14:14:09 UTC (rev 315)
@@ -10,14 +10,12 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="stripes" exported="" />
- <orderEntry type="module-library">
+ <orderEntry type="module-library" exported="">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/lib/testng-4.4.7-jdk15.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/testng-4.6-jdk15.jar!/" />
</CLASSES>
- <JAVADOC>
- <root url="http://testng.org/javadocs/index.html/" />
- </JAVADOC>
+ <JAVADOC />
<SOURCES />
</library>
</orderEntry>
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development