Skip to content

Commit 906b50e

Browse files
committed
Add FeatureMethodErrorTests
Capture common mistakes with @feature method declarations and ensure that useful error messages are produced.
1 parent 6926e0f commit 906b50e

File tree

3 files changed

+133
-8
lines changed

3 files changed

+133
-8
lines changed

org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ private void processFeatureMethod(final Method featureMethod, Object configInsta
322322
if (!(FeatureSpecification.class.isAssignableFrom(featureMethod.getReturnType()))) {
323323
// TODO SPR-7420: raise a Problem instead?
324324
throw new IllegalArgumentException(
325-
"return type from @Feature methods must be assignable to FeatureSpecification");
325+
format("Return type for @Feature method %s.%s() must be assignable to FeatureSpecification",
326+
featureMethod.getDeclaringClass().getSimpleName(), featureMethod.getName()));
326327
}
327328

328329
List<Object> beanArgs = new ArrayList<Object>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.annotation;
18+
19+
import static org.hamcrest.CoreMatchers.equalTo;
20+
import static org.junit.Assert.assertThat;
21+
import static org.junit.Assert.fail;
22+
23+
import org.junit.Test;
24+
import org.springframework.context.annotation.configuration.StubSpecification;
25+
import org.springframework.context.config.FeatureSpecification;
26+
27+
import test.beans.TestBean;
28+
29+
/**
30+
* Tests proving that @Feature methods may reference the product of @Bean methods.
31+
*
32+
* @author Chris Beams
33+
* @since 3.1
34+
*/
35+
public class FeatureMethodErrorTests {
36+
37+
@Test
38+
public void incorrectReturnType() {
39+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
40+
ctx.register(FeatureConfig.class);
41+
try {
42+
ctx.refresh();
43+
fail("expected exception");
44+
} catch (FeatureMethodExecutionException ex) {
45+
assertThat(ex.getCause().getMessage(),
46+
equalTo("Return type for @Feature method FeatureConfig.f() must be " +
47+
"assignable to FeatureSpecification"));
48+
}
49+
}
50+
51+
@Test
52+
public void voidReturnType() {
53+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
54+
ctx.register(VoidFeatureConfig.class);
55+
try {
56+
ctx.refresh();
57+
fail("expected exception");
58+
} catch (FeatureMethodExecutionException ex) {
59+
assertThat(ex.getCause().getMessage(),
60+
equalTo("Return type for @Feature method VoidFeatureConfig.f() must be " +
61+
"assignable to FeatureSpecification"));
62+
}
63+
}
64+
65+
@Test
66+
public void containsBeanMethod() {
67+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
68+
ctx.register(FeatureConfigWithBeanMethod.class);
69+
try {
70+
ctx.refresh();
71+
fail("expected exception");
72+
} catch (FeatureMethodExecutionException ex) {
73+
assertThat(ex.getMessage(),
74+
equalTo("@FeatureConfiguration classes must not contain @Bean-annotated methods. " +
75+
"FeatureConfigWithBeanMethod.testBean() is annotated with @Bean and must " +
76+
"be removed in order to proceed. Consider moving this method into a dedicated " +
77+
"@Configuration class and injecting the bean as a parameter into any @Feature " +
78+
"method(s) that need it."));
79+
}
80+
}
81+
82+
83+
@FeatureConfiguration
84+
static class FeatureConfig {
85+
@Feature
86+
public Object f() {
87+
return new StubSpecification();
88+
}
89+
}
90+
91+
92+
@FeatureConfiguration
93+
static class VoidFeatureConfig {
94+
@Feature
95+
public void f() {
96+
}
97+
}
98+
99+
100+
@FeatureConfiguration
101+
static class FeatureConfigWithBeanMethod {
102+
@Feature
103+
public FeatureSpecification f() {
104+
return new StubSpecification();
105+
}
106+
107+
@Bean
108+
public TestBean testBean() {
109+
return new TestBean();
110+
}
111+
}
112+
113+
}

org.springframework.integration-tests/src/test/java/org/springframework/context/annotation/FeatureTestSuite.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,39 @@
1616

1717
package org.springframework.context.annotation;
1818

19-
2019
/**
2120
* Tests directly or indirectly related to {@link FeatureConfiguration} class and
2221
* {@link Feature} method processing.
2322
*
2423
* @author Chris Beams
2524
* @since 3.1
26-
*/
27-
/*
25+
*
2826
* commented due to classpath visibility differences between Eclipse
2927
* and Ant/Ivy at the command line. Eclipse can see classes across
3028
* project test folders, Ant/Ivy are not configured to do so. Uncomment
3129
* as necessary when doing @Feature-related work.
32-
*
30+
import org.junit.runner.RunWith;
31+
import org.junit.runners.Suite;
32+
import org.junit.runners.Suite.SuiteClasses;
33+
import org.springframework.transaction.TxNamespaceHandlerTests;
34+
import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests;
35+
import org.springframework.transaction.annotation.TxAnnotationDrivenFeatureTests;
36+
import org.springframework.transaction.config.AnnotationDrivenTests;
37+
import org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParserTests;
38+
import org.springframework.web.servlet.config.MvcAnnotationDrivenFeatureTests;
39+
import org.springframework.web.servlet.config.MvcDefaultServletHandlerTests;
40+
import org.springframework.web.servlet.config.MvcNamespaceTests;
41+
import org.springframework.web.servlet.config.MvcResourcesTests;
42+
import org.springframework.web.servlet.config.MvcViewControllersTests;
43+
3344
@RunWith(Suite.class)
3445
@SuiteClasses({
3546
EarlyBeanReferenceProxyCreatorTests.class,
3647
SimpleFeatureMethodProcessingTests.class,
3748
BeanFactoryAwareFeatureConfigurationTests.class,
3849
FeatureMethodBeanReferenceTests.class,
3950
FeatureMethodQualifiedBeanReferenceTests.class,
51+
FeatureMethodErrorTests.class,
4052
FeatureConfigurationClassTests.class,
4153
FeatureMethodEarlyBeanProxyTests.class,
4254
FeatureConfigurationImportTests.class,
@@ -60,9 +72,8 @@
6072
MvcViewControllersTests.class,
6173
MvcResourcesTests.class,
6274
MvcDefaultServletHandlerTests.class,
63-
MvcNamespaceTests.class,
64-
})
65-
*/
75+
MvcNamespaceTests.class
76+
*/
6677
public class FeatureTestSuite {
6778

6879
}

0 commit comments

Comments
 (0)