You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/10/22 00:08:11 UTC

svn commit: r1187574 - in /tapestry/tapestry5/trunk: tapestry-core/src/test/java/org/apache/tapestry5/internal/test/ tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/ tapestry-ioc/src/...

Author: hlship
Date: Fri Oct 21 22:08:10 2011
New Revision: 1187574

URL: http://svn.apache.org/viewvc?rev=1187574&view=rev
Log:
TAP5-546: ObjectLocator.getService(Class) should be expanded to pass a varargs of marker annotation types

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Marker.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.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/RegistryWrapper.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/MasterObjectProvider.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/IOCInternalTestCase.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java Fri Oct 21 22:08:10 2011
@@ -44,6 +44,7 @@ import org.testng.annotations.AfterSuite
 import org.testng.annotations.BeforeSuite;
 
 import java.io.*;
+import java.lang.annotation.Annotation;
 
 import static org.easymock.EasyMock.isA;
 
@@ -90,7 +91,7 @@ public class InternalBaseTestCase extend
         return registry.getObject(objectType, annotationProvider);
     }
 
-    public final <T> T getService(Class<T> serviceInterface)
+    public final <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes)
     {
         return registry.getService(serviceInterface);
     }
@@ -171,7 +172,7 @@ public class InternalBaseTestCase extend
     }
 
     protected final void train_resolvePageClassNameToPageName(ComponentClassResolver resolver, String pageClassName,
-            String pageName)
+                                                              String pageName)
     {
         expect(resolver.resolvePageClassNameToPageName(pageClassName)).andReturn(pageName);
     }
@@ -245,7 +246,8 @@ public class InternalBaseTestCase extend
         expect(cache.get(pageName)).andReturn(page).atLeastOnce();
     }
 
-    protected final LinkCreationListener2 mockLinkCreationListener2() {
+    protected final LinkCreationListener2 mockLinkCreationListener2()
+    {
         return newMock(LinkCreationListener2.class);
     }
 
@@ -274,8 +276,7 @@ public class InternalBaseTestCase extend
      * leading/trailing
      * whitespace.
      *
-     * @param file
-     *            trim each line of whitespace
+     * @param file trim each line of whitespace
      */
     protected final String readFile(String file) throws Exception
     {
@@ -309,7 +310,7 @@ public class InternalBaseTestCase extend
     }
 
     protected final void train_canonicalizePageName(ComponentClassResolver resolver, String pageName,
-            String canonicalized)
+                                                    String canonicalized)
     {
         expect(resolver.canonicalizePageName(pageName)).andReturn(canonicalized);
     }
@@ -370,13 +371,13 @@ public class InternalBaseTestCase extend
     }
 
     protected final void train_getPropertyAdapter(ClassPropertyAdapter classPropertyAdapter, String propertyName,
-            PropertyAdapter propertyAdapter)
+                                                  PropertyAdapter propertyAdapter)
     {
         expect(classPropertyAdapter.getPropertyAdapter(propertyName)).andReturn(propertyAdapter).atLeastOnce();
     }
 
     protected final void train_getAdapter(PropertyAccess access, Object object,
-            ClassPropertyAdapter classPropertyAdapter)
+                                          ClassPropertyAdapter classPropertyAdapter)
     {
         expect(access.getAdapter(object)).andReturn(classPropertyAdapter);
     }
@@ -397,7 +398,7 @@ public class InternalBaseTestCase extend
     }
 
     protected final void train_setLocaleFromLocaleName(LocalizationSetter localizationSetter, String localeName,
-            boolean recognized)
+                                                       boolean recognized)
     {
         expect(localizationSetter.setLocaleFromLocaleName(localeName)).andReturn(recognized);
     }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java Fri Oct 21 22:08:10 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 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.
@@ -17,6 +17,8 @@ package org.apache.tapestry5.ioc;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.services.MasterObjectProvider;
 
