Update view-resolver namespace

Issue: SPR-7093
This commit is contained in:
Rossen Stoyanchev 2014-07-12 22:19:18 -04:00
parent f54cee47b0
commit 5e1a5c8d51
16 changed files with 730 additions and 576 deletions

View File

@ -146,9 +146,10 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
*/
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
public static final String CONTENT_NEGOTIATION_MANAGER_BEAN_NAME = "mvcContentNegotiationManager";
private static final boolean javaxValidationPresent = ClassUtils.isPresent(
"javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static boolean romePresent =
ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
@ -354,7 +355,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
factoryBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
factoryBeanDef.getPropertyValues().add("mediaTypes", getDefaultMediaTypes());
String beanName = "mvcContentNegotiationManager";
String beanName = CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
parserContext.getReaderContext().getRegistry().registerBeanDefinition(beanName , factoryBeanDef);
parserContext.registerComponent(new BeanComponentDefinition(factoryBeanDef, beanName));
contentNegotiationManagerRef = new RuntimeBeanReference(beanName);

View File

@ -0,0 +1,66 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.List;
/**
* Parse the <mvc:velocity> MVC namespace element and register
* FreeMarkerConfigurer bean
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class FreeMarkerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
public static final String BEAN_NAME = "mvcFreeMarkerConfigurer";
@Override
protected String getBeanClassName(Element element) {
return "org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer";
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return BEAN_NAME;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
List<Element> childElements = DomUtils.getChildElementsByTagName(element, "template-loader-path");
if (!childElements.isEmpty()) {
List<String> locations = new ArrayList<String>(childElements.size());
for (Element childElement : childElements) {
locations.add(childElement.getAttribute("location"));
}
if (locations.isEmpty()) {
locations.add("/WEB-INF/");
}
builder.addPropertyValue("templateLoaderPaths", locations.toArray(new String[locations.size()]));
}
}
}

View File

@ -35,7 +35,10 @@ public class MvcNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolution", new ViewResolutionBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles", new TilesBeanDefinitionParser());
registerBeanDefinitionParser("freemarker", new FreeMarkerBeanDefinitionParser());
registerBeanDefinitionParser("velocity", new VelocityBeanDefinitionParser());
}
}

View File

@ -50,6 +50,7 @@ abstract class MvcNamespaceUtils {
private static final String PATH_MATCHER_BEAN_NAME = "mvcPathMatcher";
public static void registerDefaultComponents(ParserContext parserContext, Object source) {
registerBeanNameUrlHandlerMapping(parserContext, source);
registerHttpRequestHandlerAdapter(parserContext, source);

View File

@ -0,0 +1,75 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.List;
/**
* Parse the <mvc:tiles> MVC namespace element and register
* TilesConfigurer bean
* @author Rossen Stoyanchev
* @since 4.1
*/
public class TilesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
public static final String BEAN_NAME = "mvcTilesConfigurer";
@Override
protected String getBeanClassName(Element element) {
return "org.springframework.web.servlet.view.tiles3.TilesConfigurer";
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return BEAN_NAME;
}
@Override
protected boolean shouldGenerateId() {
return super.shouldGenerateId();
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
List<Element> childElements = DomUtils.getChildElementsByTagName(element, "definitions");
if (!childElements.isEmpty()) {
List<String> locations = new ArrayList<String>(childElements.size());
for (Element childElement : childElements) {
locations.add(childElement.getAttribute("location"));
}
builder.addPropertyValue("definitions", locations.toArray(new String[locations.size()]));
}
if (element.hasAttribute("check-refresh")) {
builder.addPropertyValue("checkRefresh", element.getAttribute("check-refresh"));
}
if (element.hasAttribute("validate-definitions")) {
builder.addPropertyValue("validateDefinitions", element.getAttribute("validate-definitions"));
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* Parse the <mvc:velocity> MVC namespace element and register an
* VelocityConfigurer bean
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class VelocityBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
public static final String BEAN_NAME = "mvcVelocityConfigurer";
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return BEAN_NAME;
}
@Override
protected String getBeanClassName(Element element) {
return "org.springframework.web.servlet.view.velocity.VelocityConfigurer";
}
@Override
protected boolean isEligibleAttribute(String attributeName) {
return attributeName.equals("resource-loader-path");
}
@Override
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
if (!builder.getBeanDefinition().hasAttribute("resourceLoaderPath")) {
builder.getBeanDefinition().setAttribute("resourceLoaderPath", "/WEB-INF/");
}
}
}

View File

