Skip to content

Commit 4ff23f4

Browse files
committed
StubWebApplicationContext supports AutowireCapableBeanFactory operations (as far as possible)
This is generally worthwhile but in particular fixes a regression with our Jackson SpringHandlerInstantiator in standalone MVC tests. Issue: SPR-13375 (cherry picked from commit 7d30017)
1 parent 42d5780 commit 4ff23f4

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import java.util.Set;
2525
import javax.servlet.ServletContext;
2626

27+
import org.springframework.beans.BeanUtils;
2728
import org.springframework.beans.BeansException;
2829
import org.springframework.beans.TypeConverter;
2930
import org.springframework.beans.factory.BeanFactory;
@@ -42,20 +43,22 @@
4243
import org.springframework.core.env.StandardEnvironment;
4344
import org.springframework.core.io.Resource;
4445
import org.springframework.core.io.support.ResourcePatternResolver;
46+
import org.springframework.util.ClassUtils;
4547
import org.springframework.util.ObjectUtils;
4648
import org.springframework.web.context.WebApplicationContext;
4749
import org.springframework.web.context.support.ServletContextResourcePatternResolver;
4850

4951
/**
50-
* A mock WebApplicationContext that accepts registrations of object instances.
52+
* A stub WebApplicationContext that accepts registrations of object instances.
5153
*
52-
* <p>As registered object instances are instantiated and initialized
53-
* externally, there is no wiring, bean initialization, lifecycle events, as
54-
* well as no pre-processing and post-processing hooks typically associated with
55-
* beans managed by an {@link ApplicationContext}. Just a simple lookup into a
54+
* <p>As registered object instances are instantiated and initialized externally,
55+
* there is no wiring, bean initialization, lifecycle events, as well as no
56+
* pre-processing and post-processing hooks typically associated with beans
57+
* managed by an {@link ApplicationContext}. Just a simple lookup into a
5658
* {@link StaticListableBeanFactory}.
5759
*
5860
* @author Rossen Stoyanchev
61+
* @author Juergen Hoeller
5962
* @since 3.2
6063
*/
6164
class StubWebApplicationContext implements WebApplicationContext {
@@ -77,14 +80,12 @@ class StubWebApplicationContext implements WebApplicationContext {
7780
private final ResourcePatternResolver resourcePatternResolver;
7881

7982

80-
/**
81-
* Class constructor.
82-
*/
8383
public StubWebApplicationContext(ServletContext servletContext) {
8484
this.servletContext = servletContext;
8585
this.resourcePatternResolver = new ServletContextResourcePatternResolver(servletContext);
8686
}
8787

88+
8889
/**
8990
* Returns an instance that can initialize {@link ApplicationContextAware} beans.
9091
*/
@@ -98,6 +99,7 @@ public ServletContext getServletContext() {
9899
return this.servletContext;
99100
}
100101

102+
101103
//---------------------------------------------------------------------
102104
// Implementation of ApplicationContext interface
103105
//---------------------------------------------------------------------
@@ -137,12 +139,16 @@ public void addBean(String name, Object bean) {
137139
}
138140

139141
public void addBeans(List<?> beans) {
142+
if (beans == null) {
143+
return;
144+
}
140145
for (Object bean : beans) {
141146
String name = bean.getClass().getName() + "#" + ObjectUtils.getIdentityHexString(bean);
142147
this.beanFactory.addBean(name, bean);
143148
}
144149
}
145150

151+
146152
//---------------------------------------------------------------------
147153
// Implementation of BeanFactory interface
148154
//---------------------------------------------------------------------
@@ -202,6 +208,7 @@ public String[] getAliases(String name) {
202208
return this.beanFactory.getAliases(name);
203209
}
204210

211+
205212
//---------------------------------------------------------------------
206213
// Implementation of ListableBeanFactory interface
207214
//---------------------------------------------------------------------
@@ -262,6 +269,7 @@ public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> a
262269
return this.beanFactory.findAnnotationOnBean(beanName, annotationType);
263270
}
264271

272+
265273
//---------------------------------------------------------------------
266274
// Implementation of HierarchicalBeanFactory interface
267275
//---------------------------------------------------------------------
@@ -276,6 +284,7 @@ public boolean containsLocalBean(String name) {
276284
return this.beanFactory.containsBean(name);
277285
}
278286

287+
279288
//---------------------------------------------------------------------
280289
// Implementation of MessageSource interface
281290
//---------------------------------------------------------------------
@@ -295,20 +304,22 @@ public String getMessage(MessageSourceResolvable resolvable, Locale locale) thro
295304
return this.messageSource.getMessage(resolvable, locale);
296305
}
297306

307+
298308
//---------------------------------------------------------------------
299309
// Implementation of ResourceLoader interface
300310
//---------------------------------------------------------------------
301311

302312
@Override
303313
public ClassLoader getClassLoader() {
304-
return null;
314+
return ClassUtils.getDefaultClassLoader();
305315
}
306316

