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 2011/10/18 02:51:34 UTC

svn commit: r1185442 - in /tapestry/tapestry5/trunk/tapestry-ioc/src: main/java/org/apache/tapestry5/ioc/annotations/ main/java/org/apache/tapestry5/ioc/def/ main/java/org/apache/tapestry5/ioc/internal/ main/java/org/apache/tapestry5/ioc/internal/util/...

Author: hlship
Date: Tue Oct 18 00:51:33 2011
New Revision: 1185442

URL: http://svn.apache.org/viewvc?rev=1185442&view=rev
Log:
TAP5-955: Add @Optional annotation to mark contribution methods that can be ignored if the indicated service does not exist

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Optional.java
      - copied, changed from r1185435, tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef3.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/OptionalContributionModule.java
Modified:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef2.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ContributionDefImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ContributionDefImplTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ValidatingMappedConfigurationWrapperTest.java

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java Tue Oct 18 00:51:33 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2011 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.
@@ -13,20 +13,20 @@
 // limitations under the License.
 package org.apache.tapestry5.ioc.annotations;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
  * An annotation that may be placed on a contributor method of a module. The annotation may/should be used in combination with
- * {@link Marker} annotation to disambiguate the service to contribute into. This annotation was introduced as an alternative 
+ * {@link Marker} annotation to disambiguate the service to contribute into. This annotation was introduced as an alternative
  * to the naming convention for contributor methods.
- * 
- * @since 5.2.0
  *
+ * @see Optional
+ * @since 5.2.0
  */
 @Target(METHOD)
 @Retention(RUNTIME)