@ -1,252 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
import org.w3c.dom.Element;
/**
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
* {@code view-resolution} element to register a set of {@link ViewResolver} definitions.
*
* @author Sivaprasad Valluru
* @author Sebastien Deleuze
* @since 4.1
*/
public class ViewResolutionBeanDefinitionParser implements BeanDefinitionParser {
private Object source;
public BeanDefinition parse(Element element, ParserContext parserContext) {
source= parserContext.extractSource(element);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(),source);
parserContext.pushContainingComponent(compDefinition);
List<Element> viewResolverElements =
DomUtils.getChildElementsByTagName(element, new String[] { "jsp", "tiles", "bean-name", "freemarker", "velocity", "bean", "ref" });
ManagedList<Object> viewResolvers = new ManagedList<Object>();
viewResolvers.setSource(parserContext.extractSource(element));
int order = 0;
for (Element viewResolverElement : viewResolverElements) {
if ("jsp".equals(viewResolverElement.getLocalName())) {
viewResolvers.add(registerInternalResourceViewResolverBean(viewResolverElement, parserContext, order));
}
if("bean-name".equals(viewResolverElement.getLocalName())){
viewResolvers.add(registerBeanNameViewResolverBean(viewResolverElement, parserContext, order));
}
if ("tiles".equals(viewResolverElement.getLocalName())) {
viewResolvers.add(registerTilesViewResolverBean(viewResolverElement, parserContext, order));
registerTilesConfigurerBean(viewResolverElement, parserContext);
}
if("freemarker".equals(viewResolverElement.getLocalName())){
viewResolvers.add(registerFreemarkerViewResolverBean(viewResolverElement, parserContext, order));
registerFreemarkerConfigurerBean(viewResolverElement, parserContext);
}
if("velocity".equals(viewResolverElement.getLocalName())){
viewResolvers.add(registerVelocityViewResolverBean(viewResolverElement, parserContext, order));
registerVelocityConfigurerBean(viewResolverElement, parserContext);
}
if("bean".equals(viewResolverElement.getLocalName()) || "ref".equals(viewResolverElement.getLocalName())){
viewResolvers.add(parserContext.getDelegate().parsePropertySubElement(viewResolverElement, null));
}
order++;
}
viewResolverElements = DomUtils.getChildElementsByTagName(element, new String[] { "content-negotiating" });
if(!viewResolverElements.isEmpty()) {
registerContentNegotiatingViewResolverBean(viewResolverElements.get(0), parserContext, viewResolvers);
}
parserContext.popAndRegisterContainingComponent();
return null;
}
private BeanDefinition registerBean(Map<String,Object> propertyMap,Class<?> beanClass, ParserContext parserContext ){
RootBeanDefinition beanDef = new RootBeanDefinition(beanClass);
beanDef.setSource(source);
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
for(String propertyName:propertyMap.keySet()){
beanDef.getPropertyValues().add(propertyName, propertyMap.get(propertyName));
}
String beanName = parserContext.getReaderContext().generateBeanName(beanDef);
parserContext.getRegistry().registerBeanDefinition(beanName, beanDef);
parserContext.registerComponent(new BeanComponentDefinition(beanDef, beanName));
return beanDef;
}
private BeanDefinition registerContentNegotiatingViewResolverBean(Element viewResolverElement, ParserContext parserContext, ManagedList<Object> viewResolvers) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
ManagedList<Object> defaultViewBeanDefinitions = new ManagedList<Object>();
List<Element> defaultViewElements =
DomUtils.getChildElementsByTagName(viewResolverElement, new String[] { "default-views" });
if(!defaultViewElements.isEmpty()) {
for(Element beanElem : DomUtils.getChildElementsByTagName(defaultViewElements.get(0), "bean", "ref")) {
defaultViewBeanDefinitions.add(parserContext.getDelegate().parsePropertySubElement(beanElem, null));
}
}
if(viewResolverElement.hasAttribute("use-not-acceptable")) {
propertyMap.put("useNotAcceptableStatusCode", viewResolverElement.getAttribute("use-not-acceptable"));
}
if(viewResolverElement.hasAttribute("manager")) {
propertyMap.put("contentNegotiationManager", new RuntimeBeanReference(viewResolverElement.getAttribute("manager")));
} else {
propertyMap.put("contentNegotiationManager", new RuntimeBeanReference("mvcContentNegotiationManager"));
}
if(viewResolvers != null && !viewResolvers.isEmpty()) {
propertyMap.put("viewResolvers", viewResolvers);
}
if(defaultViewBeanDefinitions != null && !defaultViewBeanDefinitions.isEmpty()) {
propertyMap.put("defaultViews", defaultViewBeanDefinitions);
}
return registerBean(propertyMap, ContentNegotiatingViewResolver.class, parserContext);
}
private BeanDefinition registerFreemarkerConfigurerBean(Element viewResolverElement, ParserContext parserContext) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("template-loader-paths")) {
String[] paths = StringUtils.commaDelimitedListToStringArray(viewResolverElement.getAttribute("template-loader-paths"));
propertyMap.put("templateLoaderPaths", paths);
} else {
propertyMap.put("templateLoaderPaths", new String[]{"/WEB-INF/"});
}
return registerBean(propertyMap, FreeMarkerConfigurer.class, parserContext);
}
private BeanDefinition registerFreemarkerViewResolverBean(Element viewResolverElement, ParserContext parserContext, int order) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("prefix")) {
propertyMap.put("prefix", viewResolverElement.getAttribute("prefix"));
}
if(viewResolverElement.hasAttribute("suffix")) {
propertyMap.put("suffix", viewResolverElement.getAttribute("suffix"));
}
else {
propertyMap.put("suffix", ".ftl");
}
if(viewResolverElement.hasAttribute("cache")) {
propertyMap.put("cache", viewResolverElement.getAttribute("cache"));
}
propertyMap.put("order", order);
return registerBean(propertyMap, FreeMarkerViewResolver.class, parserContext);
}
private BeanDefinition registerVelocityConfigurerBean(Element viewResolverElement, ParserContext parserContext) {
String resourceLoaderPath = viewResolverElement.getAttribute("resource-loader-path");
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("resource-loader-path")) {
propertyMap.put("resourceLoaderPath", resourceLoaderPath);
} else {
propertyMap.put("resourceLoaderPath", "/WEB-INF/");
}
return registerBean(propertyMap, VelocityConfigurer.class, parserContext);
}
private BeanDefinition registerVelocityViewResolverBean(Element viewResolverElement, ParserContext parserContext, int order) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("prefix")) {
propertyMap.put("prefix", viewResolverElement.getAttribute("prefix"));
}
if(viewResolverElement.hasAttribute("suffix")) {
propertyMap.put("suffix", viewResolverElement.getAttribute("suffix"));
}
else {
propertyMap.put("suffix", ".vm");
}
if(viewResolverElement.hasAttribute("cache")) {
propertyMap.put("cache", viewResolverElement.getAttribute("cache"));
}
propertyMap.put("order", order);
return registerBean(propertyMap, VelocityViewResolver.class, parserContext);
}
private BeanDefinition registerBeanNameViewResolverBean(Element viewResolverElement, ParserContext parserContext, int order) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
propertyMap.put("order", order);
return registerBean(propertyMap, BeanNameViewResolver.class, parserContext);
}
private BeanDefinition registerTilesConfigurerBean(Element viewResolverElement, ParserContext parserContext) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("definitions")) {
String[] definitions = StringUtils.commaDelimitedListToStringArray(viewResolverElement.getAttribute("definitions"));
propertyMap.put("definitions", definitions);
}
if(viewResolverElement.hasAttribute("check-refresh")) {
propertyMap.put("checkRefresh", viewResolverElement.getAttribute("check-refresh"));
}
return registerBean(propertyMap, TilesConfigurer.class, parserContext);
}
private BeanDefinition registerTilesViewResolverBean(Element viewResolverElement, ParserContext parserContext, int order) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("prefix")) {
propertyMap.put("prefix", viewResolverElement.getAttribute("prefix"));
}
if(viewResolverElement.hasAttribute("suffix")) {
propertyMap.put("suffix", viewResolverElement.getAttribute("suffix"));
}
propertyMap.put("order", order);
return registerBean(propertyMap, TilesViewResolver.class, parserContext);
}
private BeanDefinition registerInternalResourceViewResolverBean(Element viewResolverElement, ParserContext parserContext, int order) {
Map<String, Object> propertyMap = new HashMap<String, Object>();
if(viewResolverElement.hasAttribute("prefix")) {
propertyMap.put("prefix", viewResolverElement.getAttribute("prefix"));
}
else {
propertyMap.put("prefix", "/WEB-INF/");
}
if(viewResolverElement.hasAttribute("suffix")) {
propertyMap.put("suffix", viewResolverElement.getAttribute("suffix"));
}
else {
propertyMap.put("suffix", ".jsp");
}
propertyMap.put("order", order);
return registerBean(propertyMap, InternalResourceViewResolver.class, parserContext);
}
}