+import java.lang.annotation.Annotation;
+
 /**
  * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
  * to objects or object instances available by other means. Services are accessed via service id, or
@@ -32,50 +34,43 @@ public interface ObjectLocator
      * interface as the actual service, and is used to instantiate the actual service only as needed
      * (this is
      * transparent to the application).
-     * 
+     *
      * @param <T>
-     * @param serviceId
-     *            unique Service id used to locate the service object (may contain <em>symbols</em>,
-     *            which
-     *            will be expanded), case is ignored
-     * @param serviceInterface
-     *            the interface implemented by the service (or an interface extended by the service
-     *            interface)
+     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
+     *                         which
+     *                         will be expanded), case is ignored
+     * @param serviceInterface the interface implemented by the service (or an interface extended by the service
+     *                         interface)
      * @return the service instance
-     * @throws RuntimeException
-     *             if the service is not defined, or if an error occurs instantiating it
+     * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
      */
     <T> T getService(String serviceId, Class<T> serviceInterface);
 
     /**
-     * Locates a service given just a service interface. A single service must implement the service
-     * interface (which
-     * can be hard to guarantee). The search takes into account inheritance of the service interface
+     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
      * (not the service <em>implementation</em>), which may result in a failure due to extra
-     * matches.
-     * 
-     * @param <T>
-     * @param serviceInterface
-     *            the interface the service implements
+     * matches.        The ability to specify marker annotation types was added in 5.3
+     *
+     * @param serviceInterface the interface the service implements
+     * @param markerTypes
      * @return the service's proxy
-     * @throws RuntimeException
-     *             if the service does not exist (this is considered programmer error), or multiple
-     *             services directly implement, or extend from, the service interface
+     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+     *                          services directly implement, or extend from, the service interface
+     * @see org.apache.tapestry5.ioc.annotations.Marker
      */
-    <T> T getService(Class<T> serviceInterface);
+    <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
 
     /**
      * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
-     * 
-     * @param objectType
-     *            the type of object to be returned
-     * @param annotationProvider
-     *            provides access to annotations on the field or parameter for which a value is to
-     *            be
-     *            obtained, which may be utilized in selecting an appropriate object, use
-     *            <strong>null</strong> when annotations are not available (in which case, selection
-     *            will
-     *            be based only on the object type)
+     *
+     * @param objectType         the type of object to be returned
+     * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
+     *                           be
+     *                           obtained, which may be utilized in selecting an appropriate object, use
+     *                           <strong>null</strong> when annotations are not available (in which case, selection
+     *                           will
+     *                           be based only on the object type)
      * @param <T>
      * @return the requested object
      * @see ObjectProvider
@@ -89,13 +84,11 @@ public interface ObjectLocator
      * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
      * just dependencies or objects provided via
      * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
-     * 
+     *
      * @param <T>
-     * @param clazz
-     *            the type of object to instantiate
+     * @param clazz the type of object to instantiate
      * @return the instantiated instance
-     * @throws RuntimeException
-     *             if the autobuild fails
+     * @throws RuntimeException if the autobuild fails
      * @see MasterObjectProvider
      */
     <T> T autobuild(Class<T> clazz);
@@ -103,15 +96,12 @@ public interface ObjectLocator
     /**
      * Preferred version of {@link #autobuild(Class)} that tracks the operation using
      * {@link OperationTracker#invoke(String, Invokable)}.
-     * 
+     *
      * @param <T>
-     * @param description
-     *            description used with {@link OperationTracker}
-     * @param clazz
-     *            the type of object to instantiate
+     * @param description description used with {@link OperationTracker}
+     * @param clazz       the type of object to instantiate
      * @return the instantiated instance
-     * @throws RuntimeException
-     *             if the autobuild fails
+     * @throws RuntimeException if the autobuild fails
      * @see MasterObjectProvider
      * @since 5.2.0
      */
@@ -123,16 +113,14 @@ public interface ObjectLocator
      * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
      * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
      * of autobuilding).
-     * <p>
+     * <p/>
      * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
      * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
      * (with dependencies).
-     * 
+     *
      * @param <T>
-     * @param interfaceClass
-     *            the interface implemented by the proxy
-     * @param implementationClass
-     *            a concrete class that implements the interface
+     * @param interfaceClass      the interface implemented by the proxy
+     * @param implementationClass a concrete class that implements the interface
      * @return a proxy
      * @see #autobuild(Class)
      */

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Marker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Marker.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Marker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Marker.java Fri Oct 21 22:08:10 2011
@@ -1,4 +1,4 @@
-// Copyright 2007, 2009 The Apache Software Foundation
+// Copyright 2007, 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.
@@ -17,11 +17,12 @@ package org.apache.tapestry5.ioc.annotat
 import org.apache.tapestry5.ioc.def.ServiceDef;
 
 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.ElementType.TYPE;