Copied: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Optional.java (from r1185435, tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Optional.java?p2=tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Optional.java&p1=tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java&r1=1185435&r2=1185442&rev=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Contribute.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Optional.java Tue Oct 18 00:51:33 2011
@@ -1,40 +1,37 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2011 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,
 // 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.tapestry5.ioc.annotations;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+package org.apache.tapestry5.ioc.annotations;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
- * An annotation that may be placed on a contributor method of a module. The annotation may/should be used in combination with
- * {@link Marker} annotation to disambiguate the service to contribute into. This annotation was introduced as an alternative 
- * to the naming convention for contributor methods.
- * 
- * @since 5.2.0
+ * Marks a service contribution method within a module as being optional: it is not an error if the contribution does not match against an actual service. In that case, the
+ * method will simply never be invoked.
  *
+ * @see Contribute
+ * @since 5.3
  */
 @Target(METHOD)
 @Retention(RUNTIME)
 @Documented
-public @interface Contribute
+@UseWith(AnnotationUseContext.MODULE)
+public @interface Optional
 {
-    /**
-     * Type of the service to contribute into.
-     */
-    Class value();
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef2.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef2.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef2.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef2.java Tue Oct 18 00:51:33 2011
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2011 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.
@@ -11,6 +11,7 @@
 // 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.tapestry5.ioc.def;
 
 import org.apache.tapestry5.ioc.Markable;
@@ -22,10 +23,10 @@ import org.apache.tapestry5.ioc.annotati
  * identifies the service contributed either by the service id or by a combination of {@link Contribute} annotation and
  * a set of marker annotations. This means that {@link #getServiceId()} may to return <code>null</code> if
  * {@link #getServiceInterface()} returns a non <code>null</code> value.
- * 
+ *
  * @since 5.2.0
  */
 public interface ContributionDef2 extends ContributionDef, Markable
 {
-	
+
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef3.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef3.java?rev=1185442&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef3.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ContributionDef3.java Tue Oct 18 00:51:33 2011
@@ -0,0 +1,26 @@
+// Copyright 2011 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
+//
+// 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.tapestry5.ioc.def;
+
+
+/**
+ * Starting in Tapestry 5.3, contributions could be optional.
+ *
+ * @since 5.3
+ */
+public interface ContributionDef3 extends ContributionDef2
+{
+    boolean isOptional();
+}

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ContributionDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ContributionDefImpl.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ContributionDefImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ContributionDefImpl.java Tue Oct 18 00:51:33 2011
@@ -14,33 +14,25 @@
 
 package org.apache.tapestry5.ioc.internal;
 
+import org.apache.tapestry5.ioc.*;
+import org.apache.tapestry5.ioc.def.ContributionDef3;
+import org.apache.tapestry5.ioc.internal.util.*;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.slf4j.Logger;
+
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.tapestry5.ioc.Configuration;
-import org.apache.tapestry5.ioc.MappedConfiguration;
-import org.apache.tapestry5.ioc.ModuleBuilderSource;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.OrderedConfiguration;
-import org.apache.tapestry5.ioc.ServiceResources;
-import org.apache.tapestry5.ioc.def.ContributionDef2;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.DelegatingInjectionResources;
-import org.apache.tapestry5.ioc.internal.util.InjectionResources;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.MapInjectionResources;
-import org.apache.tapestry5.ioc.internal.util.WrongConfigurationTypeGuard;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
-import org.slf4j.Logger;
-
-public class ContributionDefImpl implements ContributionDef2
+public class ContributionDefImpl implements ContributionDef3
 {
     private final String serviceId;
 
     private final Method contributorMethod;
 
+    private final boolean optional;
+
     private final PlasticProxyFactory proxyFactory;
 
     private final Set<Class> markers;
@@ -48,13 +40,14 @@ public class ContributionDefImpl impleme
     private final Class serviceInterface;
 
     private static final Class[] CONFIGURATION_TYPES = new Class[]
-    { Configuration.class, MappedConfiguration.class, OrderedConfiguration.class };
+            {Configuration.class, MappedConfiguration.class, OrderedConfiguration.class};
 
-    public ContributionDefImpl(String serviceId, Method contributorMethod, PlasticProxyFactory proxyFactory,
-            Class serviceInterface, Set<Class> markers)
+    public ContributionDefImpl(String serviceId, Method contributorMethod, boolean optional, PlasticProxyFactory proxyFactory,
+                               Class serviceInterface, Set<Class> markers)
     {
         this.serviceId = serviceId;
         this.contributorMethod = contributorMethod;
+        this.optional = optional;
         this.proxyFactory = proxyFactory;
         this.serviceInterface = serviceInterface;
         this.markers = markers;
@@ -66,6 +59,11 @@ public class ContributionDefImpl impleme
         return InternalUtils.asString(contributorMethod, proxyFactory);
     }
 
+    public boolean isOptional()
+    {
+        return optional;
+    }
+
     public String getServiceId()
     {
         return serviceId;
@@ -77,19 +75,19 @@ public class ContributionDefImpl impleme
     }
 
     public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources,
-            OrderedConfiguration configuration)
+                           OrderedConfiguration configuration)
     {
         invokeMethod(moduleSource, resources, OrderedConfiguration.class, configuration);
     }
 
     public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources,
-            MappedConfiguration configuration)
+                           MappedConfiguration configuration)
     {
         invokeMethod(moduleSource, resources, MappedConfiguration.class, configuration);
     }
 
     private <T> void invokeMethod(ModuleBuilderSource source, ServiceResources resources, Class<T> parameterType,
-            T parameterValue)
+                                  T parameterValue)
     {
         Map<Class, Object> resourceMap = CollectionFactory.newMap();
 
@@ -120,12 +118,10 @@ public class ContributionDefImpl impleme
                     injectionResources, resources.getTracker());
 
             contributorMethod.invoke(moduleInstance, parameters);
-        }
-        catch (InvocationTargetException ex)
+        } catch (InvocationTargetException ex)
         {
             fail = ex.getTargetException();
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             fail = ex;
         }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java Tue Oct 18 00:51:33 2011