View File

@ -0,0 +1,189 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Ordered;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.ViewResolverComposite;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
import org.w3c.dom.Element;
/**
* Parse the {@code view-resolvers} MVC namespace element and register
* {@link org.springframework.web.servlet.ViewResolver} bean definitions.
*
* <p>All registered resolvers are wrapped in a single (composite) ViewResolver
* with its order property set to 0 so that other external resolvers may be ordered
* before or after it.
*
* <p>When content negotiation is enabled the order property is set to highest priority
* instead with the ContentNeogitatingViewResolver encapsulating all other registered
* view resolver instances. That way the resolvers registered through the MVC namespace
* form self-encapsulated resolver chain.
*
* @author Sivaprasad Valluru
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @since 4.1
* @see org.springframework.web.servlet.config.TilesBeanDefinitionParser
* @see org.springframework.web.servlet.config.FreeMarkerBeanDefinitionParser
* @see org.springframework.web.servlet.config.VelocityBeanDefinitionParser
*/
public class ViewResolversBeanDefinitionParser implements BeanDefinitionParser {
public static final String VIEW_RESOLVER_BEAN_NAME = "mvcViewResolver";
public BeanDefinition parse(Element element, ParserContext context) {
Object source = context.extractSource(element);
context.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), source));
RootBeanDefinition compositeResolverBeanDef = new RootBeanDefinition(ViewResolverComposite.class);
compositeResolverBeanDef.setSource(source);
compositeResolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
ManagedList<Object> resolvers = new ManagedList<Object>(4);
resolvers.setSource(context.extractSource(element));
String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "bean", "ref"};
for (Element resolverElement : DomUtils.getChildElementsByTagName(element, names)) {
String name = resolverElement.getLocalName();
if ("bean".equals(name) || "ref".equals(name)) {
resolvers.add(context.getDelegate().parsePropertySubElement(resolverElement, null));
continue;
}
RootBeanDefinition resolverBeanDef = null;
if ("jsp".equals(name)) {
resolverBeanDef = new RootBeanDefinition(InternalResourceViewResolver.class);
resolverBeanDef.getPropertyValues().add("prefix", "/WEB-INF/");
resolverBeanDef.getPropertyValues().add("suffix", ".jsp");
addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
}
else if ("tiles".equals(name)) {
resolverBeanDef = new RootBeanDefinition(TilesViewResolver.class);
addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
}
else if ("freemarker".equals(name)) {
resolverBeanDef = new RootBeanDefinition(FreeMarkerViewResolver.class);
resolverBeanDef.getPropertyValues().add("suffix", ".ftl");
addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
}
else if ("velocity".equals(name)) {
resolverBeanDef = new RootBeanDefinition(VelocityViewResolver.class);
resolverBeanDef.getPropertyValues().add("suffix", ".vm");
addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
}
else if ("bean-name".equals(name)) {
resolverBeanDef = new RootBeanDefinition(BeanNameViewResolver.class);
}
else {
// Should never happen
throw new IllegalStateException("Unexpected element name: " + name);
}
resolverBeanDef.setSource(source);
resolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
resolvers.add(resolverBeanDef);
}
List<Element> elementList = DomUtils.getChildElementsByTagName(element, new String[] {"content-negotiation"});
if (elementList.isEmpty()) {
compositeResolverBeanDef.getPropertyValues().add("order", 0);
compositeResolverBeanDef.getPropertyValues().add("viewResolvers", resolvers);
}
else if (elementList.size() == 1) {
BeanDefinition beanDef = createContentNegotiatingViewResolver(elementList.get(0), context);
beanDef.getPropertyValues().add("viewResolvers", resolvers);
ManagedList<Object> list = new ManagedList<Object>(1);
list.add(beanDef);
compositeResolverBeanDef.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
compositeResolverBeanDef.getPropertyValues().add("viewResolvers", list);
}
else if (elementList.size() > 1) {
throw new IllegalArgumentException("Only one <content-negotiation> element is allowed.");
}
String beanName = VIEW_RESOLVER_BEAN_NAME;
context.getReaderContext().getRegistry().registerBeanDefinition(beanName, compositeResolverBeanDef);
context.registerComponent(new BeanComponentDefinition(compositeResolverBeanDef, beanName));
context.popAndRegisterContainingComponent();
return null;
}
private void addUrlBasedViewResolverProperties(Element element, RootBeanDefinition beanDefinition) {
if (element.hasAttribute("prefix")) {
beanDefinition.getPropertyValues().add("prefix", element.getAttribute("prefix"));
}
if (element.hasAttribute("suffix")) {
beanDefinition.getPropertyValues().add("suffix", element.getAttribute("suffix"));
}
if (element.hasAttribute("cache-views")) {
beanDefinition.getPropertyValues().add("cache", element.getAttribute("cache-views"));
}
if (element.hasAttribute("view-class")) {
beanDefinition.getPropertyValues().add("viewClass", element.getAttribute("view-class"));
}
if (element.hasAttribute("view-names")) {
beanDefinition.getPropertyValues().add("viewNames", element.getAttribute("view-names"));
}
}
private BeanDefinition createContentNegotiatingViewResolver(Element resolverElement, ParserContext context) {
RootBeanDefinition beanDef = new RootBeanDefinition(ContentNegotiatingViewResolver.class);
beanDef.setSource(context.extractSource(resolverElement));
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
MutablePropertyValues values = beanDef.getPropertyValues();
List<Element> elements = DomUtils.getChildElementsByTagName(resolverElement, new String[] {"default-views"});
if (!elements.isEmpty()) {
ManagedList<Object> list = new ManagedList<Object>();
for(Element element : DomUtils.getChildElementsByTagName(elements.get(0), "bean", "ref")) {
list.add(context.getDelegate().parsePropertySubElement(element, null));
}
values.add("defaultViews", list);
}
if (resolverElement.hasAttribute("use-not-acceptable")) {
values.add("useNotAcceptableStatusCode", resolverElement.getAttribute("use-not-acceptable"));
}
String beanName = AnnotationDrivenBeanDefinitionParser.CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
if (context.getRegistry().containsBeanDefinition(beanName)) {
values.add("contentNegotiationManager", new RuntimeBeanReference(beanName));
}
return beanDef;
}
}

