Author: mgrigorov
Date: Tue Jul 26 14:55:28 2011
New Revision: 1151124
URL: http://svn.apache.org/viewvc?rev=1151124&view=rev
Log:
WICKET-3689 @SpringBean: support 'required'
Added:
wicket/trunk/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanTest.java
Modified:
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/SpringBeanLocator.java
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/SpringBean.java
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java
Modified:
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/SpringBeanLocator.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/SpringBeanLocator.java?rev=1151124&r1=1151123&r2=1151124&view=diff
==============================================================================
---
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/SpringBeanLocator.java
(original)
+++
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/SpringBeanLocator.java
Tue Jul 26 14:55:28 2011
@@ -17,23 +17,12 @@
package org.apache.wicket.spring;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
import org.apache.wicket.proxy.IProxyTargetLocator;
import org.apache.wicket.util.lang.Objects;
import org.apache.wicket.util.lang.WicketObjects;
-import org.apache.wicket.util.string.Strings;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.config.BeanDefinition;
-import
org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.AbstractApplicationContext;
/**
* Implementation of {@link IProxyTargetLocator} that can locate beans within
a spring application
@@ -101,110 +90,6 @@ public class SpringBeanLocator implement
}
/**
- * Returns the name of the Bean as registered to Spring. Throws
IllegalState exception if none
- * or more than one beans are found.
- *
- * @param ctx
- * spring application context
- * @param clazz
- * bean class
- * @throws IllegalStateException
- * @return spring name of the bean
- */
- private final String getBeanNameOfClass(final ApplicationContext ctx,
final Class<?> clazz)
- {
- // get the list of all possible matching beans
- List<String> names = new ArrayList<String>(
-
Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(ctx, clazz)));
-
- // filter out beans that are not candidates for autowiring
- if (ctx instanceof AbstractApplicationContext)
- {
- Iterator<String> it = names.iterator();
- while (it.hasNext())
- {
- String possibility = it.next();
- BeanDefinition beanDef = getBeanDefinition(
-
((AbstractApplicationContext)ctx).getBeanFactory(), possibility);
- if
(BeanFactoryUtils.isFactoryDereference(possibility) ||
- possibility.startsWith("scopedTarget.")
|| !beanDef.isAutowireCandidate())
- {
- it.remove();
- }
- }
- }
-
- if (names.isEmpty())
- {
- throw new IllegalStateException("bean of type [" +
clazz.getName() + "] not found");
- }
- else if (names.size() > 1)
- {
- if (ctx instanceof AbstractApplicationContext)
- {
- List<String> primaries = new
ArrayList<String>();
- for (String name : names)
- {
- BeanDefinition beanDef =
getBeanDefinition(
-
((AbstractApplicationContext)ctx).getBeanFactory(), name);
- if (beanDef instanceof
AbstractBeanDefinition)
- {
- if (beanDef.isPrimary())
- {
- primaries.add(name);
- }
- }
- }
- if (primaries.size() == 1)
- {
- return primaries.get(0);
- }
- }
-
- StringBuilder msg = new StringBuilder();
- msg.append("More than one bean of type [");
- msg.append(clazz.getName());
- msg.append("] found, you have to specify the name of
the bean ");
- msg.append("(@SpringBean(name=\"foo\")) in order to
resolve this conflict. ");
- msg.append("Matched beans: ");
- msg.append(Strings.join(",", names.toArray(new
String[names.size()])));
- throw new IllegalStateException(msg.toString());
- }
- else
- {
- return names.get(0);
- }
- }
-
- /**
- *
- * @param beanFactory
- * @param name
- * @return BeanDefinition
- */
- private BeanDefinition getBeanDefinition(final
ConfigurableListableBeanFactory beanFactory,
- final String name)
- {
- if (beanFactory.containsBeanDefinition(name))
- {
- return beanFactory.getBeanDefinition(name);
- }
- else
- {
- BeanFactory parent = beanFactory.getParentBeanFactory();
- if ((parent != null) && (parent instanceof
ConfigurableListableBeanFactory))
- {
- return
getBeanDefinition((ConfigurableListableBeanFactory)parent, name);
- }
- else
- {
- return null;
- }
- }
- }
-
-
- /**
* @return returns whether the bean (the locator is supposed to
istantiate) is a singleton or
* not
*/
@@ -244,14 +129,7 @@ public class SpringBeanLocator implement
{
final ApplicationContext context = getSpringContext();
- if ((beanName != null) && (beanName.length() > 0))
- {
- return lookupSpringBean(context, beanName,
getBeanType());
- }
- else
- {
- return lookupSpringBean(context, getBeanType());
- }
+ return lookupSpringBean(context, beanName, getBeanType());
}
/**
@@ -274,10 +152,6 @@ public class SpringBeanLocator implement
*/
public final String getBeanName()
{
- if ((beanName == null) || "".equals(beanName))
- {
- beanName = getBeanNameOfClass(getSpringContext(),
getBeanType());
- }
return beanName;
}
@@ -290,23 +164,6 @@ public class SpringBeanLocator implement
}
/**
- * Looks up a bean by its class. Throws IllegalState exception if none
or more than one beans
- * are found.
- *
- * @param ctx
- * spring application context
- *
- * @param clazz
- * bean class
- * @throws IllegalStateException
- * @return found bean
- */
- private final Object lookupSpringBean(final ApplicationContext ctx,
final Class<?> clazz)
- {
- return lookupSpringBean(ctx, getBeanNameOfClass(ctx, clazz),
clazz);
- }
-
- /**
* Looks up a bean by its name and class. Throws IllegalState exception
if bean not found.
*
* @param ctx
@@ -324,7 +181,14 @@ public class SpringBeanLocator implement
{
try
{
- return ctx.getBean(name, clazz);
+ if (name == null)
+ {
+ return ctx.getBean(clazz);
+ }
+ else
+ {
+ return ctx.getBean(name, clazz);
+ }
}
catch (NoSuchBeanDefinitionException e)
{
Modified:
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java?rev=1151124&r1=1151123&r2=1151124&view=diff
==============================================================================
---
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java
(original)
+++
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java
Tue Jul 26 14:55:28 2011
@@ -21,7 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.wicket.injection.IFieldValueFactory;
import org.apache.wicket.proxy.LazyInitProxyFactory;
@@ -40,9 +40,9 @@ import org.springframework.context.suppo
/**
* {@link IFieldValueFactory} that uses {@link LazyInitProxyFactory} to create
proxies for Spring
* dependencies based on the {@link SpringBean} annotation applied to a field.
This class is usually
- * used by the {@link SpringComponentInjector} to inject objects with lazy
init proxies. However, this
- * class can be used on its own to create proxies for any field decorated with
a {@link SpringBean}
- * annotation.
+ * used by the {@link SpringComponentInjector} to inject objects with lazy
init proxies. However,
+ * this class can be used on its own to create proxies for any field decorated
with a
+ * {@link SpringBean} annotation.
* <p>
* Example:
*
@@ -72,9 +72,9 @@ public class AnnotProxyFieldValueFactory
{
private final ISpringContextLocator contextLocator;
- private final ConcurrentHashMap<SpringBeanLocator, Object> cache =
Generics.newConcurrentHashMap();
+ private final ConcurrentMap<SpringBeanLocator, Object> cache =
Generics.newConcurrentHashMap();
- private final ConcurrentHashMap<Class<?>, String> beanNameCache =
Generics.newConcurrentHashMap();
+ private final ConcurrentMap<Class<?>, String> beanNameCache =
Generics.newConcurrentHashMap();
private final boolean wrapInProxies;
@@ -109,7 +109,14 @@ public class AnnotProxyFieldValueFactory
{
if (supportsField(field))
{
- SpringBeanLocator locator = new
SpringBeanLocator(getBeanName(field), field.getType(),
+ String beanName = getBeanName(field);
+
+ if (beanName == null)
+ {
+ return null;
+ }
+
+ SpringBeanLocator locator = new
SpringBeanLocator(beanName, field.getType(),
contextLocator);
// only check the cache if the bean is a singleton
@@ -154,8 +161,12 @@ public class AnnotProxyFieldValueFactory
name = beanNameCache.get(field.getType());
if (name == null)
{
- name =
getBeanNameOfClass(contextLocator.getSpringContext(), field.getType());
- beanNameCache.put(field.getType(), name);
+ name =
getBeanNameOfClass(contextLocator.getSpringContext(), field.getType(), annot);
+
+ if (name != null)
+ {
+ beanNameCache.put(field.getType(),
name);
+ }
}
}
return name;
@@ -169,10 +180,13 @@ public class AnnotProxyFieldValueFactory
* spring application context
* @param clazz
* bean class
+ * @param annot
+ * the SpringBean annotation
* @throws IllegalStateException
* @return spring name of the bean
*/
- private final String getBeanNameOfClass(final ApplicationContext ctx,
final Class<?> clazz)
+ private final String getBeanNameOfClass(final ApplicationContext ctx,
final Class<?> clazz,
+ final SpringBean annot)
{
// get the list of all possible matching beans
List<String> names = new ArrayList<String>(
@@ -198,7 +212,11 @@ public class AnnotProxyFieldValueFactory
if (names.isEmpty())
{
- throw new IllegalStateException("bean of type [" +
clazz.getName() + "] not found");
+ if (annot.required())
+ {
+ throw new IllegalStateException("bean of type
[" + clazz.getName() + "] not found");
+ }
+ return null;
}
else if (names.size() > 1)
{
Modified:
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/SpringBean.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/SpringBean.java?rev=1151124&r1=1151123&r2=1151124&view=diff
==============================================================================
---
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/SpringBean.java
(original)
+++
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/SpringBean.java
Tue Jul 26 14:55:28 2011
@@ -28,7 +28,7 @@ import java.lang.annotation.Target;
* @author Igor Vaynberg (ivaynberg)
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({/* ElementType.METHOD, */ElementType.FIELD })
+@Target({ ElementType.FIELD })
@Documented
public @interface SpringBean {
/**
@@ -38,4 +38,12 @@ public @interface SpringBean {
* @return name attr
*/
String name() default "";
+
+
+ /**
+ * Optional attribute for specifying if bean is required or not.
+ *
+ * @return {@code false} if the bean is optional. Default: {@code true}.
+ */
+ boolean required() default true;
}
Modified:
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java?rev=1151124&r1=1151123&r2=1151124&view=diff
==============================================================================
---
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java
(original)
+++
wicket/trunk/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java
Tue Jul 26 14:55:28 2011
@@ -138,7 +138,7 @@ public class ApplicationContextMock impl
}
final T bean = beans.next();
- if (beans.hasNext() == false)
+ if (beans.hasNext() != false)
{
throw new NoSuchBeanDefinitionException("more than one
bean of required type " +
requiredType + " found");
Added:
wicket/trunk/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanTest.java?rev=1151124&view=auto
==============================================================================
---
wicket/trunk/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanTest.java
(added)
+++
wicket/trunk/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanTest.java
Tue Jul 26 14:55:28 2011
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.spring.injection.annot;
+
+import org.apache.wicket.proxy.ILazyInitProxy;
+import org.apache.wicket.spring.Bean;
+import org.apache.wicket.spring.SpringBeanLocator;
+import org.apache.wicket.spring.test.ApplicationContextMock;
+import org.apache.wicket.util.tester.DummyHomePage;
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test for SpringBean.
+ *
+ *
+ * @author Andrea Del Bene
+ */
+
+public class SpringBeanTest extends Assert
+{
+ private WicketTester tester;
+ private ApplicationContextMock ctx;
+
+ /**
+ * @throws Exception
+ */
+ @Before
+ public void before() throws Exception
+ {
+ tester = new WicketTester();
+ ctx = new ApplicationContextMock();
+
+ SpringComponentInjector springInjector = new
SpringComponentInjector(
+ tester.getApplication(), ctx);
+
+
tester.getApplication().getComponentInstantiationListeners().add(springInjector);
+ }
+
+ /**
+ * @throws Exception
+ */
+ @Test
+ public void beanExists() throws Exception
+ {
+ // add dependency bean
+ ctx.putBean("bean", new Bean());
+ AnnotatedBeanRequired page;
+
+ // first test with standard behavior (required = true)
+ tester.startPage(page = new AnnotatedBeanRequired());
+ assertNotNull(page.getBean());
+
+ // now test with required = false
+ AnnotatedBeanNotRequired notRequiredpage;
+ tester.startPage(notRequiredpage = new
AnnotatedBeanNotRequired());
+ assertNotNull(notRequiredpage.getBean());
+
+ // both page must have the same bean instance
+ assertTrue(page.getBean() == notRequiredpage.getBean());
+ }
+
+ /**
+ * @throws Exception
+ */
+ @Test
+ public void beanNotExists() throws Exception
+ {
+ // with required = true we get IllegalStateException
+ try
+ {
+ tester.startPage(new AnnotatedBeanRequired());
+ fail();
+ }
+ catch (IllegalStateException e)
+ {
+ }
+
+ // with required = false everything is fine
+ AnnotatedBeanNotRequired page;
+ tester.startPage(page = new AnnotatedBeanNotRequired());
+ assertNull(page.getBean());
+ }
+
+ /**
+ * @throws Exception
+ */
+ @Test
+ public void beanExistsDifferentName() throws Exception
+ {
+ // add dependency beans of the same type
+ ctx.putBean("mrBean", new Bean());
+ ctx.putBean("theBean", new Bean());
+
+ // with no name specified we get IllegalStateException
+ try
+ {
+ tester.startPage(new AnnotatedBeanRequired());
+ fail();
+ }
+ catch (IllegalStateException e)
+ {
+ }
+
+ // we must inject bean with name "mrBean"
+ AnnotatedBeanNotRequiredDifferentName page;
+ tester.startPage(page = new
AnnotatedBeanNotRequiredDifferentName());
+ SpringBeanLocator locator =
(SpringBeanLocator)((ILazyInitProxy)page.getBean()).getObjectLocator();
+
+ assertTrue(locator.getBeanName().equals("mrBean"));
+ }
+}
+
+class AnnotatedBeanRequired extends DummyHomePage
+{
+ @SpringBean
+ private Bean bean;
+
+ public Bean getBean()
+ {
+ return bean;
+ }
+}
+
+class AnnotatedBeanNotRequired extends DummyHomePage
+{
+ @SpringBean(required = false)
+ private Bean bean;
+
+ public Bean getBean()
+ {
+ return bean;
+ }
+}
+
+class AnnotatedBeanNotRequiredDifferentName extends DummyHomePage
+{
+ @SpringBean(required = false, name = "mrBean")
+ private Bean bean;
+
+ public Bean getBean()
+ {
+ return bean;
+ }
+}