-import java.lang.annotation.Retention;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import java.lang.annotation.Target;
 
 /**
  * Used to define one or more {@linkplain ServiceDef#getMarkers() marker annotations} for a service implementation. This
@@ -32,9 +33,11 @@ import java.lang.annotation.Target;
  * additive, so a Marker annotation on the implementation class and/or specified with {@link
  * org.apache.tapestry5.ioc.ServiceBindingOptions#withMarker(Class[])} will accumulate; a service may have any number of
  * markers.  Generally one or two is enough.
+ *
+ * @see org.apache.tapestry5.ioc.ObjectLocator#getService(Class, Class[])
  */
 @Target(
-        { TYPE, METHOD })
+        {TYPE, METHOD})
 @Retention(RUNTIME)
 @Documented
 @UseWith({AnnotationUseContext.SERVICE, AnnotationUseContext.MODULE})

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java Fri Oct 21 22:08:10 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 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.
@@ -17,6 +17,8 @@ package org.apache.tapestry5.ioc.interna
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.ObjectLocator;
 
+import java.lang.annotation.Annotation;
+
 /**
  * Base service locator class used when only the module is known (i.e., when instantiating a module
  * class).
@@ -40,9 +42,9 @@ public class ObjectLocatorImpl implement
         return registry.getService(expandedServiceId, serviceInterface);
     }
 
-    public <T> T getService(Class<T> serviceInterface)
+    public <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes)
     {
-        return registry.getService(serviceInterface);
+        return registry.getService(serviceInterface, markerTypes);
     }
 
     public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider)

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=1187574&r1=1187573&r2=1187574&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 Fri Oct 21 22:08:10 2011
@@ -30,7 +30,11 @@ import org.apache.tapestry5.ioc.util.Unk
 import org.apache.tapestry5.services.UpdateListenerHub;
 import org.slf4j.Logger;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.util.*;
 
 @SuppressWarnings("all")
@@ -108,6 +112,8 @@ public class RegistryImpl implements Reg
 
     private final TypeCoercerProxy typeCoercerProxy = new TypeCoercerProxyImpl(this);
 
+    private final Map<Class<? extends Annotation>, Annotation> cachedAnnotationProxies = CollectionFactory.newConcurrentMap();
+
     /**
      * Constructs the registry from a set of module definitions and other resources.
      *
@@ -627,10 +633,20 @@ public class RegistryImpl implements Reg
         }
     }
 
-    public <T> T getService(Class<T> serviceInterface)
+    public <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes)
     {
         lock.check();
 
+        if (markerTypes.length == 0)
+        {
+            return findServiceByTypeAlone(serviceInterface);
+        }
+
+        return findServiceByTypeAndMarkers(serviceInterface, markerTypes);
+    }
+
+    private <T> T findServiceByTypeAlone(Class<T> serviceInterface)
+    {
         List<String> serviceIds = findServiceIdsForInterface(serviceInterface);
 
         if (serviceIds == null)
@@ -656,6 +672,67 @@ public class RegistryImpl implements Reg
         }
     }
 
+    private <T> T findServiceByTypeAndMarkers(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes)
+    {
+        AnnotationProvider provider = createAnnotationProvider(markerTypes);
+
+        Set<ServiceDef2> matches = CollectionFactory.newSet();
+        List<Class> markers = CollectionFactory.newList();
+
+        findServiceDefsMatchingMarkerAndType(serviceInterface, provider, null, markers, matches);
+
+        return extractServiceFromMatches(serviceInterface, markers, matches);
+    }
+
+    private AnnotationProvider createAnnotationProvider(Class<? extends Annotation>... markerTypes)
+    {
+        final Map<Class<? extends Annotation>, Annotation> map = CollectionFactory.newMap();
+
+        for (Class<? extends Annotation> markerType : markerTypes)
+        {
+            map.put(markerType, createAnnotationProxy(markerType));
+        }
+
+        return new AnnotationProvider()
+        {
+            public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+            {
+                return annotationClass.cast(map.get(annotationClass));
+            }
+        };
+    }
+
+    private <A extends Annotation> Annotation createAnnotationProxy(final Class<A> annotationType)
+    {
+        Annotation result = cachedAnnotationProxies.get(annotationType);
+
+        if (result == null)
+        {
+            // We create a JDK proxy because its pretty quick and easy.
+
+            InvocationHandler handler = new InvocationHandler()
+            {
+                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+                {
+                    if (method.getName().equals("annotationType"))
+                    {
+                        return annotationType;
+                    }
+
+                    return method.invoke(proxy, args);
+                }
+            };
+
+            result = (Annotation) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+                    new Class[]{annotationType},
+                    handler);
+
+            cachedAnnotationProxies.put(annotationType, result);
+        }
+
+        return result;
+    }
+
     private List<String> findServiceIdsForInterface(Class serviceInterface)
     {
         List<String> result = CollectionFactory.newList();
@@ -805,34 +882,29 @@ public class RegistryImpl implements Reg
         if (provider == null)
             return null;
 
-        boolean localOnly = localModule != null && provider.getAnnotation(Local.class) != null;
-
         Set<ServiceDef2> matches = CollectionFactory.newSet();
-
-        matches.addAll(filterByType(objectType, localOnly ? moduleToServiceDefs.get(localModule) : allServiceDefs));
-
         List<Class> markers = CollectionFactory.newList();
 
-        if (localOnly)
-            markers.add(Local.class);
-
-        for (Class marker : markerToServiceDef.keySet())
-        {
-            if (provider.getAnnotation(marker) == null)
-                continue;
-
-            markers.add(marker);
+        findServiceDefsMatchingMarkerAndType(objectType, provider, localModule, markers, matches);
 
-            matches = intersection(matches, markerToServiceDef.get(marker));
-        }
 
         // If didn't see @Local or any recognized marker annotation, then don't try to filter that
-        // way.
-        // Continue on, eventually to the MasterObjectProvider service.
+        // way. Continue on, eventually to the MasterObjectProvider service.
 
         if (markers.isEmpty())
+        {
             return null;
+        }
 
+        return extractServiceFromMatches(objectType, markers, matches);
+    }
+
+    /**
+     * Given markers and matches processed by {@link #findServiceDefsMatchingMarkerAndType(Class, org.apache.tapestry5.ioc.AnnotationProvider, Module, java.util.List, java.util.Set)}, this
+     * finds the singular match, or reports an error for 0 or 2+ matches.
+     */
+    private <T> T extractServiceFromMatches(Class<T> objectType, List<Class> markers, Set<ServiceDef2> matches)
+    {
         switch (matches.size())
         {
 
@@ -859,28 +931,36 @@ public class RegistryImpl implements Reg
         }
     }
 
