AnnotationDrivenBeanDefinitionParser.java 10.0 KB
Newer Older
1
/*
J
Juergen Hoeller 已提交
2
 * Copyright 2002-2010 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15
 *
 * 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.
 */
16

17 18
package org.springframework.web.servlet.config;

J
Juergen Hoeller 已提交
19 20
import org.w3c.dom.Element;

21
import org.springframework.beans.factory.config.BeanDefinition;
22
import org.springframework.beans.factory.config.RuntimeBeanReference;
23 24
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
25
import org.springframework.beans.factory.support.ManagedList;
26
import org.springframework.beans.factory.support.RootBeanDefinition;
27
import org.springframework.beans.factory.xml.BeanDefinitionParser;
28
import org.springframework.beans.factory.xml.ParserContext;
K
Keith Donald 已提交
29
import org.springframework.core.convert.ConversionService;
30
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
31 32
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
33
import org.springframework.http.converter.ResourceHttpMessageConverter;
34
import org.springframework.http.converter.StringHttpMessageConverter;
35 36
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
37 38 39
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
K
Keith Donald 已提交
40 41 42
import org.springframework.util.ClassUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
43
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
J
Juergen Hoeller 已提交
44
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
K
Keith Donald 已提交
45
import org.springframework.web.servlet.handler.MappedInterceptor;
46 47
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
48 49

/**
50 51 52 53
 * {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring MVC web
 * application.
 *
 * <p>Responsible for:
K
Keith Donald 已提交
54
 * <ol>
55 56
 * <li>Registering a DefaultAnnotationHandlerMapping bean for mapping HTTP Servlet Requests to @Controller methods
 * using @RequestMapping annotations.
K
Keith Donald 已提交
57
 * <li>Registering a AnnotationMethodHandlerAdapter bean for invoking annotated @Controller methods.
58 59
 * Will configure the HandlerAdapter's <code>webBindingInitializer</code> property for centrally configuring
 * {@code @Controller} {@code DataBinder} instances:
K
Keith Donald 已提交
60
 * <ul>
61 62 63 64 65 66 67
 * <li>Configures the conversionService if specified, otherwise defaults to a fresh {@link ConversionService} instance
 * created by the default {@link FormattingConversionServiceFactoryBean}.
 * <li>Configures the validator if specified, otherwise defaults to a fresh {@link Validator} instance created by the
 * default {@link LocalValidatorFactoryBean} <em>if the JSR-303 API is present on the classpath</em>.
 * <li>Configures standard {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters},
 * including the {@link Jaxb2RootElementHttpMessageConverter} <em>if JAXB2 is present on the classpath</em>, and
 * the {@link MappingJacksonHttpMessageConverter} <em>if Jackson is present on the classpath</em>.
K
Keith Donald 已提交
68 69
 * </ul>
 * </ol>
70
 *
71
 * @author Keith Donald
72
 * @author Juergen Hoeller
73
 * @author Arjen Poutsma
K
Keith Donald 已提交
74
 * @since 3.0
75
 */
J
Juergen Hoeller 已提交
76
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
77 78

	private static final boolean jsr303Present = ClassUtils.isPresent(
79
			"javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
80

81 82 83 84 85 86 87
	private static final boolean jaxb2Present =
			ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());

	private static final boolean jacksonPresent =
			ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) &&
					ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());

88 89
	private static boolean romePresent =
			ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
90

91

92 93
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		Object source = parserContext.extractSource(element);
94

95 96 97
		CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
		parserContext.pushContainingComponent(compDefinition);
		
98 99
		RootBeanDefinition annMappingDef = new RootBeanDefinition(DefaultAnnotationHandlerMapping.class);
		annMappingDef.setSource(source);
100
		annMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
101 102
		annMappingDef.getPropertyValues().add("order", 0);
		String annMappingName = parserContext.getReaderContext().registerWithGeneratedName(annMappingDef);
103

K
Keith Donald 已提交
104 105 106
		RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
		RuntimeBeanReference validator = getValidator(element, source, parserContext);
		
107 108
		RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
		bindingDef.setSource(source);
109
		bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
K
Keith Donald 已提交
110 111
		bindingDef.getPropertyValues().add("conversionService", conversionService);
		bindingDef.getPropertyValues().add("validator", validator);
112

113 114
		RootBeanDefinition annAdapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
		annAdapterDef.setSource(source);
115
		annAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
116
		annAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
117
		annAdapterDef.getPropertyValues().add("messageConverters", getMessageConverters(source));
K
Keith Donald 已提交
118 119
		String annAdapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef);

J
Juergen Hoeller 已提交
120
		RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
K
Keith Donald 已提交
121 122 123 124 125 126 127 128
		csInterceptorDef.setSource(source);
		csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);		
		RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
		mappedCsInterceptorDef.setSource(source);
		mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
		mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
		String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
129
		
130
		parserContext.registerComponent(new BeanComponentDefinition(annMappingDef, annMappingName));
K
Keith Donald 已提交
131 132
		parserContext.registerComponent(new BeanComponentDefinition(annAdapterDef, annAdapterName));
		parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
133 134 135 136 137 138
		parserContext.popAndRegisterContainingComponent();
		
		return null;
	}
	

K
Keith Donald 已提交
139
	private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) {
140
		if (element.hasAttribute("conversion-service")) {
141 142 143 144 145
			return new RuntimeBeanReference(element.getAttribute("conversion-service"));
		}
		else {
			RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
			conversionDef.setSource(source);
146
			conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
147
			String conversionName = parserContext.getReaderContext().registerWithGeneratedName(conversionDef);
148
			parserContext.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
149
			return new RuntimeBeanReference(conversionName);
150 151
		}
	}
K
Keith Donald 已提交
152

K
Keith Donald 已提交
153
	private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) {
154
		if (element.hasAttribute("validator")) {
155 156 157 158 159
			return new RuntimeBeanReference(element.getAttribute("validator"));
		}
		else if (jsr303Present) {
			RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class);
			validatorDef.setSource(source);
160
			validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
161
			String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
162
			parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
163 164 165 166
			return new RuntimeBeanReference(validatorName);
		}
		else {
			return null;
K
Keith Donald 已提交
167
		}
168
	}
169

170 171 172 173 174
	private ManagedList<RootBeanDefinition> getMessageConverters(Object source) {
		ManagedList<RootBeanDefinition> messageConverters = new ManagedList<RootBeanDefinition>();
		messageConverters.setSource(source);
		messageConverters.add(new RootBeanDefinition(ByteArrayHttpMessageConverter.class));
		messageConverters.add(new RootBeanDefinition(StringHttpMessageConverter.class));
175
		messageConverters.add(new RootBeanDefinition(ResourceHttpMessageConverter.class));
176 177 178 179 180 181 182 183
		messageConverters.add(new RootBeanDefinition(FormHttpMessageConverter.class));
		messageConverters.add(new RootBeanDefinition(SourceHttpMessageConverter.class));
		if (jaxb2Present) {
			messageConverters.add(new RootBeanDefinition(Jaxb2RootElementHttpMessageConverter.class));
		}
		if (jacksonPresent) {
			messageConverters.add(new RootBeanDefinition(MappingJacksonHttpMessageConverter.class));
		}
184 185 186 187
		if (romePresent) {
			messageConverters.add(new RootBeanDefinition(AtomFeedHttpMessageConverter.class));
			messageConverters.add(new RootBeanDefinition(RssChannelHttpMessageConverter.class));
		}
188 189 190
		return messageConverters;
	}

191
}