Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-13559

<mvc:view-resolvers> does not reliably find declared ContentNegotiationManager

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: 4.1.7, 4.2.1
    • Fix Version/s: 4.1.9, 4.2.3
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      In the following, does the ContentNegotiatingViewResolver created by <mvc:view-resolvers> automatically get set with the mvcContentNegotiationManager? My tests are telling me not.

      	<mvc:annotation-driven
      		content-negotiation-manager="mvcContentNegotiationManager" />
       
      	<!-- View resolver chain -->
      	<mvc:view-resolvers>
      		<mvc:content-negotiation use-not-acceptable="true" />
      		<mvc:bean-name />
      		<mvc:tiles />
      		<bean class="rewardsonline.accounts.JsonViewResolver" />
      	</mvc:view-resolvers>
       
      	<bean id="mvcContentNegotiationManager"
      		class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
      		<property name="ignoreAcceptHeader" value="true" />
      		<property name="defaultContentType" value="text/html" />
      	</bean>
      

      Running this as a servlet app does work, but my MockMvc test fails trying to generate JSON.

      If I explicitly get the ContentNegotiatingViewResolver when the test starts and manually set the ContentNegotiationManager to mvcContentNegotiationManager, it works.

      I would expect the CNVR created using <mvc:view-resolvers/> to be initialised with the same ContentNegotiationManager that was specified to <mvc:annotation-driven>.

        Activity

        Hide
        rstoya05-aop Rossen Stoyanchev added a comment -

        What version are you using? Also could you provide some details on how your tests indicate what CNVC is used?

        Show
        rstoya05-aop Rossen Stoyanchev added a comment - What version are you using? Also could you provide some details on how your tests indicate what CNVC is used?
        Hide
        chapmanp Paul Chapman added a comment - - edited

        I am using Spring V4.2.0.RELEASE.

        The code I wrote did the following:

        1. Fetched the one and only view-resolver the application context. - turns out to be a ViewResolverComposite.
        2. Iterates over its view-resolvers to find the CNVR
        3. Found the one and only `ContentNegotiationManager` in the application context.
        4. Used reflection to access the `contentNegotiationManager` inside the CNVR
        5. Checked to see if the two `ContentNegotiationManagers` were the same instance - they weren't
        6. Used `cnvr.setContentNegotiationManager(contentNegotiationManager)` to set the `ContentNegotiationManager `in the CNVR instance to eb the one in the application context.

        After that, when I ran my `MockMvc` test to fetch JSON, I did get JSON returned. Before it was returning HTML and my test failed - I think because the original `ContentNegotiationManager` in the CNVR instance was not the one I had configured to look for .json on the end of the URL.

        Show
        chapmanp Paul Chapman added a comment - - edited I am using Spring V4.2.0.RELEASE. The code I wrote did the following: Fetched the one and only view-resolver the application context. - turns out to be a ViewResolverComposite. Iterates over its view-resolvers to find the CNVR Found the one and only `ContentNegotiationManager` in the application context. Used reflection to access the `contentNegotiationManager` inside the CNVR Checked to see if the two `ContentNegotiationManagers` were the same instance - they weren't Used `cnvr.setContentNegotiationManager(contentNegotiationManager)` to set the `ContentNegotiationManager `in the CNVR instance to eb the one in the application context. After that, when I ran my `MockMvc` test to fetch JSON, I did get JSON returned. Before it was returning HTML and my test failed - I think because the original `ContentNegotiationManager` in the CNVR instance was not the one I had configured to look for .json on the end of the URL.
        Hide
        rstoya05-aop Rossen Stoyanchev added a comment -

        It appears this is sensitive to where the "mvcContentNegotiationManager" bean appears. It works if it is before <mvc:view-resolvers>.

        On the implementation side, ViewResolversBeanDefinitionParser is checking if context.getRegistry().containsBeanDefinition(beanName) where beanName is "mvcContentNegotiationManager". Two issues here, one it shouldn't be sensitive to the order of declaration and two it should work in cases where a ContentNegotiationManager is configured with a bean reference, i.e.:

        <mvc:annotation-driven content-negotiation-manager="myManager" />
        <bean id="myManager" class="..." />
        

        Show
        rstoya05-aop Rossen Stoyanchev added a comment - It appears this is sensitive to where the "mvcContentNegotiationManager" bean appears. It works if it is before <mvc:view-resolvers> . On the implementation side, ViewResolversBeanDefinitionParser is checking if context.getRegistry().containsBeanDefinition(beanName) where beanName is "mvcContentNegotiationManager". Two issues here, one it shouldn't be sensitive to the order of declaration and two it should work in cases where a ContentNegotiationManager is configured with a bean reference, i.e.: < mvc :annotation-driven content-negotiation-manager = "myManager" /> < bean id = "myManager" class = "..." />

          People

          • Assignee:
            rstoya05-aop Rossen Stoyanchev
            Reporter:
            chapmanp Paul Chapman
            Last updater:
            St├ęphane Nicoll
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              2 years, 18 weeks, 5 days ago