@@ -14,50 +14,23 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.ioc.AdvisorDef;
-import org.apache.tapestry5.ioc.Configuration;
-import org.apache.tapestry5.ioc.MappedConfiguration;
-import org.apache.tapestry5.ioc.MethodAdviceReceiver;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.OrderedConfiguration;
-import org.apache.tapestry5.ioc.ScopeConstants;
-import org.apache.tapestry5.ioc.ServiceBinder;
-import org.apache.tapestry5.ioc.ServiceBuilderResources;
-import org.apache.tapestry5.ioc.annotations.Advise;
-import org.apache.tapestry5.ioc.annotations.Contribute;
-import org.apache.tapestry5.ioc.annotations.Decorate;
-import org.apache.tapestry5.ioc.annotations.EagerLoad;
-import org.apache.tapestry5.ioc.annotations.Marker;
-import org.apache.tapestry5.ioc.annotations.Match;
-import org.apache.tapestry5.ioc.annotations.Order;
-import org.apache.tapestry5.ioc.annotations.PreventServiceDecoration;
-import org.apache.tapestry5.ioc.annotations.Scope;
-import org.apache.tapestry5.ioc.annotations.Startup;
-import org.apache.tapestry5.ioc.def.ContributionDef;
-import org.apache.tapestry5.ioc.def.ContributionDef2;
-import org.apache.tapestry5.ioc.def.DecoratorDef;
-import org.apache.tapestry5.ioc.def.ModuleDef2;
-import org.apache.tapestry5.ioc.def.ServiceDef;
+import org.apache.tapestry5.ioc.*;
+import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.def.*;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.slf4j.Logger;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
 /**
  * Starting from the Class for a module, identifies all the services (service builder methods),
  * decorators (service
@@ -117,12 +90,9 @@ public class DefaultModuleDefImpl implem
     }
 
     /**
-     * @param moduleClass
-     *            the class that is responsible for building services, etc.
-     * @param logger
-     *            based on the class name of the module
-     * @param proxyFactory
-     *            factory used to create proxy classes at runtime
+     * @param moduleClass  the class that is responsible for building services, etc.
+     * @param logger       based on the class name of the module
+     * @param proxyFactory factory used to create proxy classes at runtime
      */
     public DefaultModuleDefImpl(Class<?> moduleClass, Logger logger, PlasticProxyFactory proxyFactory)
     {
@@ -264,7 +234,7 @@ public class DefaultModuleDefImpl implem
     {
         Set<Class> markers = Collections.emptySet();
 
-        ContributionDef2 def = new ContributionDefImpl("RegistryStartup", method, proxyFactory, Runnable.class, markers);
+        ContributionDef2 def = new ContributionDefImpl("RegistryStartup", method, false, proxyFactory, Runnable.class, markers);
 
         contributionDefs.add(def);
     }
@@ -299,9 +269,11 @@ public class DefaultModuleDefImpl implem
         if (type == null)
             throw new RuntimeException(IOCMessages.noContributionParameter(method));
 
-        Set<Class> markers = extractMarkers(method, Contribute.class);
+        Set<Class> markers = extractMarkers(method, Contribute.class, Optional.class);
 
-        ContributionDef2 def = new ContributionDefImpl(serviceId, method, proxyFactory, serviceInterface, markers);
+        boolean optional = method.getAnnotation(Optional.class) != null;
+
+        ContributionDef3 def = new ContributionDefImpl(serviceId, method, optional, proxyFactory, serviceInterface, markers);
 
         contributionDefs.add(def);
     }
@@ -338,7 +310,7 @@ public class DefaultModuleDefImpl implem
 
         if (match == null)
         {
-            return new String[] { id };
+            return new String[]{id};
         }
 
         return match.value();
@@ -478,20 +450,27 @@ public class DefaultModuleDefImpl implem
     }
 
     @SuppressWarnings("rawtypes")
-    private Set<Class> extractMarkers(Method method, final Class annotationClassToSkip)
+    private Set<Class> extractMarkers(Method method, final Class... annotationClassesToSkip)
     {
         return F.flow(method.getAnnotations()).map(new Mapper<Annotation, Class>()
         {
             public Class map(Annotation value)
             {
                 return value.annotationType();
-            };
+            }
         }).filter(new Predicate<Class>()
         {
-            public boolean accept(Class object)
+            public boolean accept(Class element)
             {
-                return !object.equals(annotationClassToSkip);
+                for (Class skip : annotationClassesToSkip)
+                {
+                    if (skip.equals(element))
+                    {
+                        return false;
+                    }
+                }
 
+                return true;
             }
         }).toSet();
     }