-    /**
-     * Filters the set into a new set, containing only elements shared between the set and the
-     * filter collection.
-     *
-     * @param set    to be filtered
-     * @param filter values to keep from the set
-     * @return a new set containing only the shared values
-     */
-    private static <T> Set<T> intersection(Set<T> set, Collection<T> filter)
+    private <T> void findServiceDefsMatchingMarkerAndType(Class<T> objectType, AnnotationProvider provider, Module localModule, List<Class> markers,
+                                                          Set<ServiceDef2> matches)
     {
-        if (set.isEmpty())
-            return Collections.emptySet();
+        assert provider != null;
 
-        Set<T> result = CollectionFactory.newSet();
+        boolean localOnly = localModule != null && provider.getAnnotation(Local.class) != null;
+
+        matches.addAll(filterByType(objectType, localOnly ? moduleToServiceDefs.get(localModule) : allServiceDefs));
 
-        for (T elem : filter)
+        if (localOnly)
         {
-            if (set.contains(elem))
-                result.add(elem);
+            markers.add(Local.class);
         }
 
-        return result;
+        for (Class marker : markerToServiceDef.keySet())
+        {
+            if (provider.getAnnotation(marker) == null)
+            {
+                continue;
+            }
+
+            markers.add(marker);
+
+            matches.retainAll(markerToServiceDef.get(marker));
+
+            if (matches.isEmpty())
+            {
+                return;
+            }
+        }
     }
 
     public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider)

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryWrapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryWrapper.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryWrapper.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryWrapper.java Fri Oct 21 22:08:10 2011
@@ -1,4 +1,4 @@
-// Copyright 2007, 2010 The Apache Software Foundation
+// Copyright 2007, 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.
@@ -18,9 +18,11 @@ import org.apache.tapestry5.ioc.Annotati
 import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.Registry;
 
