Search code examples
javaspringdependency-injectiontapestry

Tapestry 5 and Spring beans with same interface


I have a problem with Tapestry 5 and Spring integration. Problem occurs if I have a multiple beans that implement the same interface and I try to inject them with @Inject annotation. Of course I got an exception.

I found a tutorial that says that in that case I have to use @Service annotation too but now I'm getting

org.apache.tapestry5.internal.services.TransformationException
Error obtaining injected value for field 
com.foo.pages.Foo.testService: Service 
id 'someServiceIDeclaredInSpringContextFile' is not defined by any module...

Anyway, question is: How can I inject two different spring beans, that implement a same interface, into Tapestry 5 page?


Solution

  • I solved this problem.

    First I made a new annotation

    public @interface Bean {
        String value();
    }
    

    and I use this wherever I have this one of multiple beans implementing same interface

    @Inject
    @Bean("springBeanName")
    Service foo;
    

    Then I changed org.apache.tapestry5.internal.spring.SpringModuleDef

    private ContributionDef createContributionToMasterObjectProvider() {
      ....
      public void contribute(ModuleBuilderSource moduleSource, 
                    ServiceResources resources,
                    OrderedConfiguration configuration) {
        ....
        switch (beanMap.size()) {
               case 0:
                 return null;
               case 1:
                 Object bean = beanMap.values().iterator().next();
                 return objectType.cast(bean);
               default:
                 Bean annotation = annotationProvider.getAnnotation(Bean.class);
                 Object springBean = null;
                 String beanName = null;
    
                 if (annotation != null) {
                   beanName = annotation.value();
                   springBean = beanMap.get(beanName);
                 } else {
                   String message = String.format(
                     "Spring context contains %d beans assignable to type %s: %s.",
                     beanMap.size(),
                     ClassFabUtils.toJavaClassName(objectType),
                     InternalUtils.joinSorted(beanMap.keySet()));
                   throw new IllegalArgumentException(message);
                 }
                 if (springBean != null) {
                   return objectType.cast(springBean);
                 } else {
                   String message = String.format(
                     "Bean [%s] of type %s doesn't exists. Available beans: %s",
                     beanName, ClassFabUtils.toJavaClassName(objectType),
                     InternalUtils.joinSorted(beanMap.keySet()));
                   throw new IllegalArgumentException(message);
                 }
               }
             }
           };