@@ -533,13 +512,12 @@ public class DefaultModuleDefImpl implem
 
     /**
      * See if the build class defined a bind method and invoke it.
-     * 
-     * @param remainingMethods
-     *            set of methods as yet unaccounted for
+     *
+     * @param remainingMethods set of methods as yet unaccounted for
      * @param modulePreventsServiceDecoration
-     *            true if {@link org.apache.tapestry5.ioc.annotations.PreventServiceDecoration} on
-     *            module
-     *            class
+     *                         true if {@link org.apache.tapestry5.ioc.annotations.PreventServiceDecoration} on
+     *                         module
+     *                         class
      */
     private void bind(Set<Method> remainingMethods, boolean modulePreventsServiceDecoration)
     {
@@ -563,22 +541,18 @@ public class DefaultModuleDefImpl implem
             remainingMethods.remove(bindMethod);
 
             return;
-        }
-        catch (NoSuchMethodException ex)
+        } catch (NoSuchMethodException ex)
         {
             // No problem! Many modules will not have such a method.
 
             return;
-        }
-        catch (IllegalArgumentException ex)
+        } catch (IllegalArgumentException ex)
         {
             failure = ex;
-        }
-        catch (IllegalAccessException ex)
+        } catch (IllegalAccessException ex)
         {
             failure = ex;
-        }
-        catch (InvocationTargetException ex)
+        } catch (InvocationTargetException ex)
         {
             failure = ex.getTargetException();
         }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java Tue Oct 18 00:51:33 2011
@@ -213,19 +213,29 @@ public class RegistryImpl implements Reg
             {
                 String serviceId = cd.getServiceId();
 
-                ContributionDef2 cd2 = InternalUtils.toContributionDef2(cd);
+                ContributionDef3 cd3 = InternalUtils.toContributionDef3(cd);
 
-                if (cd2.getServiceId() != null)
+                // Ignore any optional contribution methods; there's no way to validate that
+                // they contribute to a known service ... that's the point of @Optional
+
+                if (cd3.isOptional())
+                {
+                    continue;
+                }
+
+                // Otherwise, check that the service being contributed to exists ...
+
+                if (cd3.getServiceId() != null)
                 {
                     if (!serviceIdToModule.containsKey(serviceId))
                     {
                         throw new IllegalArgumentException(
                                 IOCMessages.contributionForNonexistentService(cd));
                     }
-                } else if (!isContributionForExistentService(module, cd2))
+                } else if (!isContributionForExistentService(module, cd3))
                 {
                     throw new IllegalArgumentException(
-                            IOCMessages.contributionForUnqualifiedService(cd2));
+                            IOCMessages.contributionForUnqualifiedService(cd3));
                 }
             }
         }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java Tue Oct 18 00:51:33 2011
@@ -1085,6 +1085,55 @@ public class InternalUtils
         };
     }
 
+    public static ContributionDef3 toContributionDef3(ContributionDef contribution)
+    {
+
+        if (contribution instanceof ContributionDef2)
+        {
+            return (ContributionDef3) contribution;
+        }
+
+        final ContributionDef2 cd2 = toContributionDef2(contribution);
+
+        return new ContributionDef3()
+        {
+            public boolean isOptional()
+            {
+                return false;
+            }
+
+            public String getServiceId()
+            {
+                return cd2.getServiceId();
+            }
+
+            public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources, Configuration configuration)
+            {
+                cd2.contribute(moduleSource, resources, configuration);
+            }
+
+            public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources, OrderedConfiguration configuration)
+            {
+                cd2.contribute(moduleSource, resources, configuration);
+            }
+
+            public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources, MappedConfiguration configuration)
+            {
+                cd2.contribute(moduleSource, resources, configuration);
+            }
+
+            public Set<Class> getMarkers()
+            {
+                return cd2.getMarkers();
+            }
+
+            public Class getServiceInterface()
+            {
+                return cd2.getServiceInterface();
+            }
+        };
+    }
+
     /**
      * @since 5.2.2
      */

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java Tue Oct 18 00:51:33 2011
@@ -1606,4 +1606,11 @@ public class IntegrationTest extends IOC
             assertMessageContains(ex, "No defined implementation class to generate simple id from");
         }
     }