+import java.lang.annotation.Annotation;
+
 /**
  * A wrapper around {@link InternalRegistry} that exists to expand symbols in a service id before
- * invoking {@link ObjectLocator#getService(Class)}.
+ * invoking {@link ObjectLocator#getService(String, Class)}.
  */
 public class RegistryWrapper implements Registry
 {
@@ -53,9 +55,9 @@ public class RegistryWrapper implements 
         return registry.getService(expandedServiceId, serviceInterface);
     }
 
-    public <T> T getService(Class<T> serviceInterface)
+    public <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes)
     {
-        return registry.getService(serviceInterface);
+        return registry.getService(serviceInterface, markerTypes);
     }
 
     public <T> T autobuild(Class<T> clazz)

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/MasterObjectProvider.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/MasterObjectProvider.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/MasterObjectProvider.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/MasterObjectProvider.java Fri Oct 21 22:08:10 2011
@@ -39,7 +39,8 @@ public interface MasterObjectProvider
      * decorator method. The locator parameter provides access to the services visible <em>to that context</em>.
      * <p/>
      * When the value is required and no {@link ObjectProvider} provided a non-null value, then {@link
-     * ObjectLocator#getService(Class)} is invoked, to provide a uniquely matching service, or throw a failure exception
+     * ObjectLocator#getService(Class, Class[])}  is invoked (with no marker annotations),
+     * to provide a uniquely matching service, or throw a failure exception
      * if no <em>single</em> service can be found.
      *
      * @param objectType         the expected object type

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=1187574&r1=1187573&r2=1187574&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 Fri Oct 21 22:08:10 2011
@@ -827,6 +827,19 @@ public class IntegrationTest extends IOC
     }
 
     @Test
+    public void get_service_by_type_and_markers()
+    {
+        Registry r = buildRegistry(GreeterModule.class);
+
+        Greeter blue = r.getService(Greeter.class, BlueMarker.class);
+
+        assert blue.getGreeting().equals("Blue");
+
+        r.shutdown();
+    }
+
+
+    @Test
     public void service_activity_scoreboard_perthread() throws InterruptedException
     {
         final Registry r = buildRegistry(GreeterModule.class, PerThreadModule.class);

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/IOCInternalTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/IOCInternalTestCase.java?rev=1187574&r1=1187573&r2=1187574&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/IOCInternalTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/IOCInternalTestCase.java Fri Oct 21 22:08:10 2011
@@ -14,11 +14,6 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import static org.easymock.EasyMock.isA;
-
-import java.util.Collections;
-import java.util.List;
-
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.RegistryBuilder;
@@ -31,6 +26,12 @@ import org.testng.annotations.AfterMetho
 import org.testng.annotations.AfterSuite;
 import org.testng.annotations.BeforeSuite;
 
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.List;
+
+import static org.easymock.EasyMock.isA;
+
 public class IOCInternalTestCase extends IOCTestCase implements Registry
 {
     private static Registry registry;
@@ -60,9 +61,9 @@ public class IOCInternalTestCase extends
         return registry.getObject(objectType, annotationProvider);
     }
 
-    public final <T> T getService(Class<T> serviceInterface)
+    public final <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes)
     {
-        return registry.getService(serviceInterface);
+        return registry.getService(serviceInterface, markerTypes);
     }
 
     public final <T> T getService(String serviceId, Class<T> serviceInterface)
@@ -146,7 +147,7 @@ public class IOCInternalTestCase extends
     }
 
     protected final <T> void train_getService(InternalRegistry registry, String serviceId, Class<T> serviceInterface,
-            T service)
+                                              T service)
     {
         expect(registry.getService(serviceId, serviceInterface)).andReturn(service);
     }
@@ -156,7 +157,9 @@ public class IOCInternalTestCase extends
         return newMock(ServiceActivityTracker.class);
     }
 
-    /** @since 5.3 */
+    /**
+     * @since 5.3
+     */
     protected final TypeCoercerProxy mockTypeCoercerProxy()
     {
         return newMock(TypeCoercerProxy.class);