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

  • ResponseEntity<?> return type @ExceptionHandler method in 3.2.0.RC2

    I just wrote up this bug: https://jira.springsource.org/browse/SPR-10090

    But I wanted to check here and make sure I'm not doing anything wrong. I have an @Controller class that defines an @ExceptionHandler that returns a ResponseEntity:

    Code:
    @ExceptionHandler(java.lang.Exception.class)
    public
    ResponseEntity<String>
    handleException(java.lang.Exception inEx)
    {
        ...
    }
    Pretty straightforward. But it throws an exception:

    Code:
    00:50:42.949 ERROR annotation.AnnotationMethodHandlerExceptionResolver (AnnotationMethodHandlerExceptionResolver.java:147) Invoking request method resulted in exception : public org.springframework.http.ResponseEntity com.latencyzero.gamecenter.web.ServiceController.handleException(java.lang.Exception)
    java.lang.IllegalArgumentException: Invalid handler method return value: <500 Internal Server Error,{"resultMsg":"Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Cannot open connection","result":1},{Content-Type=[application/json;charset=UTF-8]}>
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver.getModelAndView(AnnotationMethodHandlerExceptionResolver.java:414)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver.doResolveException(AnnotationMethodHandlerExceptionResolver.java:144)
    	at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:136)
    	at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1148)
    	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:985)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:917)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:813)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:120)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:798)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:97)
    and the source code doesn't seem to be able to handle anything that doesn't turn into a ModelAndView. However, the docs are pretty clear that the RequestEntity return type is supported, and there are even other classes provided by Spring that do that.

    So, am I missing something? Thanks!

  • #2
    Your configuration is wrong... The AnnotationMethodHandlerExceptionResolver is indeed not supporting this it stems from the initial and first annotation-driven web mvc approach. You should be using the approriate exceptionhandler the ExceptionHandlerExceptionResolver.

    Either configure this explicitly or use the mvc:annotation-driven or @EnableWebMvc if you are using @Configuration for configuring your app.

    Note: According to the issue you modified the code, not sure why and also the @deprecated in the class should have been an indicator that you shouldn't use this class.

    Note2: The other case you linked to also mention the appropriate class to use.

    So please do a bit more/better investigation next time before raising a bug!
    Last edited by Marten Deinum; Dec 12th, 2012, 04:52 AM. Reason: Fixed URL link.

    Comment


    • #3
      Thanks for pointing that out.

      So please do a bit more/better investigation next time before raising a bug!
      Seriously? Dude, people here aren't very clear about stuff. I'm extraordinarily busy trying to get my app to work. I spent a lot of time trying to figure this out, something I didn't need to do, but got curious. IT IS NOT CLEAR what needs to be done to make things work. I read the docs on the classes and and the bug, and it was NOT CLEAR from either exactly what I had to do, especially in the context of a move from code that originated back in the 2.5 days. Even your post is not entirely clear. What is "mvc:annotation-driven"? As opposed to what? Obviously my code is annotation-driven, but if I'm not using "mvc:annotation-driven" then I must be using something else. You could be a lot more helpful by indicating what need to look for to change it. Now I gotta dig through the web to find the answer. Had the docs been clear in the first place, I might not've had to do any of this.

      But the docs lead me toward @ControllerAdvice, which is not what I wanted.

      Note that I haven't modified any code but my own copy, and provided the changes. I didn't notice the @deprecated in there, or I would not have wasted my time.

      Comment


      • #4
        What is "mvc:annotation-driven"? As opposed to what? Obviously my code is annotation-driven, but if I'm not using "mvc:annotation-driven" then I must be using something else
        I suggest a read of the reference guide (this is the 3.1 link because 3.2 isn't final yet). Which explains what is mvc:annotation-driven and what is registered when you use that. There is also a brief explanation of the DispatcherServlet defaults.

        When doing an upgrade I tend to read the documentation of the new product at least the section that are relevant. But that could just be me.

        it was NOT CLEAR from either exactly what I had to do
        The comment I linked to gives you the classes which provide the support you want and explains what you need to do.

        But to be short and solve your problem add mvc:annotation-driven to your dispatcher servlet context file.

        Comment


        • #5
          When doing an upgrade I tend to read the documentation of the new product at least the section that are relevant. But that could just be me.
          That can be a LOT of reading for something like Spring. And I find it very easy to completely forget about the one-time configuration I did way back when, so I wouldn't even know that there was something to go look at. More helpful would've been logging as the code executes indicating I'm using deprecated classes and pointing me at documentation summarizing the changes (rather than having to read through long docs to find the one bit that I need).

          But to be short and solve your problem add mvc:annotation-driven to your dispatcher servlet context file.
          Thank you. I'm reading the docs now. It's still not entirely clear, but it has revealed other things that need to be updated. I'm tired and I've wasted a lot of time with this issue (which of course manages to only come up now). Hopefully it'll be resolved soon.

          Comment


          • #6
            Argh, nope, still not clear. This doc pretty explicitly states I can choose either annotation-based ("Java config") OR XML. It does not say I need both.

            But if I have no .xml file, I get an ERROR exception logged at startup and it fails to initialize the context. Do I just put an empty XML file there? Inelegant, at best.

            Comment


            • #7
              Argh, nope, still not clear. This doc pretty explicitly states I can choose either annotation-based ("Java config") OR XML. It does not say I need both.
              Correct, whwhich one to use depends on your configuration means XML or Java... As you are migrating from 2.5 I suspect you are using xml.. So which file is loaded by the DispatcherServlet add mvc:annotation-driven in there. You must be configuring your MVC somewhere or at least have a context-component-scan somewhere (to pickup your @Controllers)...

              Comment


              • #8
                Originally posted by Marten Deinum View Post
                Correct, whwhich one to use depends on your configuration means XML or Java... As you are migrating from 2.5 I suspect you are using xml.. So which file is loaded by the DispatcherServlet add mvc:annotation-driven in there. You must be configuring your MVC somewhere or at least have a context-component-scan somewhere (to pickup your @Controllers)...
                My web.xml passed a "contextConfigLocation" param to the DispatcherServlet. All the examples in the code don't show that, because it will look in the default location, but I had moved mine. Unfortunately, it seems that one is required to have an XML file, which is not consistent with the documentation.

                Anyway, I'm trying to configure my app from first principles, and looking at examples online, some people seem to be combining the general context configuration with their web configuration. My context is configured with a "contextConfigLocation" <context-param> in my web.xml, and org.springframework.web.context.ContextLoaderListe ner. The docs for that suggest using SpringServletContainerInitializer, which is instantiated by a servlet-3.0 container, so I'm trying to update my servlet-2.5 web.xml to servlet-3.0 standards (which also seems to use annotations for configuration). It's an incredibly tedious process to find all this information and make sure I'm doing it "right."

                Comment


                • #9
                  I wouldn't upgrade your web.xml and simply stick to your current configuration and simply add mvc:annotation-driven there. Don't do everything at once, make it work and later decide to change your configuration. (Moving to a 3.0 configuration will only work in a 3.0 container so it also means that you have to make sure your container is compatible).

                  You also don't have to have an xml file it depends in which WebApplicationContext class you use and the default is to use a WebXmlApplicationContext instance which, as the name suggests, reads an xml file. I like convention over configuration so most people stick with the default ([servletname]-context.xml). I strongly suggest you simply add mvc:annotation-driven there (after adding the namespace declaration)...

                  As mentioned before the only thing you are missing is the mvc:annotation-driven, imho it is pretty stupid to rewrite your whole configuration just to add this line.

                  Comment


                  • #10
                    Originally posted by Marten Deinum View Post
                    I strongly suggest you simply add mvc:annotation-driven there (after adding the namespace declaration)...
                    I did. It didn't work. That is, none of my endpoints could be found. So I re-added the <context:component-scan base-package=...> that I had in there before, because it wasn't creating my @Controller. That helped, but then something else went wrong, exceptions about not being able to cast something to something else. Googling suggested that was cause by a conflict between mvc:annotation-driven and the package scan. One thing led to another, and now I'm upgrading to servlet 3.0.

                    I'm using Resin 4.0.32, it's servlet-3.0 compliant.

                    But of course, it's not working properly, either. I got rid of web.xml, and according to what I read, Spring should have a dispatcher automatically instantiated, but it's not yet happening. I'm sure I'm missing some Java glue in there.

                    Comment


                    • #11
                      mvc:annotation-driven needs to be used next to the component-scan (unless you configure all your @Controllers by hand)... It isn't a replacement...

                      There aren't any conflicts I know about between the 2... Could you post the stacktrace? Switching to java based configuration shouldn't solve the problem because you still need component-scan and annotation-driven (@ComponentScan and @EnableWebMvc) ... So that isn't the solution...

                      And could you also post your original configuration and maybe a controller? (There might be something conflicting in there!).

                      One thing about the component-scan (and you wouldn't be the first to fall in that trap) is that there is also one in the ContextLoaderLIstener with the same base package which leads to duplication of all your beans! A rule of thumb your component-scan for the dispatcherservlet should (in general) only be scanning for @Controllers (in short disable default filters and add a include-filter for the Controller annotation). And your ContextLoaderListener for anything BUT @Controller (simply include an exclusion for @Controller).
                      Last edited by Marten Deinum; Dec 12th, 2012, 06:06 AM. Reason: Add component-scan note.

                      Comment


                      • #12
                        I've departed pretty far from what I had.

                        Can you clarify: should I be able to completely do away with the servlet.xml config file, and use annotations only? Or MUST I have mvc:annotation-driven in there? Like I said, the docs suggest it's either-or. What I'm reading here implies I don't need both.

                        Comment


                        • #13
                          I'm going to give the default consultant answer it depends... For the mvc part you don't need an xml file you can create a class annotate it with @Configuration and add @EnableWebMvc (the jva config alternative to mvc:annotation-driven)... I suggest you also let that class extend WebMvcConfigurationSupport which makes it easier to modify the default settings or extend on them.

                          Basically with Servlet 3.0 and Spring 3.x you can create a xml less application. However depending on the other spring products you use YMMV as not all spring products have a full java configuration option yet. (Spring Web Flow and Spring Batch for instance ) then you still need an xml file for that part of the configuration.

                          Sample (from the top of my head).
                          Code:
                          @Configuration
                          @EnableWebMvc
                          @ComponentScan(basePackages = {"your.base.package", useDefaultFilters=false, filters = Filter{type=ANNOTATION, value=org.springframework.stereotype.Controller.class}}
                          public class WebContextConfiguration extends WebMvcConfigurationSupport {
                          
                          }
                          Initializer
                          Code:
                          public class MyApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
                          
                            protected Class[] getRootConfigClasses() {
                              return new Class[] { RootContext.class}; // Or whatever you called it
                            }
                            
                          
                            protected Class[] getServletConfigClasses() {
                              return new Class[] {WebContextConfiguration.class}; // Or whatever you called it
                            }
                          
                          
                          }

                          Comment


                          • #14
                            I'm trying to implement it as described under "A 100% code-based approach to configuration" here: http://static.springsource.org/sprin...itializer.html

                            So far, my container spits out:

                            [12-12-12 04:28:22.086] {main} WebApp[production/webapp/default/ROOT,STARTING] No Spring WebApplicationInitializer types detected on classpath

                            It's 4:30 am. I'm going to bed.

                            Comment


                            • #15
                              Marten,

                              I've gotten past the servlet-3.0 stuff. My org.springframework.web.WebApplicationInitializer is being configured now, but I'm having trouble configuring Spring as described in "A 100% code-based approach to configuration". But I get an exception "Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!".

                              The exception occurs when I try to create and register the ContextLoaderListener.

                              I have a class that looks like this (which is almost identical to the one in the docs):

                              Code:
                              public
                              class
                              WebappInitializer implements org.springframework.web.WebApplicationInitializer
                              {
                                  @Override
                                  public
                                  void
                                  onStartup(ServletContext inContainer)
                                  {
                                      sLogger.debug("enter onStartup");
                                      
                                      //  Create the root Spring application context…
                                      
                                      sLogger.debug("Create and register rootContext");
                                      
                                      AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
                                      rootContext.register(AppConfig.class);
                              
                                      //  Manage the lifecycle of the root application context…
                                      
                                      sLogger.debug("Create and register ContextLoaderListener");
                                      
                                      //  Exception occurs here:
                                      inContainer.addListener(new ContextLoaderListener(rootContext));
                              
                                      // Create the dispatcher servlet's Spring application context…
                                      
                                      sLogger.debug("Create and register dispatchContext");
                                      
                                      AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
                                      dispatcherContext.register(WebConfig.class);
                              
                                      //  Register and map the dispatcher servlet…
                                      
                                      sLogger.debug("Create dispatcher");
                                      
                                      ServletRegistration.Dynamic dispatcher = inContainer.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
                                      dispatcher.setLoadOnStartup(2);
                                      dispatcher.addMapping("/");
                                      
                                      sLogger.debug("done");
                                  }
                                  
                                  @Configuration
                                  public
                                  static
                                  class
                                  AppConfig
                                  {
                                  }
                                  
                                  @EnableWebMvc
                                  @Configuration
                                  public
                                  static
                                  class
                                  WebConfig
                                  {
                                  }
                              }
                              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".

                              Comment

                              Working...
                              X