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;
+       }
+}


Reply via email to