+
+    @Test
+    public void optional_contribution_to_unknown_service_is_not_an_error()
+    {
+
+        buildRegistry(OptionalContributionModule.class);
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/OptionalContributionModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/OptionalContributionModule.java?rev=1185442&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/OptionalContributionModule.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/OptionalContributionModule.java Tue Oct 18 00:51:33 2011
@@ -0,0 +1,25 @@
+// Copyright 2011 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
+//
+// 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.tapestry5.ioc;
+
+import org.apache.tapestry5.ioc.annotations.Optional;
+
+public class OptionalContributionModule
+{
+    @Optional
+    public static void contributeMissing(Configuration<String> whoKnows)
+    {
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ContributionDefImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ContributionDefImplTest.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ContributionDefImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ContributionDefImplTest.java Tue Oct 18 00:51:33 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009,, 2011 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.
@@ -14,22 +14,16 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import java.lang.reflect.Method;
-
-import javax.inject.Named;
-
-import org.apache.tapestry5.ioc.Configuration;
-import org.apache.tapestry5.ioc.MappedConfiguration;
-import org.apache.tapestry5.ioc.ModuleBuilderSource;
-import org.apache.tapestry5.ioc.OperationTracker;
-import org.apache.tapestry5.ioc.OrderedConfiguration;
-import org.apache.tapestry5.ioc.ServiceResources;
+import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.InjectService;
 import org.apache.tapestry5.ioc.def.ContributionDef;
 import org.apache.tapestry5.ioc.test.IOCTestCase;
 import org.slf4j.Logger;
 import org.testng.annotations.Test;
 
+import javax.inject.Named;
+import java.lang.reflect.Method;
+
 public class ContributionDefImplTest extends IOCTestCase implements ModuleBuilderSource
 {
     private final OperationTracker tracker = new QuietOperationTracker();
@@ -58,7 +52,7 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeUnordered");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, serviceResources, configuration);
 
@@ -83,13 +77,13 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeUnorderedParameter");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, resources, configuration);
 
         verify();
     }
-    
+
     @SuppressWarnings("unchecked")
     @Test
     public void unordered_collection_with_named_service_lookup()
@@ -108,7 +102,7 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeUnorderedParameterNamedServiceLookup");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, resources, configuration);
 
@@ -128,18 +122,17 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeUnorderedWrongParameter");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         try
         {
             def.contribute(this, resources, configuration);
             unreachable();
-        }
-        catch (RuntimeException ex)
+        } catch (RuntimeException ex)
         {
             assertMessageContains(ex,
-                                  "Error invoking service contribution method org.apache.tapestry5.ioc.internal.ContributionDefImplTest.contributeUnorderedWrongParameter(MappedConfiguration)",
-                                  "Service 'Bif' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
+                    "Error invoking service contribution method org.apache.tapestry5.ioc.internal.ContributionDefImplTest.contributeUnorderedWrongParameter(MappedConfiguration)",
+                    "Service 'Bif' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
             );
         }
 
@@ -168,7 +161,7 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeOrderedParameter");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, resources, configuration);
 
@@ -194,7 +187,7 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeOrderedParameterNamedServiceLookup");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, resources, configuration);
 
@@ -220,7 +213,7 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeMappedParameter");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, resources, configuration);
 
@@ -246,7 +239,7 @@ public class ContributionDefImplTest ext
         replay();
 
         Method m = findMethod("contributeMappedParameterNamedServiceLookup");
-        ContributionDef def = new ContributionDefImpl("foo.Bar", m, null, null, null);
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m, false, null, null, null);
 
         def.contribute(this, resources, configuration);
 
@@ -272,8 +265,8 @@ public class ContributionDefImplTest ext
     }
 
     public void contributeUnorderedParameterNamedServiceLookup(Configuration<UpcaseService> configuration,
-                                             @Named("zip.Zap")
-                                             UpcaseService service)
+                                                               @Named("zip.Zap")
+                                                               UpcaseService service)
     {
         configuration.add(service);
     }