View File

@ -220,6 +220,13 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
this.useNotAcceptableStatusCode = useNotAcceptableStatusCode;
}
/**
* Whether to return HTTP Status 406 if no suitable is found.
*/
public boolean isUseNotAcceptableStatusCode() {
return this.useNotAcceptableStatusCode;
}
/**
* Set the default views to use when a more specific view can not be obtained
* from the {@link ViewResolver} chain.

View File

@ -598,8 +598,43 @@
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="jsp-type">
<xsd:complexType name="contentNegotiationType">
<xsd:all>
<xsd:element name="default-views" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="beans:bean">
<xsd:annotation>
<xsd:documentation><![CDATA[
A bean definition for an org.springframework.web.servlet.View class.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="beans:ref">
<xsd:annotation>
<xsd:documentation><![CDATA[
A reference to a bean for an org.springframework.web.servlet.View class.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
<xsd:attribute name="use-not-acceptable" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicate whether a 406 Not Acceptable status code should be returned if no suitable
view can be found.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="urlViewResolverType">
<xsd:attribute name="prefix" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
@ -614,205 +649,208 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="tiles-type">
<xsd:attribute name="definitions" type="xsd:string">
<xsd:attribute name="cache-views" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
The Tiles definitions, i.e. a single value or a comma separated list of files containing the definitions.
Enable or disable thew caching of resolved views.
Default is "true": caching is enabled.
Disable this only for debugging and development.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="check-refresh" type="xsd:string">
<xsd:attribute name="view-class" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set whether to check Tiles definition files for a refresh at runtime.
The view class that should be used to create views.
Configure this if you want to provide a custom View implementation, typically a ub-class of the expected View type.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="java:java.lang.Class" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="view-names" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set the view names (or name patterns) that can be handled by this view resolver.
View names can contain simple wildcards such that 'my*', '*Report' and '*Repo*'
will all match the view name 'myReport'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="bean-name-type" />
<xsd:complexType name="freemarker-type">
<xsd:attribute name="prefix" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set the prefix that gets prepended to view names when building a URL.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set the suffix that gets appended to view names when building a URL.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cache" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Enable or disable caching.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="template-loader-paths" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set a List of TemplateLoaders that will be used to search for templates.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="velocity-type">
<xsd:attribute name="prefix" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set the prefix that gets prepended to view names when building a URL.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set the suffix that gets appended to view names when building a URL.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cache" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Enable or disable caching.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="resource-loader-path" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Set the Velocity resource loader path via a Spring resource location.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="view-resolution">
<xsd:element name="view-resolvers">
<xsd:annotation>
<xsd:documentation><![CDATA[
Helps with configuring a list of view resolvers.
Configure a chain of ViewResolver instances to resolve view names returned from
controllers into actual view instances to use for rendering.
All registered resolvers are wrapped in a single (composite) ViewResolver
with its order property set to 0 so that other external resolvers may be ordered
before or after it.
When content negotiation is enabled the order property is set to highest priority
instead with the ContentNeogitatingViewResolver encapsulating all other registered
view resolver instances. That way the resolvers registered through the MVC namespace
form self-encapsulated resolver chain.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence minOccurs="0">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="content-negotiating" type="content-negotiating-type" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a ContentNegotiatingViewResolver bean.
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="content-negotiation" type="contentNegotiationType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Registers a ContentNegotiatingViewResolver with the list of all other registered
ViewResolver instances used to set its "viewResolvers" property. See the Javadoc
of ContentNegotiatingViewResolver for more details.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="jsp" type="jsp-type" maxOccurs="1">
</xsd:annotation>
</xsd:element>
<xsd:element name="jsp" type="urlViewResolverType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register an InternalResourceViewResolver bean.
Default configuration is "/WEB-INF/" prefix and ".jsp" suffix
Register an InternalResourceViewResolver bean for JSP rendering.
By default "/WEB-INF/" is registered as a view name prefix and ".jsp" as a suffix.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="tiles" type="tiles-type" maxOccurs="1">
<xsd:element name="tiles" type="urlViewResolverType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a TilesViewResolver and a TilesConfigurer with default "/WEB-INF/tiles.xml"
definition and no Tiles definition check refresh.
Register a TilesViewResolver based on Tiles 3.x.
To configure Tiles you must also add a top-level <mvc:tiles> element
or declare a TilesConfigurer bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="bean-name" type="bean-name-type" maxOccurs="1">
<xsd:element name="freemarker" type="urlViewResolverType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a BeanNameViewResolver bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="freemarker" type="freemarker-type" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a FreeMarkerViewResolver and a FreeMarkerConfigurer beans with "" prefix,
".ftl" suffix and "/WEB-INF/" templateLoaderPath.
Register a FreeMarkerViewResolver.
By default ".ftl" is configured as a view name suffix.
To configure FreeMarker you must also add a top-level <mvc:freemarker> element
or declare a FreeMarkerConfigurer bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="velocity" type="velocity-type" maxOccurs="1">
<xsd:element name="velocity" type="urlViewResolverType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a VelocityLayoutViewResolver and a VelocityConfigurer beans with default ""
prefix, ".vm" suffix and "/WEB-INF/" resourceLoaderPath.
Register a VelocityViewResolver.
By default ".vm" is configured as a view name suffix.
To configure Velocity you must also add a top-level <mvc:velocity> element.
or declare a VelocityConfigurer bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="bean-name" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a BeanNameViewResolver bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="beans:bean">
<xsd:annotation>
<xsd:documentation><![CDATA[
A bean definition.
Register a ViewResolver as a direct bean declaration.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="beans:ref">
<xsd:annotation>
<xsd:documentation><![CDATA[
A reference to a bean.
Register a ViewResolver through references to an existing bean declaration.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:choice>
</xsd:complexType>
</xsd:element>
<xsd:element name="tiles">
<xsd:annotation>
<xsd:documentation><![CDATA[
Configure Tiles 3.x by registering a TilesConfigurer bean.
This is a shortcut alternative to declaring a TilesConfigurer bean directly.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="definitions" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="location" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The location of a file containing Tiles definitions (or a Spring resource pattern).
If no Tiles definitions are registerd, then "/WEB-INF/tiles.xml" is expected to exists.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="check-refresh" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
Whether to check Tiles definition files for a refresh at runtime.
Default is "false".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="validate-definitions" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
Whether to validate the Tiles XML definitions. Default is "true".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="freemarker">
<xsd:annotation>
<xsd:documentation><![CDATA[
Configure FreeMarker for view resolution by registering a FreeMarkerConfigurer bean.
This is a shortcut alternative to declaring a FreeMarkerConfigurer bean directly.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="template-loader-path" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="location" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The location of a FreeMarker template loader path (or a Spring resource pattern).
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="content-negotiating-type">
<xsd:all>
<xsd:element name="default-views" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="beans:bean">
<xsd:annotation>
<xsd:documentation><![CDATA[
A bean definition.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="beans:ref">
<xsd:annotation>
<xsd:documentation><![CDATA[
A reference to a bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
<xsd:attribute name="manager" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The bean name of the ContentNegotiationManager implementation to use for determining
the requested MediaType media types of a request.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="use-not-acceptable" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicate whether a 406 Not Acceptable status code should be returned if no suitable
view can be found.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="velocity">
<xsd:annotation>
<xsd:documentation><![CDATA[
Configure Velocity for view resolution by registering a VelocityConfigurer bean.
This is a shortcut alternative to declaring a VelocityConfigurer bean directly.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="resource-loader-path" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The Velocity resource loader path via a Spring resource location.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@ -67,6 +67,7 @@ import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.handler.*;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
@ -95,6 +96,8 @@ import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
import static org.junit.Assert.*;
/**
* Tests loading actual MVC namespace configuration.
*
* @author Keith Donald
* @author Arjen Poutsma
* @author Jeremy Grelle
@ -557,95 +560,87 @@ public class MvcNamespaceTests {
}
@Test
public void testViewResolvers() throws Exception {
loadBeanDefinitions("mvc-config-view-resolution.xml", 8);
public void testViewResolution() throws Exception {
loadBeanDefinitions("mvc-config-view-resolution.xml", 5);
ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class);
assertNotNull(compositeResolver);
assertEquals(7, compositeResolver.getViewResolvers().size());
assertEquals(0, compositeResolver.getOrder());
List<ViewResolver> resolvers = compositeResolver.getViewResolvers();
assertEquals(BeanNameViewResolver.class, resolvers.get(0).getClass());
ViewResolver resolver = resolvers.get(1);
assertEquals(InternalResourceViewResolver.class, resolver.getClass());
DirectFieldAccessor accessor = new DirectFieldAccessor(resolver);
assertEquals(InternalResourceView.class, accessor.getPropertyValue("viewClass"));
assertEquals(TilesViewResolver.class, resolvers.get(2).getClass());
resolver = resolvers.get(3);
FreeMarkerViewResolver freeMarkerViewResolver = (FreeMarkerViewResolver) resolver;
accessor = new DirectFieldAccessor(resolver);
assertEquals("freemarker-", accessor.getPropertyValue("prefix"));
assertEquals(".freemarker", accessor.getPropertyValue("suffix"));
assertArrayEquals(new String[] {"my*", "*Report"}, (String[]) accessor.getPropertyValue("viewNames"));
assertEquals(1024, accessor.getPropertyValue("cacheLimit"));
resolver = resolvers.get(4);
VelocityViewResolver velocityViewResolver = (VelocityViewResolver) resolver;
accessor = new DirectFieldAccessor(resolver);
assertEquals("", accessor.getPropertyValue("prefix"));
assertEquals(".vm", accessor.getPropertyValue("suffix"));
assertEquals(0, accessor.getPropertyValue("cacheLimit"));
assertEquals(InternalResourceViewResolver.class, resolvers.get(5).getClass());
assertEquals(InternalResourceViewResolver.class, resolvers.get(6).getClass());
InternalResourceViewResolver internalResourceViewResolver = appContext.getBean(InternalResourceViewResolver.class);
assertNotNull(internalResourceViewResolver);
assertEquals(0, internalResourceViewResolver.getOrder());
DirectFieldAccessor internalResourceViewResolverFieldAccessor = new DirectFieldAccessor(internalResourceViewResolver);
assertEquals("/WEB-INF/", internalResourceViewResolverFieldAccessor.getPropertyValue("prefix"));
assertEquals(".jsp", internalResourceViewResolverFieldAccessor.getPropertyValue("suffix"));
BeanNameViewResolver beanNameViewResolver = appContext.getBean(BeanNameViewResolver.class);
assertNotNull(beanNameViewResolver);
assertEquals(1, beanNameViewResolver.getOrder());
TilesConfigurer tilesConfigurer = appContext.getBean(TilesConfigurer.class);
assertNotNull(tilesConfigurer);
DirectFieldAccessor tilesConfigurerFieldAccessor = new DirectFieldAccessor(tilesConfigurer);
assertArrayEquals(new String[]{"/org/springframework/web/servlet/resource/tiles/tiles1.xml","/org/springframework/web/servlet/resource/tiles/tiles2.xml"},
(String[])tilesConfigurerFieldAccessor.getPropertyValue("definitions"));
assertTrue((boolean)tilesConfigurerFieldAccessor.getPropertyValue("checkRefresh"));
TilesViewResolver tilesViewResolver = appContext.getBean(TilesViewResolver.class);
assertNotNull(tilesViewResolver);
assertEquals(2, tilesViewResolver.getOrder());
String[] definitions = {
"/org/springframework/web/servlet/resource/tiles/tiles1.xml",
"/org/springframework/web/servlet/resource/tiles/tiles2.xml"
};
accessor = new DirectFieldAccessor(tilesConfigurer);
assertArrayEquals(definitions, (String[]) accessor.getPropertyValue("definitions"));
assertTrue((boolean)accessor.getPropertyValue("checkRefresh"));
FreeMarkerConfigurer freeMarkerConfigurer = appContext.getBean(FreeMarkerConfigurer.class);
assertNotNull(freeMarkerConfigurer);
DirectFieldAccessor freeMarkerConfigurerFieldAccessor = new DirectFieldAccessor(freeMarkerConfigurer);
assertArrayEquals(new String[]{"/","/test"},
(String[])freeMarkerConfigurerFieldAccessor.getPropertyValue("templateLoaderPaths"));
FreeMarkerViewResolver freeMarkerViewResolver = appContext.getBean(FreeMarkerViewResolver.class);
assertNotNull(freeMarkerViewResolver);
assertEquals(3, freeMarkerViewResolver.getOrder());
DirectFieldAccessor freeMarkerViewResolverFieldAccessor = new DirectFieldAccessor(freeMarkerViewResolver);
assertEquals("", freeMarkerViewResolverFieldAccessor.getPropertyValue("prefix"));
assertEquals(".ftl", freeMarkerViewResolverFieldAccessor.getPropertyValue("suffix"));
assertEquals(0, freeMarkerViewResolverFieldAccessor.getPropertyValue("cacheLimit"));
accessor = new DirectFieldAccessor(freeMarkerConfigurer);
assertArrayEquals(new String[]{"/", "/test"}, (String[]) accessor.getPropertyValue("templateLoaderPaths"));
VelocityConfigurer velocityConfigurer = appContext.getBean(VelocityConfigurer.class);
assertNotNull(velocityConfigurer);
DirectFieldAccessor velocityConfigurerFieldAccessor = new DirectFieldAccessor(velocityConfigurer);
assertEquals("/", velocityConfigurerFieldAccessor.getPropertyValue("resourceLoaderPath"));
VelocityViewResolver velocityViewResolver = appContext.getBean(VelocityViewResolver.class);
assertNotNull(velocityViewResolver);
assertEquals(4, velocityViewResolver.getOrder());
DirectFieldAccessor velocityViewResolverFieldAccessor = new DirectFieldAccessor(velocityViewResolver);
assertEquals("", velocityViewResolverFieldAccessor.getPropertyValue("prefix"));
assertEquals(".vm", velocityViewResolverFieldAccessor.getPropertyValue("suffix"));
assertEquals(0, velocityViewResolverFieldAccessor.getPropertyValue("cacheLimit"));
accessor = new DirectFieldAccessor(velocityConfigurer);
assertEquals("/test", accessor.getPropertyValue("resourceLoaderPath"));
}
@Test
public void testContentNegotiating() throws Exception {
loadBeanDefinitions("mvc-config-content-negotiating.xml", 11);
public void testViewResolutionWithContentNegotiation() throws Exception {
loadBeanDefinitions("mvc-config-view-resolution-content-negotiation.xml", 5);
ContentNegotiatingViewResolver contentNegotiatingViewResolver = appContext.getBean(ContentNegotiatingViewResolver.class);
assertNotNull(contentNegotiatingViewResolver);
DirectFieldAccessor contentNegotiatingViewResolverFieldAccessor = new DirectFieldAccessor(contentNegotiatingViewResolver);
assertTrue((boolean)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("useNotAcceptableStatusCode"));
assertEquals(1, ((List<?>)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("defaultViews")).size());
assertEquals(7, ((List<?>)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("viewResolvers")).size());
ContentNegotiationManager contentNegotiationManagerProperty =
(ContentNegotiationManager)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("contentNegotiationManager");
assertNotNull(contentNegotiationManagerProperty);
ContentNegotiationManager contentNegotiationManager = appContext.getBean(ContentNegotiationManager.class);
assertNotNull(contentNegotiationManager);
assertEquals(contentNegotiationManagerProperty.getClass(), contentNegotiationManager.getClass());
ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class);
assertNotNull(compositeResolver);
assertEquals(1, compositeResolver.getViewResolvers().size());
assertEquals(Ordered.HIGHEST_PRECEDENCE, compositeResolver.getOrder());
List<ViewResolver> resolvers = compositeResolver.getViewResolvers();
assertEquals(ContentNegotiatingViewResolver.class, resolvers.get(0).getClass());
ContentNegotiatingViewResolver cnvr = (ContentNegotiatingViewResolver) resolvers.get(0);
assertEquals(5, cnvr.getViewResolvers().size());
assertEquals(1, cnvr.getDefaultViews().size());
assertTrue(cnvr.isUseNotAcceptableStatusCode());
String beanName = "contentNegotiationManager";
DirectFieldAccessor accessor = new DirectFieldAccessor(cnvr);
ContentNegotiationManager manager = (ContentNegotiationManager) accessor.getPropertyValue(beanName);
assertNotNull(manager);
assertSame(manager, this.appContext.getBean(ContentNegotiationManager.class));
}
@Test
public void testContentNegotiatingWithDefaultValues() throws Exception {
loadBeanDefinitions("mvc-config-content-negotiating-with-default-values.xml", 19);
ContentNegotiatingViewResolver contentNegotiatingViewResolver = appContext.getBean(ContentNegotiatingViewResolver.class);
assertNotNull(contentNegotiatingViewResolver);
DirectFieldAccessor contentNegotiatingViewResolverFieldAccessor = new DirectFieldAccessor(contentNegotiatingViewResolver);
assertEquals(1, ((List<?>)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("defaultViews")).size());
assertEquals(3, ((List<?>)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("viewResolvers")).size());
ContentNegotiationManager contentNegotiationManagerProperty =
(ContentNegotiationManager)contentNegotiatingViewResolverFieldAccessor.getPropertyValue("contentNegotiationManager");
assertNotNull(contentNegotiationManagerProperty);
ContentNegotiationManager contentNegotiationManager = appContext.getBean(ContentNegotiationManager.class);
assertNotNull(contentNegotiationManager);
assertEquals(contentNegotiationManagerProperty.getClass(), contentNegotiationManager.getClass());
}
@Test
public void testPathMatchingHandlerMappings() throws Exception {
loadBeanDefinitions("mvc-config-path-matching-mappings.xml", 20);
@ -673,7 +668,8 @@ public class MvcNamespaceTests {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
ClassPathResource resource = new ClassPathResource(fileName, AnnotationDrivenBeanDefinitionParserTests.class);
reader.loadBeanDefinitions(resource);
assertEquals(expectedBeanCount, appContext.getBeanDefinitionCount());
assertEquals("Bean names: " + Arrays.toString(this.appContext.getBeanDefinitionNames()),
expectedBeanCount, appContext.getBeanDefinitionCount());
appContext.refresh();
}

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mvc:annotation-driven />
<mvc:view-resolution>
<mvc:content-negotiating use-not-acceptable="true">
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</mvc:default-views>
</mvc:content-negotiating>
<mvc:jsp />
<mvc:freemarker />
<mvc:velocity />
</mvc:view-resolution>
</beans>

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myViewResolver2"
class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<value>
xml=application/rss+xml
</value>
</property>
</bean>
<mvc:view-resolution>
<mvc:content-negotiating manager="contentNegotiationManager" use-not-acceptable="true">
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</mvc:default-views>
</mvc:content-negotiating>
<mvc:jsp prefix="/WEB-INF/" suffix=".jsp" />
<mvc:bean-name />
<mvc:tiles definitions="/org/springframework/web/servlet/resource/tiles/tiles1.xml" />
<mvc:freemarker prefix="" suffix=".ftl" template-loader-paths="/" />
<mvc:velocity prefix="" suffix=".vm" resource-loader-path="/" />
<bean id="myViewResolver1" class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<ref bean="myViewResolver2" />
</mvc:view-resolution>
</beans>

View File

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
View resolution finds the ContentNegotiationManager created by or
registered with <mvc:annotation-driven>. Or in its absence simply declare it.
-->
<bean id="mvcContentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"/>
<mvc:view-resolvers>
<mvc:content-negotiation use-not-acceptable="true">
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</mvc:default-views>
</mvc:content-negotiation>
<mvc:bean-name />
<mvc:jsp />
<mvc:tiles />
<mvc:freemarker />
<mvc:velocity />
</mvc:view-resolvers>
<mvc:tiles check-refresh="true">
<mvc:definitions location="/org/springframework/web/servlet/resource/tiles/tiles1.xml" />
</mvc:tiles>
<mvc:freemarker>
<mvc:template-loader-path location="/org/springframework/web/servlet/view" />
</mvc:freemarker>
<mvc:velocity resource-loader-path="/org/springframework/web/servlet/view" />
</beans>

View File

@ -1,26 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mvc:view-resolution>
<mvc:view-resolvers>
<mvc:bean-name />
<mvc:jsp view-class="org.springframework.web.servlet.view.InternalResourceView" />
<mvc:tiles />
<mvc:freemarker prefix="freemarker-" suffix=".freemarker" view-names="my*,*Report" />
<mvc:velocity cache-views="false" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
<ref bean="customResolver" />
</mvc:view-resolvers>
<mvc:jsp prefix="/WEB-INF/" suffix=".jsp" />
<bean id="customResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
<mvc:bean-name />
<mvc:tiles check-refresh="true" validate-definitions="true">
<mvc:definitions location="/org/springframework/web/servlet/resource/tiles/tiles1.xml" />
<mvc:definitions location="/org/springframework/web/servlet/resource/tiles/tiles2.xml" />
</mvc:tiles>
<mvc:tiles definitions="/org/springframework/web/servlet/resource/tiles/tiles1.xml,/org/springframework/web/servlet/resource/tiles/tiles2.xml"
check-refresh="true" />
<mvc:freemarker>
<mvc:template-loader-path location="/" />
<mvc:template-loader-path location="/test" />
</mvc:freemarker>
<mvc:freemarker prefix="" suffix=".ftl"
template-loader-paths="/,/test" cache="false" />
<mvc:velocity resource-loader-path="/test" />
<mvc:velocity prefix="" suffix=".vm"
resource-loader-path="/" cache="false" />
</mvc:view-resolution>
</beans>