Tapestry 5
  1. Tapestry 5
  2. TAP5-1788

Service id 'environment' has already been defined by org.apache.tapestry5.services.TapestryModule with Spring 3.1

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.2.4
    • Fix Version/s: 5.3.2, 5.4
    • Component/s: tapestry-spring
    • Labels:
      None

      Description

      After upgrading to Spring 3.1, started seeing the following error with Tapestry 5.2.4.

      java.lang.RuntimeException: Service id 'environment' has already been defined by org.apache.tapestry5.services.TapestryModule.buildEnvironment(PerthreadManager)

      More information at http://tapestry.1045711.n5.nabble.com/tapestry-5-2-4-and-spring-3-1M1-td4462226.html#a4742011

        Issue Links

          Activity

          Hide
          Denis Stepanov added a comment -

          Why not just prefix spring service ids with "spring."?

          Show
          Denis Stepanov added a comment - Why not just prefix spring service ids with "spring."?
          Hide
          Fernando Padilla added a comment -

          I also have the same issue as Ralf. We need to go back to getting the beanNames including ancestors/parents please.

          are there any better solutions, can't we simply ignore the "environment" bean from spring? Or can we just have Tapestry IoC prefer services defined from Tapestry, before looking at spring based ones??

          Show
          Fernando Padilla added a comment - I also have the same issue as Ralf. We need to go back to getting the beanNames including ancestors/parents please. are there any better solutions, can't we simply ignore the "environment" bean from spring? Or can we just have Tapestry IoC prefer services defined from Tapestry, before looking at spring based ones??
          Hide
          Ralf Edmund Stranzenbach added a comment -

          This solution has an undesired side effect. It prevents me from using a centralized spring context that is associated as a "parent context" to the "application.xml" loaded by the tapestry-spring filter.

          Only the few beans assigned to the web-app specific part of the spring configuration are therefore visible to the tapestry injector. The main part of my applications infrastructure became invisible to tapestry.

          A better solution would be to either assign an implicit "namespace" to spring beans in case they duplicate a service name already used in tapestry. This would enable the use of parent spring context while preventing the duplicate "Environment" service.

          Show
          Ralf Edmund Stranzenbach added a comment - This solution has an undesired side effect. It prevents me from using a centralized spring context that is associated as a "parent context" to the "application.xml" loaded by the tapestry-spring filter. Only the few beans assigned to the web-app specific part of the spring configuration are therefore visible to the tapestry injector. The main part of my applications infrastructure became invisible to tapestry. A better solution would be to either assign an implicit "namespace" to spring beans in case they duplicate a service name already used in tapestry. This would enable the use of parent spring context while preventing the duplicate "Environment" service.
          Hide
          Hudson added a comment -

          Integrated in tapestry-trunk-freestyle #644 (See https://builds.apache.org/job/tapestry-trunk-freestyle/644/)
          TAP5-1788: Avoid collision with Service id 'environment' that has already been defined in Spring 3.1

          drobiazko : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1214678
          Files :

          • /tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/SpringModuleDefTest.java
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryExternalSpringContextIntegrationTest.java
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/pages
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/pages/Index.java
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/services
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/services/AppModule.java
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/Index.tml
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/WEB-INF
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/WEB-INF/applicationContext.xml
          • /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/WEB-INF/web.xml
          Show
          Hudson added a comment - Integrated in tapestry-trunk-freestyle #644 (See https://builds.apache.org/job/tapestry-trunk-freestyle/644/ ) TAP5-1788 : Avoid collision with Service id 'environment' that has already been defined in Spring 3.1 drobiazko : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1214678 Files : /tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/SpringModuleDefTest.java /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryExternalSpringContextIntegrationTest.java /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1 /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/pages /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/pages/Index.java /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/services /tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp1/services/AppModule.java /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1 /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/Index.tml /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/WEB-INF /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/WEB-INF/applicationContext.xml /tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp1/WEB-INF/web.xml
          Hide
          Igor Drobiazko added a comment -

          Thanks for the patch, Matt. I added some integration tests to prove that it works. Also backported the 5.3 maintenance branch.

          Show
          Igor Drobiazko added a comment - Thanks for the patch, Matt. I added some integration tests to prove that it works. Also backported the 5.3 maintenance branch.
          Hide
          Matt Raible added a comment - - edited

          The attached patch solves this for me on trunk.

          Show
          Matt Raible added a comment - - edited The attached patch solves this for me on trunk.
          Hide
          Matt Raible added a comment -

          As suggested in the Nabble thread, changing SpringModuleDef.java from:

          private void addServiceDefsForSpringBeans(ApplicationContext context)
          {
          for (final String beanName : BeanFactoryUtils.beanNamesIncludingAncestors(context))

          { String trueName = beanName.startsWith("&") ? beanName.substring(1) : beanName; services.put(trueName, new SpringBeanServiceDef(trueName, context)); }

          }

          To:

          private void addServiceDefsForSpringBeans(ApplicationContext context)
          {
          for (final String beanName : context.getBeanDefinitionNames())

          { String trueName = beanName.startsWith("&") ? beanName.substring(1) : beanName; services.put(trueName, new SpringBeanServiceDef(trueName, context)); }

          }

          Does solve the problem.

          Show
          Matt Raible added a comment - As suggested in the Nabble thread, changing SpringModuleDef.java from: private void addServiceDefsForSpringBeans(ApplicationContext context) { for (final String beanName : BeanFactoryUtils.beanNamesIncludingAncestors(context)) { String trueName = beanName.startsWith("&") ? beanName.substring(1) : beanName; services.put(trueName, new SpringBeanServiceDef(trueName, context)); } } To: private void addServiceDefsForSpringBeans(ApplicationContext context) { for (final String beanName : context.getBeanDefinitionNames()) { String trueName = beanName.startsWith("&") ? beanName.substring(1) : beanName; services.put(trueName, new SpringBeanServiceDef(trueName, context)); } } Does solve the problem.
          Hide
          Matt Raible added a comment -

          If I try to run it w/o compatibility mode, I get the following error:

          org.apache.tapestry5.ioc.internal.OperationException: Error obtaining injected value for field org.appfuse.webapp.pages.admin.UserList.userManager: No service implements the interface org.appfuse.service.UserManager.

          The userManager bean is initialized by Spring using annotations:

          @Service("userManager")
          ...

          <!-- Activates scanning of @Service -->
          <context:component-scan base-package="org.appfuse.service"/>

          Here's how I'm wiring it up in my test:

          https://gist.github.com/1478384

          Show
          Matt Raible added a comment - If I try to run it w/o compatibility mode, I get the following error: org.apache.tapestry5.ioc.internal.OperationException: Error obtaining injected value for field org.appfuse.webapp.pages.admin.UserList.userManager: No service implements the interface org.appfuse.service.UserManager. The userManager bean is initialized by Spring using annotations: @Service("userManager") ... <!-- Activates scanning of @Service --> <context:component-scan base-package="org.appfuse.service"/> Here's how I'm wiring it up in my test: https://gist.github.com/1478384
          Hide
          Howard M. Lewis Ship added a comment -

          It's always a challenge to make these two things fit together. I believe you are running tapestry-spring in 5.0 compatibility mode, where it attempts to expose Spring beans as Tapestry services.

          We need to find a way to run tapestry-spring in its current mode (since 5.1), where Spring beans are injectable, but not services. This will defuse naming collisions, such as with "Environment", but may create some other issues, depending on what is inside your Spring application context.

          In some ways, I wish we had maintained the namespaced service ids that HiveMind had for Tapestry 4 (but namespaceds ids add their own complications); in the future will be services without ids, but that's a couple of release cycles away!

          Show
          Howard M. Lewis Ship added a comment - It's always a challenge to make these two things fit together. I believe you are running tapestry-spring in 5.0 compatibility mode, where it attempts to expose Spring beans as Tapestry services. We need to find a way to run tapestry-spring in its current mode (since 5.1), where Spring beans are injectable, but not services. This will defuse naming collisions, such as with "Environment", but may create some other issues, depending on what is inside your Spring application context. In some ways, I wish we had maintained the namespaced service ids that HiveMind had for Tapestry 4 (but namespaceds ids add their own complications); in the future will be services without ids, but that's a couple of release cycles away!

            People

            • Assignee:
              Igor Drobiazko
              Reporter:
              Matt Raible
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development