spring-projects / spring-projects/spring-boot

Views for different contenttypes cannot be resolved anymore.

Open
#13,424 3 comments 1 reaction 1 assignee View on GitHub

@bclozel is already working on this.

Since Jun 12, 2018.

status: feedback-provided
Dominant language
Java
Stars
81.5k
Forks
42.7k
Avg merge
2d 4h
Merged PRs (30d)
65

Description

Find full demo and failing test attached:
demo.zip

Given the following controller

@Controller
public class SomeController {
	@GetMapping(value = "/", produces = {MediaType.TEXT_HTML_VALUE, MediaType.APPLICATION_ATOM_XML_VALUE, "text/csv"})
	public String someView() {
		return "someView";
	}
}

I can have multiple views providing the requested content types. For example an atom and a csv view:

@Component("someView.csv")
class SomeCSVView extends AbstractView {
	public SomeCSVView() {
		super.setContentType("text/csv");
	}

	@Override
	protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) throws Exception {
		response.setContentType(UTF_8.name());
		try(Writer out = new OutputStreamWriter(response.getOutputStream(), UTF_8)) {
			out.write("this;is;a;test\n");
		}
		response.flushBuffer();
	}
}

@Component("someView.atom")
class SomeAtomView extends AbstractAtomFeedView {

	@Override
	protected List<Entry> buildFeedEntries(Map<String, Object> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
		final Entry entry = new Entry();
		entry.setTitle("This is a test");
		return Arrays.asList(entry);
	}
}

In addition to that I have to configure unknown media types as so

spring.mvc.content-negotiation.media-types.atom = application/atom+xml
spring.mvc.content-negotiation.media-types.csv = text/csv

I expect that the views are correctly resolved depending on the media type given through the accept header. However, only the text/html gets resolved (for example as an answer to ` curl -v -H "Accept: application/atom+xml" localhost:8080).

This does not work anymore since 2.0.0.RC1, as the new Path Matching and Content Negotiation break ContentNegotiatingViewResolver.

The official? (or at least usual) way to name the different views was "name.ext". That worked as shown above in 1.x and in 2 until 2.0.0.RC1, where those changes have been introduced.

Those changes are fine, but they break ContentNegotiatingViewResolver. In org.springframework.web.servlet.view.ContentNegotiatingViewResolver#getCandidateViews it uses a ContentNegotiationManager. String viewNameWithExtension = viewName + '.' + extension; pretty much assures me that naming the views as above has been correct.

However, the ContentNegotiationManagercannot resolve any extension in resolveFileExtensions because there is no more MediaTypeFileExtensionResolver as spring.mvc.content-negotiation.favor-path-extension is false since 2.0.0.RC1.

I would understand the the failure if I requested /someView.atom but I'm using the accept header as shown in the test.

Workaround is to set favor to true, but that is not recommend for good reasons.

Another one is to provide a bean post processor like this

@Bean
	public BeanPostProcessor contentNegotiationManagerPostProcessor(final WebMvcProperties webMvcProperties) {
		return new BeanPostProcessor() {
			@Override
			public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
				if(ContentNegotiationManager.class.isInstance(bean)) {
					((ContentNegotiationManager)bean)
						.addFileExtensionResolvers(new MappingMediaTypeFileExtensionResolver(webMvcProperties.getContentnegotiation().getMediaTypes()));
				}
				return bean;
			}
		};
	}

and that would be something I expect from Boot itself.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.