Skip to content

Commit f7a4850

Browse files
committed
AnnotationJmxAttributeSource uses MergedAnnotation API directly
Includes deprecation of AnnotationBeanUtils class (now unused). Closes gh-22657
1 parent 0db3175 commit f7a4850

File tree

2 files changed

+84
-29
lines changed

2 files changed

+84
-29
lines changed

spring-beans/src/main/java/org/springframework/beans/annotation/AnnotationBeanUtils.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -19,6 +19,7 @@
1919
import java.lang.annotation.Annotation;
2020
import java.lang.reflect.Method;
2121
import java.util.Arrays;
22+
import java.util.Collections;
2223
import java.util.HashSet;
2324
import java.util.Set;
2425

@@ -34,7 +35,9 @@
3435
* @author Rob Harrop
3536
* @author Juergen Hoeller
3637
* @since 2.0
38+
* @deprecated as of 5.2, in favor of custom annotation attribute processing
3739
*/
40+
@Deprecated
3841
public abstract class AnnotationBeanUtils {
3942

4043
/**
@@ -62,7 +65,8 @@ public static void copyPropertiesToBean(Annotation ann, Object bean, String... e
6265
public static void copyPropertiesToBean(Annotation ann, Object bean, @Nullable StringValueResolver valueResolver,
6366
String... excludedProperties) {
6467

65-
Set<String> excluded = new HashSet<>(Arrays.asList(excludedProperties));
68+
Set<String> excluded = (excludedProperties.length == 0 ? Collections.emptySet() :
69+
new HashSet<>(Arrays.asList(excludedProperties)));
6670
Method[] annotationProperties = ann.annotationType().getDeclaredMethods();
6771
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(bean);
6872
for (Method annotationProperty : annotationProperties) {

spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -17,19 +17,30 @@
1717
package org.springframework.jmx.export.annotation;
1818

1919
import java.lang.annotation.Annotation;
20+
import java.lang.reflect.AnnotatedElement;
2021
import java.lang.reflect.Array;
2122
import java.lang.reflect.Method;
2223
import java.lang.reflect.Modifier;
23-
import java.util.Collection;
24-
import java.util.Set;
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.stream.Collectors;
2528

2629
import org.springframework.beans.BeanUtils;
27-
import org.springframework.beans.annotation.AnnotationBeanUtils;
30+
import org.springframework.beans.BeanWrapper;
31+
import org.springframework.beans.MutablePropertyValues;
32+
import org.springframework.beans.PropertyAccessorFactory;
33+
import org.springframework.beans.PropertyValue;
2834
import org.springframework.beans.factory.BeanFactory;
2935
import org.springframework.beans.factory.BeanFactoryAware;
3036
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
3137
import org.springframework.beans.factory.config.EmbeddedValueResolver;
32-
import org.springframework.core.annotation.AnnotationUtils;
38+
import org.springframework.core.annotation.AnnotationFilter;
39+
import org.springframework.core.annotation.MergedAnnotation;
40+
import org.springframework.core.annotation.MergedAnnotationPredicates;
41+
import org.springframework.core.annotation.MergedAnnotations;
42+
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
43+
import org.springframework.core.annotation.RepeatableContainers;
3344
import org.springframework.jmx.export.metadata.InvalidMetadataException;
3445
import org.springframework.jmx.export.metadata.JmxAttributeSource;
3546
import org.springframework.lang.Nullable;
@@ -65,85 +76,125 @@ public void setBeanFactory(BeanFactory beanFactory) {
6576
@Override
6677
@Nullable
6778
public org.springframework.jmx.export.metadata.ManagedResource getManagedResource(Class<?> beanClass) throws InvalidMetadataException {
68-
ManagedResource ann = AnnotationUtils.findAnnotation(beanClass, ManagedResource.class);
69-
if (ann == null) {
79+
MergedAnnotation<ManagedResource> ann = MergedAnnotations.from(beanClass, SearchStrategy.EXHAUSTIVE)
80+
.get(ManagedResource.class).withNonMergedAttributes();
81+
if (!ann.isPresent()) {
7082
return null;
7183
}
72-
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(ManagedResource.class, beanClass);
84+
Class<?> declaringClass = (Class<?>) ann.getSource();
7385
Class<?> target = (declaringClass != null && !declaringClass.isInterface() ? declaringClass : beanClass);
7486
if (!Modifier.isPublic(target.getModifiers())) {
7587
throw new InvalidMetadataException("@ManagedResource class '" + target.getName() + "' must be public");
7688
}
77-
org.springframework.jmx.export.metadata.ManagedResource managedResource = new org.springframework.jmx.export.metadata.ManagedResource();
78-
AnnotationBeanUtils.copyPropertiesToBean(ann, managedResource, this.embeddedValueResolver);
79-
return managedResource;
89+
90+
org.springframework.jmx.export.metadata.ManagedResource bean = new org.springframework.jmx.export.metadata.ManagedResource();
91+
Map<String, Object> map = ann.asMap();
92+
List<PropertyValue> list = new ArrayList<>(map.size());
93+
map.forEach((attrName, attrValue) -> {
94+
if (!"value".equals(attrName)) {
95+
Object value = attrValue;
96+
if (this.embeddedValueResolver != null && value instanceof String) {
97+
value = this.embeddedValueResolver.resolveStringValue((String) value);
98+
}
99+
list.add(new PropertyValue(attrName, value));
100+
}
101+
});
102+
PropertyAccessorFactory.forBeanPropertyAccess(bean).setPropertyValues(new MutablePropertyValues(list));
103+
return bean;
80104
}
81105

82106
@Override
83107
@Nullable
84108
public org.springframework.jmx.export.metadata.ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException {
85-
ManagedAttribute ann = AnnotationUtils.findAnnotation(method, ManagedAttribute.class);
86-
if (ann == null) {
109+
MergedAnnotation<ManagedAttribute> ann = MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE)
110+
.get(ManagedAttribute.class).withNonMergedAttributes();
111+
if (!ann.isPresent()) {
87112
return null;
88113
}
89-
org.springframework.jmx.export.metadata.ManagedAttribute managedAttribute = new org.springframework.jmx.export.metadata.ManagedAttribute();
90-
AnnotationBeanUtils.copyPropertiesToBean(ann, managedAttribute, "defaultValue");
91-
if (ann.defaultValue().length() > 0) {
92-
managedAttribute.setDefaultValue(ann.defaultValue());
114+
115+
org.springframework.jmx.export.metadata.ManagedAttribute bean = new org.springframework.jmx.export.metadata.ManagedAttribute();
116+
Map<String, Object> map = ann.asMap();
117+
MutablePropertyValues pvs = new MutablePropertyValues(map);
118+
pvs.removePropertyValue("defaultValue");
119+
PropertyAccessorFactory.forBeanPropertyAccess(bean).setPropertyValues(pvs);
120+
String defaultValue = (String) map.get("defaultValue");
121+
if (defaultValue.length() > 0) {
122+
bean.setDefaultValue(defaultValue);
93123
}
94-
return managedAttribute;
124+
return bean;
95125
}
96126

97127
@Override
98128
@Nullable
99129
public org.springframework.jmx.export.metadata.ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException {
100-
ManagedMetric ann = AnnotationUtils.findAnnotation(method, ManagedMetric.class);
130+
MergedAnnotation<ManagedMetric> ann = MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE)
131+
.get(ManagedMetric.class).withNonMergedAttributes();
132+
101133
return copyPropertiesToBean(ann, org.springframework.jmx.export.metadata.ManagedMetric.class);
102134
}
103135

104136
@Override
105137
@Nullable
106138
public org.springframework.jmx.export.metadata.ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException {
107-
ManagedOperation ann = AnnotationUtils.findAnnotation(method, ManagedOperation.class);
139+
MergedAnnotation<ManagedOperation> ann = MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE)
140+
.get(ManagedOperation.class).withNonMergedAttributes();
141+
108142
return copyPropertiesToBean(ann, org.springframework.jmx.export.metadata.ManagedOperation.class);
109143
}
110144

111145
@Override
112146
public org.springframework.jmx.export.metadata.ManagedOperationParameter[] getManagedOperationParameters(Method method)
113147
throws InvalidMetadataException {
114148

115-
Set<ManagedOperationParameter> anns = AnnotationUtils.getRepeatableAnnotations(
149+
List<MergedAnnotation<? extends Annotation>> anns = getRepeatableAnnotations(
116150
method, ManagedOperationParameter.class, ManagedOperationParameters.class);
151+
117152
return copyPropertiesToBeanArray(anns, org.springframework.jmx.export.metadata.ManagedOperationParameter.class);
118153
}
119154

120155
@Override
121156
public org.springframework.jmx.export.metadata.ManagedNotification[] getManagedNotifications(Class<?> clazz)
122157
throws InvalidMetadataException {
123158

124-
Set<ManagedNotification> anns = AnnotationUtils.getRepeatableAnnotations(
159+
List<MergedAnnotation<? extends Annotation>> anns = getRepeatableAnnotations(
125160
clazz, ManagedNotification.class, ManagedNotifications.class);
161+
126162
return copyPropertiesToBeanArray(anns, org.springframework.jmx.export.metadata.ManagedNotification.class);
127163
}
128164

129165

166+
private static List<MergedAnnotation<? extends Annotation>> getRepeatableAnnotations(
167+
AnnotatedElement annotatedElement, Class<? extends Annotation> annotationType,
168+
Class<? extends Annotation> containerAnnotationType) {
169+
170+
return MergedAnnotations.from(annotatedElement, SearchStrategy.EXHAUSTIVE,
171+
RepeatableContainers.of(annotationType, containerAnnotationType), AnnotationFilter.PLAIN)
172+
.stream(annotationType)
173+
.filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex))
174+
.map(MergedAnnotation::withNonMergedAttributes)
175+
.collect(Collectors.toList());
176+
}
177+
130178
@SuppressWarnings("unchecked")
131-
private static <T> T[] copyPropertiesToBeanArray(Collection<? extends Annotation> anns, Class<T> beanClass) {
179+
private static <T> T[] copyPropertiesToBeanArray(
180+
List<MergedAnnotation<? extends Annotation>> anns, Class<T> beanClass) {
181+
132182
T[] beans = (T[]) Array.newInstance(beanClass, anns.size());
133183
int i = 0;
134-
for (Annotation ann : anns) {
184+
for (MergedAnnotation<? extends Annotation> ann : anns) {
135185
beans[i++] = copyPropertiesToBean(ann, beanClass);
136186
}
137187
return beans;
138188
}
139189

140190
@Nullable
141-
private static <T> T copyPropertiesToBean(@Nullable Annotation ann, Class<T> beanClass) {
142-
if (ann == null) {
191+
private static <T> T copyPropertiesToBean(MergedAnnotation<? extends Annotation> ann, Class<T> beanClass) {
192+
if (!ann.isPresent()) {
143193
return null;
144194
}
145195
T bean = BeanUtils.instantiateClass(beanClass);
146-
AnnotationBeanUtils.copyPropertiesToBean(ann, bean);
196+
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(bean);
197+
bw.setPropertyValues(new MutablePropertyValues(ann.asMap()));
147198
return bean;
148199
}
149200

0 commit comments

Comments
 (0)