Skip to content

Commit 1d6978a

Browse files
committed
Revised ControllerAdvice basePackages handling (based on package names instead of java.lang.Package)
Issue: SPR-12506 (cherry picked from commit 4013fe0)
1 parent 4660e61 commit 1d6978a

File tree

1 file changed

+79
-83
lines changed

1 file changed

+79
-83
lines changed

spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java

Lines changed: 79 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
import java.lang.annotation.Annotation;
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
22+
import java.util.LinkedHashSet;
2223
import java.util.List;
23-
24-
import org.apache.commons.logging.Log;
25-
import org.apache.commons.logging.LogFactory;
24+
import java.util.Set;
2625

2726
import org.springframework.beans.factory.BeanFactory;
2827
import org.springframework.beans.factory.BeanFactoryUtils;
@@ -39,91 +38,93 @@
3938
* Encapsulates information about an {@linkplain ControllerAdvice @ControllerAdvice}
4039
* Spring-managed bean without necessarily requiring it to be instantiated.
4140
*
42-
* <p>The {@link #findAnnotatedBeans(ApplicationContext)} method can be used to discover
43-
* such beans. However, an {@code ControllerAdviceBean} may be created from
44-
* any object, including ones without an {@code @ControllerAdvice}.
41+
* <p>The {@link #findAnnotatedBeans(ApplicationContext)} method can be used to
42+
* discover such beans. However, a {@code ControllerAdviceBean} may be created
43+
* from any object, including ones without an {@code @ControllerAdvice}.
4544
*
4645
* @author Rossen Stoyanchev
4746
* @author Brian Clozel
47+
* @author Juergen Hoeller
4848
* @since 3.2
4949
*/
5050
public class ControllerAdviceBean implements Ordered {
5151

52-
private static final Log logger = LogFactory.getLog(ControllerAdviceBean.class);
53-
5452
private final Object bean;
5553

54+
private final BeanFactory beanFactory;
55+
5656
private final int order;
5757

58-
private final BeanFactory beanFactory;
58+
private final Set<String> basePackages;
5959

60-
private final List<Package> basePackages = new ArrayList<Package>();
60+
private final List<Class<?>> assignableTypes;
6161

62-
private final List<Class<? extends Annotation>> annotations = new ArrayList<Class<? extends Annotation>>();
62+
private final List<Class<? extends Annotation>> annotations;
6363

64-
private final List<Class<?>> assignableTypes = new ArrayList<Class<?>>();
6564

65+
/**
66+
* Create a {@code ControllerAdviceBean} using the given bean instance.
67+
* @param bean the bean instance
68+
*/
69+
public ControllerAdviceBean(Object bean) {
70+
this(bean, null);
71+
}
6672

6773
/**
68-
* Create an instance using the given bean name.
74+
* Create a {@code ControllerAdviceBean} using the given bean name.
6975
* @param beanName the name of the bean
7076
* @param beanFactory a BeanFactory that can be used later to resolve the bean
7177
*/
7278
public ControllerAdviceBean(String beanName, BeanFactory beanFactory) {
73-
Assert.hasText(beanName, "Bean name must not be null");
74-
Assert.notNull(beanFactory, "BeanFactory must not be null");
75-
76-
if (!beanFactory.containsBean(beanName)) {
77-
throw new IllegalArgumentException(
78-
"BeanFactory [" + beanFactory + "] does not contain bean with name '" + beanName + "'");
79-
}
80-
81-
this.bean = beanName;
82-
this.beanFactory = beanFactory;
83-
84-
Class<?> beanType = this.beanFactory.getType(beanName);
85-
this.order = initOrderFromBeanType(beanType);
86-
87-
ControllerAdvice annotation = AnnotationUtils.findAnnotation(beanType,ControllerAdvice.class);
88-
Assert.notNull(annotation, "BeanType [" + beanType.getName() + "] is not annotated @ControllerAdvice");
89-
90-
this.basePackages.addAll(initBasePackagesFromBeanType(beanType, annotation));
91-
this.annotations.addAll(Arrays.asList(annotation.annotations()));
92-
this.assignableTypes.addAll(Arrays.asList(annotation.assignableTypes()));
79+
this((Object) beanName, beanFactory);
9380
}
9481

95-
/**
96-
* Create an instance using the given bean instance.
97-
* @param bean the bean
98-
*/
99-
public ControllerAdviceBean(Object bean) {
100-
Assert.notNull(bean, "Bean must not be null");
82+
private ControllerAdviceBean(Object bean, BeanFactory beanFactory) {
10183
this.bean = bean;
102-
this.order = initOrderFromBean(bean);
103-
104-
Class<?> beanType = bean.getClass();
105-
ControllerAdvice annotation = AnnotationUtils.findAnnotation(beanType,ControllerAdvice.class);
106-
Assert.notNull(annotation, "Bean type [" + beanType.getName() + "] is not annotated @ControllerAdvice");
84+
this.beanFactory = beanFactory;
85+
Class<?> beanType;
86+
87+
if (bean instanceof String) {
88+
String beanName = (String) bean;
89+
Assert.hasText(beanName, "Bean name must not be null");
90+
Assert.notNull(beanFactory, "BeanFactory must not be null");
91+
if (!beanFactory.containsBean(beanName)) {
92+
throw new IllegalArgumentException("BeanFactory [" + beanFactory +
93+
"] does not contain specified controller advice bean '" + beanName + "'");
94+
}
95+
beanType = this.beanFactory.getType(beanName);
96+
this.order = initOrderFromBeanType(beanType);
97+
}
98+
else {
99+
Assert.notNull(bean, "Bean must not be null");
100+
beanType = bean.getClass();
101+
this.order = initOrderFromBean(bean);
102+
}
107103

108-
this.basePackages.addAll(initBasePackagesFromBeanType(beanType, annotation));
109-
this.annotations.addAll(Arrays.asList(annotation.annotations()));
110-
this.assignableTypes.addAll(Arrays.asList(annotation.assignableTypes()));
111-
this.beanFactory = null;
104+
ControllerAdvice annotation = AnnotationUtils.findAnnotation(beanType, ControllerAdvice.class);
105+
if (annotation == null) {
106+
throw new IllegalArgumentException(
107+
"Bean type [" + beanType.getName() + "] is not annotated as @ControllerAdvice");
108+
}
109+
this.basePackages = initBasePackages(annotation);
110+
this.assignableTypes = Arrays.asList(annotation.assignableTypes());
111+
this.annotations = Arrays.asList(annotation.annotations());
112112
}
113113

114114

115115
/**
116116
* Returns the order value extracted from the {@link ControllerAdvice}
117-
* annotation or {@link Ordered#LOWEST_PRECEDENCE} otherwise.
117+
* annotation, or {@link Ordered#LOWEST_PRECEDENCE} otherwise.
118118
*/
119119
@Override
120120
public int getOrder() {
121121
return this.order;
122122
}
123123

124124
/**
125-
* Returns the type of the contained bean.
126-
* If the bean type is a CGLIB-generated class, the original, user-defined class is returned.
125+
* Return the type of the contained bean.
126+
* <p>If the bean type is a CGLIB-generated class, the original
127+
* user-defined class is returned.
127128
*/
128129
public Class<?> getBeanType() {
129130
Class<?> clazz = (this.bean instanceof String ?
@@ -139,7 +140,7 @@ public Object resolveBean() {
139140
}
140141

141142
/**
142-
* Checks whether the given bean type should be assisted by this
143+
* Check whether the given bean type should be assisted by this
143144
* {@code @ControllerAdvice} instance.
144145
* @param beanType the type of the bean to check
145146
* @see org.springframework.web.bind.annotation.ControllerAdvice
@@ -150,6 +151,12 @@ public boolean isApplicableToBeanType(Class<?> beanType) {
150151
return true;
151152
}
152153
else if (beanType != null) {
154+
String packageName = ClassUtils.getPackageName(beanType);
155+
for (String basePackage : this.basePackages) {
156+
if (packageName.startsWith(basePackage)) {
157+
return true;
158+
}
159+
}
153160
for (Class<?> clazz : this.assignableTypes) {
154161
if (ClassUtils.isAssignable(clazz, beanType)) {
155162
return true;
@@ -160,25 +167,25 @@ else if (beanType != null) {
160167
return true;
161168
}
162169
}
163-
String packageName = beanType.getPackage().getName();
164-
for (Package basePackage : this.basePackages) {
165-
if (packageName.startsWith(basePackage.getName())) {
166-
return true;
167-
}
168-
}
169170
}
170171
return false;
171172
}
172173

173174
private boolean hasSelectors() {
174-
return (!this.basePackages.isEmpty() || !this.annotations.isEmpty() || !this.assignableTypes.isEmpty());
175+
return (!this.basePackages.isEmpty() || !this.assignableTypes.isEmpty() || !this.annotations.isEmpty());
175176
}
176177

177178

178179
@Override
179180
public boolean equals(Object other) {
180-
return (this == other ||
181-
(other instanceof ControllerAdviceBean && this.bean.equals(((ControllerAdviceBean) other).bean)));
181+
if (this == other) {
182+
return true;
183+
}
184+
if (!(other instanceof ControllerAdviceBean)) {
185+
return false;
186+
}
187+
ControllerAdviceBean otherAdvice = (ControllerAdviceBean) other;
188+
return (this.bean.equals(otherAdvice.bean) && this.beanFactory == otherAdvice.beanFactory);
182189
}
183190

184191
@Override
@@ -216,32 +223,21 @@ private static int initOrderFromBeanType(Class<?> beanType) {
216223
return (ann != null ? ann.value() : Ordered.LOWEST_PRECEDENCE);
217224
}
218225

219-
private static List<Package> initBasePackagesFromBeanType(Class<?> beanType, ControllerAdvice annotation) {
220-
List<Package> basePackages = new ArrayList<Package>();
221-
List<String> basePackageNames = new ArrayList<String>();
222-
basePackageNames.addAll(Arrays.asList(annotation.value()));
223-
basePackageNames.addAll(Arrays.asList(annotation.basePackages()));
224-
for (String pkgName : basePackageNames) {
225-
if (StringUtils.hasText(pkgName)) {
226-
Package pkg = Package.getPackage(pkgName);
227-
if (pkg != null) {
228-
basePackages.add(pkg);
229-
}
230-
else {
231-
logger.warn("Package [" + pkgName + "] was not found, see [" + beanType.getName() + "]");
232-
}
226+
private static Set<String> initBasePackages(ControllerAdvice annotation) {
227+
Set<String> basePackages = new LinkedHashSet<String>();
228+
for (String basePackage : annotation.value()) {
229+
if (StringUtils.hasText(basePackage)) {
230+
basePackages.add(basePackage);
233231
}
234232
}
235-
for (Class<?> markerClass : annotation.basePackageClasses()) {
236-
Package pack = markerClass.getPackage();
237-
if (pack != null) {
238-
basePackages.add(pack);
239-
}
240-
else {
241-
logger.warn("Package was not found for class [" + markerClass.getName() +
242-
"], see [" + beanType.getName() + "]");
233+
for (String basePackage : annotation.basePackages()) {
234+
if (StringUtils.hasText(basePackage)) {
235+
basePackages.add(basePackage);
243236
}
244237
}
238+
for (Class<?> markerClass : annotation.basePackageClasses()) {
239+
basePackages.add(ClassUtils.getPackageName(markerClass));
240+
}
245241
return basePackages;
246242
}
247243

0 commit comments

Comments
 (0)