Announcement Announcement Module
Collapse
No announcement yet.
ResponseEntity<?> return type @ExceptionHandler method in 3.2.0.RC2 Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Make sure you have no web.xml with ContextLoaderListener registered.

    The onStartup() completes execution, but even though the DispatcherServlet is registered, requests aren't handled. It does not appear to be loading my @Controller "ServiceController".
    As expected as there is no @ComponentScan and as such your controllers aren't picked up (none of your beans are). Also if you get an exception, as you mention, nothing will be started.

    See the sample @Configuration class I posted yesterday! The @ComponentScan for the root context should contain an exclusion filter for @Controller.

    Code:
    @Configuration
    @ComponentScan(basePackages = {"your.base.package", excludeFilters = Filter{type=ANNOTATION, value=org.springframework.stereotype.Controller.class}}
    public static class AppConfig {}
    
    @Configuration
    @EnableWebMvc 
    @ComponentScan(basePackages = {"your.base.package", useDefaultFilters="false", includeFilters = Filter{type=ANNOTATION, value=org.springframework.stereotype.Controller.class}}
    public static class WebConfig extends WebMvcConfigurationSupport {
    
      protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable(); // Needed because we map DispatcherServlet to /
      }
    }
    Also as mentioned in that same post I suggest using one of the convenience classes (AbstractAnnotationConfigDispatcherServletInitiali zer ) from Spring instead of implementing the interface yourself.

    Comment


    • #17
      Originally posted by Marten Deinum View Post
      Make sure you have no web.xml with ContextLoaderListener registered.
      Yep there are no .xml files at all. This might be a bug in resin (maybe it's aggressively instantiating all ServletContextListener implementations it finds?); I've asked those guys to clarify.

      As expected as there is no @ComponentScan and as such your controllers aren't picked up (none of your beans are). Also if you get an exception, as you mention, nothing will be started.
      Ah, right. I keep thinking @EnableWebMvc does the scanning. Before, when I had this in .xml files, adding the component-scan caused issues. Is that because it wasn't filtering?

      Based on your example, I want to exclude @Controllers from the AppConfig, but include only @Controllers in the WebConfig. This seems a little cumbersome, but at least there's a solution.

      As an aside, wouldn't I just want to combine the Web and App contexts and configurations (and class scanning) into one thing?

      Also as mentioned in that same post I suggest using one of the convenience classes (AbstractAnnotationConfigDispatcherServletInitiali zer ) from Spring instead of implementing the interface yourself.
      Thanks for all your help so far, Marten. You did mention that, but the way I interpreted the docs, I thought I was missing out on something automatic if I did that. There really should be a new paragraph for that last line in that section.

      My new initializer class looks like this:

      Code:
      public
      class
      WebappInitializer extends org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer
      {
          @Override
          public
          void
          onStartup(ServletContext inContainer)
              throws
                  javax.servlet.ServletException
          {
              sLogger.debug("enter onStartup");
              super.onStartup(inContainer);
              sLogger.debug("done");
          }
          
          protected
          Class<?>[]
          getRootConfigClasses()
          {
              Class<?>[] classes = { AppConfig.class };
              return classes;
          }
          
          protected
          Class<?>[]
          getServletConfigClasses()
          {
              Class<?>[] classes = { WebConfig.class };
              return classes;
          }
          
          protected
          java.lang.String[]
          getServletMappings()
          {
              String[] mappings = { "/" };
              return mappings;
          }
          
          @Configuration
          public
          static
          class
          AppConfig
          {
          }
          
          @EnableWebMvc
          @Configuration
          public
          static
          class
          WebConfig
          {
          }
      }
      I'll add the @ComponentScan after I resolve the ContextLoaderListener issue (baby steps).

      Comment


      • #18
        Things are getting closer. I've added @ComponentScan, and according to the logging it's instantiating my controllers and wiring up my model objects and DAOs, but it's still not mapping requests. I still have to figure out how to properly instantiate the sessionFactory and set up the transaction stuff, but for now I just want to get the mapping to work.

        I see this in the logs:

        Code:
        03:03:59.233 DEBUG web.servlet.handler.AbstractDetectingUrlHandlerMapping (AbstractDetectingUrlHandlerMapping.java:71) Looking for URL mappings in application context: WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Dec 13 03:03:58 PST 2012]; parent: Root WebApplicationContext
        ...
        03:03:59.235 DEBUG web.servlet.handler.AbstractDetectingUrlHandlerMapping (AbstractDetectingUrlHandlerMapping.java:86) Rejected bean name 'mainController': no URL paths identified
        03:03:59.235 DEBUG web.servlet.handler.AbstractDetectingUrlHandlerMapping (AbstractDetectingUrlHandlerMapping.java:86) Rejected bean name 'serviceController': no URL paths identified
        ...
        even though a little earlier in the logs I have this:

        Code:
        ...
        03:03:59.174 INFO  web.servlet.handler.AbstractHandlerMethodMapping (AbstractHandlerMethodMapping.java:186) Mapped "{[/ || /Main],methods=[GET || HEAD],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.latencyzero.gamecenter.web.MainController.main()
        03:03:59.181 INFO  web.servlet.handler.AbstractHandlerMethodMapping (AbstractHandlerMethodMapping.java:186) Mapped "{[/service/],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json;charset=UTF-8],custom=[]}" onto public org.springframework.http.ResponseEntity<java.lang.String> com.latencyzero.gamecenter.web.ServiceController.getRoot() throws java.lang.Exception
        ...

        Comment


        • #19
          Which means that they are mapped...

          There are several HandlerMappings defined which try to detect mapping information, some apply others don't so there is mapping...

          Check the logs for what is happening which request is handled and why it isn't found. Probably the url doesn't match make sure that the servlet mapping is the same as you previously had in your web.xml...

          Comment


          • #20
            Originally posted by Marten Deinum View Post
            Check the logs for what is happening which request is handled and why it isn't found. Probably the url doesn't match make sure that the servlet mapping is the same as you previously had in your web.xml...
            Yeah, in my web.xml I had <url-pattern>/</url-pattern>, and you can see above I return a single mapping "/".

            By the way, what's the new @WebAppConfiguration and @ContextConfiguration for my test class (that will go through the annotation-based configuration)?

            Thanks!

            Comment


            • #21
              Okay, turns out that the servlet 3.0 spec says that addMapping() doesn't override already-existing mappings. Resin puts in a default mapping for "/", and so I can't override it (they'll fix that in a future release). But something like "/*" works.

              I'm now looking to see how to convert the following XML into annotations.

              Code:
              <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  <property name="dataSource" ref="dataSource"/>
                  <property name="packagesToScan" value="com.foo.bar.model"/>
                  <property name="hibernateProperties">
                      <props>
                          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          <prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
                          <prop key="hibernate.jdbc.batch_size">20</prop>
                          <prop key="hibernate.show_sql">false</prop>
                          <prop key="hibernate.format_sql">true</prop>
                          <prop key="hibernate.use_sql_comments">false</prop>
                          <prop key="hibernate.generate_statistics">true</prop>
                      </props>
                  </property>
              </bean>
              
              <bean id="transactionManager"
                  class="org.springframework.orm.hibernate3.HibernateTransactionManager"
                  p:sessionFactory-ref="sessionFactory" />
              I can just create it, something like this:

              Code:
              @Configuration
              @ComponentScan(basePackages = { "com.foo.bar.model", "com.foo.bar.dao" },
                              excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Controller.class) })
              public static class AppConfig
              {
                  @Bean
                  public
                  org.springframework.jndi.JndiObjectFactoryBean
                  dataSource()
                  {
                      org.springframework.jndi.JndiObjectFactoryBean bean = new org.springframework.jndi.JndiObjectFactoryBean();
                      bean.setJndiName("java:comp/env/jdbc/db");
                      return bean;
                  }
                  
                  @Bean
                  public
                  org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
                  sessionFactory()
                  {
                      DataSource dataSource = <get a data source, but how? Can I @Autowire?>;
                      org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean bean = new org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean();
                      bean.setDataSource(dataSource);
                      return bean;
                  }
              }
              But as you can see in the code, I'm not sure how to wire it to the data source. Moreover, I don't know if I need to scan any packages, since I've already scanned my model package in the AppConfig.

              I guess the general question is, how do I create my beans in code and access created beans in the context.

              You had suggested using org.springframework.web.servlet.config.annotation. WebMvcConfigurationSupport, but I'm trying to do this in my AppConfig, not my WebConfig, and I don't see an analogous class to inherit from for aid.

              Thanks!

              Comment


              • #22
                Ah. I finally found it in the docs: you can just refer to the @Bean methods, and it magically ensures that only a single instance is used (I think that's how I interpret it):

                http://static.springsource.org/sprin...g-dependencies

                Comment


                • #23
                  Everything is working now but my automated unit tests. I don't know how to convert the use of @WebAppConfiguration("file:target/build") and @ContextConfiguration({"file:target/build/WEB-INF/config/springContext.xml", "file:target/build/WEB-INF/config/springWebDispatcherConfig.xml"}) to use the servlet-3.0 annotation-based configuration (using my AbstractAnnotationConfigDispatcherServletInitializ er subclass), and using my AppConfig and WebConfig @Configuration classes.

                  I'm not sure it's even possible to configure spring-test-mvc this way. Is it?

                  Comment

                  Working...
                  X