@@ -286,8 +279,8 @@ public class ContributionDefImplTest ext
     }
 
     public void contributeOrderedParameterNamedServiceLookup(OrderedConfiguration<UpcaseService> configuration,
-                                           @Named("zip.Zap")
-                                           UpcaseService service)
+                                                             @Named("zip.Zap")
+                                                             UpcaseService service)
     {
         configuration.add("fred", service);
     }
@@ -300,8 +293,8 @@ public class ContributionDefImplTest ext
     }
 
     public void contributeMappedParameterNamedServiceLookup(MappedConfiguration<String, UpcaseService> configuration,
-                                          @Named("zip.Zap")
-                                          UpcaseService service)
+                                                            @Named("zip.Zap")
+                                                            UpcaseService service)
     {
         configuration.add("upcase", service);
     }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ValidatingMappedConfigurationWrapperTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ValidatingMappedConfigurationWrapperTest.java?rev=1185442&r1=1185441&r2=1185442&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ValidatingMappedConfigurationWrapperTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/ValidatingMappedConfigurationWrapperTest.java Tue Oct 18 00:51:33 2011
@@ -14,18 +14,18 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
-
-import java.util.Map;
-
 import org.apache.tapestry5.ioc.MappedConfiguration;
 import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.def.ContributionDef;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.testng.annotations.Test;
 
+import java.util.Map;
+
+import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
+
 @SuppressWarnings(
-{ "rawtypes", "unchecked" })
+        {"rawtypes", "unchecked"})
 public class ValidatingMappedConfigurationWrapperTest extends IOCInternalTestCase
 {
     private static final String SERVICE_ID = "Baz";
@@ -111,8 +111,7 @@ public class ValidatingMappedConfigurati
         {
             wrapper.add(key, value);
             unreachable();
-        }
-        catch (IllegalArgumentException ex)
+        } catch (IllegalArgumentException ex)
         {
             assertMessageContains(ex, "Service contribution (to service 'Baz') conflicts with existing contribution");
         }
@@ -141,8 +140,7 @@ public class ValidatingMappedConfigurati
         {
             wrapper.add(null, value);
             unreachable();
-        }
-        catch (NullPointerException ex)
+        } catch (NullPointerException ex)
         {
             assertEquals(ex.getMessage(), "Key for service contribution (to service 'Baz') was null.");
         }
@@ -171,8 +169,7 @@ public class ValidatingMappedConfigurati
         {
             wrapper.add("java.util.List", value);
             unreachable();
-        }
-        catch (IllegalArgumentException ex)
+        } catch (IllegalArgumentException ex)
         {
             assertEquals(
                     ex.getMessage(),
@@ -201,8 +198,7 @@ public class ValidatingMappedConfigurati
         {
             wrapper.add(Integer.class, null);
             unreachable();
-        }
-        catch (NullPointerException ex)
+        } catch (NullPointerException ex)
         {
             assertEquals(ex.getMessage(), "Service contribution (to service 'Baz') was null.");
         }
@@ -214,7 +210,7 @@ public class ValidatingMappedConfigurati
 
     private ContributionDef newContributionDef(String methodName)
     {
-        return new ContributionDefImpl(SERVICE_ID, findMethod(methodName), getProxyFactory(), null, null);
+        return new ContributionDefImpl(SERVICE_ID, findMethod(methodName), false, getProxyFactory(), null, null);
     }
 
     public void contributionPlaceholder1()