2010-04-21 8 views
4

J'ai un problème avec l'intégration de Tapestry 5 et Spring. Le problème se produit si j'ai plusieurs beans qui implémentent la même interface et j'essaie de leur injecter l'annotation @Inject. Bien sûr, j'ai une exception.Tapisserie 5 et haricots de printemps avec la même interface

J'ai trouvé un tutorial qui dit que, dans ce cas, je dois utiliser @Service annotation aussi, mais maintenant je suis en train de

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... 

Quoi qu'il en soit, la question est: Comment puis-je injecter deux grains de printemps différents, qui mettent en œuvre une même interface, dans la page Tapestry 5?

Répondre

2

J'ai résolu ce problème.

D'abord, je fait une nouvelle annotation

public @interface Bean { 
    String value(); 
} 

et j'utiliser partout où j'ai celui de plusieurs haricots mise en œuvre même interface

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

Puis j'ai changé 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); 
      } 
      } 
     } 
     }; 
+4

Le comportement de l'intégration de Spring a changé entre la version 5.0 et 5.1. Dans 5.0, chaque bean Spring était exposé en tant que service Tapestry, et si vous aviez deux beans implémentant la même interface, vous pouviez toujours utiliser '@ Service' avec le nom du bean approprié pour clarifier quel objet vous vouliez. Dans 5.1, ce n'est plus le cas, rendant l'annotation '@ Service' inutile pour les beans Spring. Vous êtes arrosé à moins que vous ne soyez prêt à faire de la magie de métaprogrammation vous-même. Bonne solution, d'ailleurs. – Henning

0

Il semble que vous ayez une faute de frappe dans le nom donné à l'annotation @Service, ou que vous n'ayez pas défini le bean avec le nom que vous attendiez. Sans plus d'informations, il est difficile de dire avec certitude, car il existe également d'autres possibilités.

+0

Nope , double vérification - pas de fautes de frappe et dans commonBeans.ctx.xml J'ai aussi cette fève – vrm