You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by "Dmitry Gusev (Jira)" <ji...@apache.org> on 2020/08/17 13:01:00 UTC

[jira] [Commented] (TAP5-2637) Provide API to query multiple/all service instances from ObjectLocator by service interface/markers

    [ https://issues.apache.org/jira/browse/TAP5-2637?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17178964#comment-17178964 ] 

Dmitry Gusev commented on TAP5-2637:
------------------------------------

 

For the sake of backwards compatibility and following the [developer bible on evolving user interfaces|https://tapestry.apache.org/developer-bible.html#DeveloperBible-UserInterfaces] we may create `ObjectLocator2` extending `ObjectLocator` and include new methods there.

Proof of concept and slightly hacky way of implementing the getServices() on previous tapestry versions:
{code:java}
public interface ObjectLocatorHelper
{
    <T> List<T> getServices(Class<T> clazz);
}

public class ObjectLocatorHelperImpl implements ObjectLocatorHelper
{
    private final RegistryImpl registryImpl;

    private final Method findServiceIdsForInterfaceMethod;

    public ObjectLocatorHelperImpl(ObjectLocator objectLocator) throws NoSuchMethodException, IllegalAccessException
    {
        if (objectLocator instanceof ServiceBuilderResources || objectLocator instanceof RegistryWrapper)
        {
            final Field registryField = getField(objectLocator.getClass(), "registry", true);

            registryImpl = (RegistryImpl) registryField.get(objectLocator);
        }
        else
        {
            throw new IllegalArgumentException();
        }

        //  private List<String> findServiceIdsForInterface(Class serviceInterface)
        findServiceIdsForInterfaceMethod =
                registryImpl.getClass()
                        .getDeclaredMethod(
                                "findServiceIdsForInterface",
                                Class.class);

        findServiceIdsForInterfaceMethod.setAccessible(true);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> getServices(Class<T> clazz)
    {
        try
        {
            final List<String> serviceIds =
                    (List<String>) findServiceIdsForInterfaceMethod.invoke(registryImpl, clazz);

            if (serviceIds == null || serviceIds.isEmpty())
            {
                return List.of();
            }

            return serviceIds
                    .stream()
                    .map(serviceId -> registryImpl.getService(serviceId, clazz))
                    .collect(toList());
        }
        catch (IllegalAccessException | InvocationTargetException e)
        {
            throw new RuntimeException(e);
        }
    }
}

{code}
 

 

> Provide API to query multiple/all service instances from ObjectLocator by service interface/markers
> ---------------------------------------------------------------------------------------------------
>
>                 Key: TAP5-2637
>                 URL: https://issues.apache.org/jira/browse/TAP5-2637
>             Project: Tapestry 5
>          Issue Type: Improvement
>          Components: tapestry-ioc
>            Reporter: Dmitry Gusev
>            Priority: Major
>
> Tapestry IoC's `ObjectLocator` can only return a service if there's exactly one implementation matching criteria:
>  
> {code:java}
> <T> T getService(Class<T> serviceInterface)
> <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
> {code}
> It's sometimes necessary to get all registered services, i.e. when integrating with 3rd party libraries that support "bring your own service discovery", they expect this functionality from service discovery.
> At present `RegistryImpl` has everything we need to implement this feature, see `#findServiceIdsForInterface` and `#findServiceDefsMatchingMarkerAndType`.
>  
> As future work we could also support list-type injections, i.e.
> {code:java}
> @Inject List<ServiceA> multipleInjections;{code}
> Marker annotations would fit nicely here, e.g. `@Inject @Blue List<ServiceA> multipleInjections;`
> In theory it may break injections for services that implement the `List` interface itself, unsure if there are any real use-cases for it. But as all service definitions are known upfront on registry initialisation we may implement a safety check and fail with error if there's any. We may also provide a symbol to disable List-injections, and only run the mentioned check/failure if the symbol is enabled.
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)