307317
@Override
308318
public Resource getResource(String location) {
309319
return this.resourcePatternResolver.getResource(location);
310320
}
311321

322+
312323
//---------------------------------------------------------------------
313324
// Other
314325
//---------------------------------------------------------------------
@@ -340,65 +351,61 @@ public Object initializeBean(Object existingBean, String beanName) throws BeansE
340351

341352
@Override
342353
public <T> T createBean(Class<T> beanClass) {
343-
throw new UnsupportedOperationException();
354+
return BeanUtils.instantiate(beanClass);
344355
}
345356

346357
@Override
347358
@SuppressWarnings("rawtypes")
348-
public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) {
349-
throw new UnsupportedOperationException();
359+
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
360+
return BeanUtils.instantiate(beanClass);
350361
}
351362

352363
@Override
353364
@SuppressWarnings("rawtypes")
354-
public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) {
355-
throw new UnsupportedOperationException();
365+
public Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
366+
return BeanUtils.instantiate(beanClass);
356367
}
357368

358369
@Override
359370
public void autowireBean(Object existingBean) throws BeansException {
360-
throw new UnsupportedOperationException();
361371
}
362372

363373
@Override
364374
public void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) {
365-
throw new UnsupportedOperationException();
366375
}
367376

368377
@Override
369378
public Object configureBean(Object existingBean, String beanName) {
370-
throw new UnsupportedOperationException();
379+
return existingBean;
371380
}
372381

373382
@Override
374383
public Object resolveDependency(DependencyDescriptor descriptor, String beanName) {
375-
throw new UnsupportedOperationException();
384+
throw new UnsupportedOperationException("Dependency resolution not supported");
376385
}
377386

378387
@Override
379388
public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
380389
Set<String> autowiredBeanNames, TypeConverter typeConverter) {
381-
throw new UnsupportedOperationException();
390+
throw new UnsupportedOperationException("Dependency resolution not supported");
382391
}
383392

384393
@Override
385394
public void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException {
386-
throw new UnsupportedOperationException();
387395
}
388396

389397
@Override
390398
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) {
391-
throw new UnsupportedOperationException();
399+
return existingBean;
392400
}
393401

394402
@Override
395403
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) {
396-
throw new UnsupportedOperationException();
404+
return existingBean;
397405
}
398406

399407
@Override
400408
public void destroyBean(Object existingBean) {
401-
throw new UnsupportedOperationException();
402409
}
403410
}
404411

spring-test/src/test/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilderTests.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,8 +23,11 @@
2323
import javax.servlet.http.HttpServletRequest;
2424
import javax.servlet.http.HttpServletResponse;
2525

26+
import com.fasterxml.jackson.databind.JsonSerializer;
27+
import com.fasterxml.jackson.databind.ser.impl.UnknownSerializer;
2628
import org.junit.Test;
2729

30+
import org.springframework.http.converter.json.SpringHandlerInstantiator;
2831
import org.springframework.mock.web.test.MockHttpServletRequest;
2932
import org.springframework.stereotype.Controller;
3033
import org.springframework.web.bind.annotation.RequestMapping;
@@ -46,7 +49,7 @@
4649
*/
4750
public class StandaloneMockMvcBuilderTests {
4851

49-
@Test // SPR-10825
52+
@Test // SPR-10825
5053
public void placeHoldersInRequestMapping() throws Exception {
5154

5255
TestStandaloneMockMvcBuilder builder = new TestStandaloneMockMvcBuilder(new PlaceholderController());
@@ -62,7 +65,7 @@ public void placeHoldersInRequestMapping() throws Exception {
6265
assertEquals("handleWithPlaceholders", ((HandlerMethod) chain.getHandler()).getMethod().getName());
6366
}
6467

65-
@Test // SPR-12553
68+
@Test // SPR-12553
6669
public void applicationContextAttribute() {
6770
TestStandaloneMockMvcBuilder builder = new TestStandaloneMockMvcBuilder(new PlaceholderController());
6871
builder.addPlaceHolderValue("sys.login.ajax", "/foo");
@@ -96,6 +99,15 @@ public void addFilterPatternContainsNull() {
9699
builder.addFilter(new ContinueFilter(), (String) null);
97100
}
98101

102+
@Test // SPR-13375
103+
public void springHandlerInstantiator() {
104+
TestStandaloneMockMvcBuilder builder = new TestStandaloneMockMvcBuilder(new PersonController());
105+
builder.build();
106+
SpringHandlerInstantiator instantiator = new SpringHandlerInstantiator(builder.wac.getAutowireCapableBeanFactory());
107+
JsonSerializer serializer = instantiator.serializerInstance(null, null, UnknownSerializer.class);
108+
assertNotNull(serializer);
109+
}
110+
99111

100112
@Controller
101113
private static class PlaceholderController {

0 commit comments

Comments
 (0)