diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java index 4fbe0e765f..0a802724ed 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java @@ -17,8 +17,12 @@ package org.springframework.jmx.export.annotation; import java.lang.annotation.Annotation; +import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Set; +import org.springframework.beans.BeanUtils; import org.springframework.beans.annotation.AnnotationBeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -26,25 +30,19 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.jmx.export.metadata.InvalidMetadataException; import org.springframework.jmx.export.metadata.JmxAttributeSource; -import org.springframework.jmx.export.metadata.ManagedAttribute; -import org.springframework.jmx.export.metadata.ManagedMetric; -import org.springframework.jmx.export.metadata.ManagedNotification; -import org.springframework.jmx.export.metadata.ManagedOperation; -import org.springframework.jmx.export.metadata.ManagedOperationParameter; -import org.springframework.jmx.export.metadata.ManagedResource; import org.springframework.util.StringValueResolver; /** * Implementation of the {@code JmxAttributeSource} interface that - * reads JDK 1.5+ annotations and exposes the corresponding attributes. + * reads annotations and exposes the corresponding attributes. * * @author Rob Harrop * @author Juergen Hoeller * @author Jennifer Hickey * @since 1.2 - * @see org.springframework.jmx.export.annotation.ManagedResource - * @see org.springframework.jmx.export.annotation.ManagedAttribute - * @see org.springframework.jmx.export.annotation.ManagedOperation + * @see ManagedResource + * @see ManagedAttribute + * @see ManagedOperation */ public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFactoryAware { @@ -66,25 +64,23 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFac } @Override - public ManagedResource getManagedResource(Class beanClass) throws InvalidMetadataException { - org.springframework.jmx.export.annotation.ManagedResource ann = - AnnotationUtils.getAnnotation(beanClass, org.springframework.jmx.export.annotation.ManagedResource.class); + public org.springframework.jmx.export.metadata.ManagedResource getManagedResource(Class beanClass) throws InvalidMetadataException { + ManagedResource ann = AnnotationUtils.findAnnotation(beanClass, ManagedResource.class); if (ann == null) { return null; } - ManagedResource managedResource = new ManagedResource(); + org.springframework.jmx.export.metadata.ManagedResource managedResource = new org.springframework.jmx.export.metadata.ManagedResource(); AnnotationBeanUtils.copyPropertiesToBean(ann, managedResource, this.embeddedValueResolver); return managedResource; } @Override - public ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException { - org.springframework.jmx.export.annotation.ManagedAttribute ann = - AnnotationUtils.findAnnotation(method, org.springframework.jmx.export.annotation.ManagedAttribute.class); + public org.springframework.jmx.export.metadata.ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException { + ManagedAttribute ann = AnnotationUtils.findAnnotation(method, ManagedAttribute.class); if (ann == null) { return null; } - ManagedAttribute managedAttribute = new ManagedAttribute(); + org.springframework.jmx.export.metadata.ManagedAttribute managedAttribute = new org.springframework.jmx.export.metadata.ManagedAttribute(); AnnotationBeanUtils.copyPropertiesToBean(ann, managedAttribute, "defaultValue"); if (ann.defaultValue().length() > 0) { managedAttribute.setDefaultValue(ann.defaultValue()); @@ -93,65 +89,53 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFac } @Override - public ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException { - org.springframework.jmx.export.annotation.ManagedMetric ann = - AnnotationUtils.findAnnotation(method, org.springframework.jmx.export.annotation.ManagedMetric.class); - if (ann == null) { - return null; - } - ManagedMetric managedMetric = new ManagedMetric(); - AnnotationBeanUtils.copyPropertiesToBean(ann, managedMetric); - return managedMetric; + public org.springframework.jmx.export.metadata.ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException { + ManagedMetric ann = AnnotationUtils.findAnnotation(method, ManagedMetric.class); + return copyPropertiesToBean(ann, org.springframework.jmx.export.metadata.ManagedMetric.class); } @Override - public ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException { - Annotation ann = AnnotationUtils.findAnnotation(method, org.springframework.jmx.export.annotation.ManagedOperation.class); - if (ann == null) { - return null; - } - ManagedOperation op = new ManagedOperation(); - AnnotationBeanUtils.copyPropertiesToBean(ann, op); - return op; + public org.springframework.jmx.export.metadata.ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException { + ManagedOperation ann = AnnotationUtils.findAnnotation(method, ManagedOperation.class); + return copyPropertiesToBean(ann, org.springframework.jmx.export.metadata.ManagedOperation.class); } @Override - public ManagedOperationParameter[] getManagedOperationParameters(Method method) + public org.springframework.jmx.export.metadata.ManagedOperationParameter[] getManagedOperationParameters(Method method) throws InvalidMetadataException { - ManagedOperationParameters params = AnnotationUtils.findAnnotation(method, ManagedOperationParameters.class); - ManagedOperationParameter[] result = null; - if (params == null) { - result = new ManagedOperationParameter[0]; - } - else { - Annotation[] paramData = params.value(); - result = new ManagedOperationParameter[paramData.length]; - for (int i = 0; i < paramData.length; i++) { - Annotation annotation = paramData[i]; - ManagedOperationParameter managedOperationParameter = new ManagedOperationParameter(); - AnnotationBeanUtils.copyPropertiesToBean(annotation, managedOperationParameter); - result[i] = managedOperationParameter; - } - } - return result; + Set anns = AnnotationUtils.getRepeatableAnnotations( + method, ManagedOperationParameter.class, ManagedOperationParameters.class); + return copyPropertiesToBeanArray(anns, org.springframework.jmx.export.metadata.ManagedOperationParameter.class); } @Override - public ManagedNotification[] getManagedNotifications(Class clazz) throws InvalidMetadataException { - ManagedNotifications notificationsAnn = AnnotationUtils.getAnnotation(clazz, ManagedNotifications.class); - if (notificationsAnn == null) { - return new ManagedNotification[0]; + public org.springframework.jmx.export.metadata.ManagedNotification[] getManagedNotifications(Class clazz) + throws InvalidMetadataException { + + Set anns = AnnotationUtils.getRepeatableAnnotations( + clazz, ManagedNotification.class, ManagedNotifications.class); + return copyPropertiesToBeanArray(anns, org.springframework.jmx.export.metadata.ManagedNotification.class); + } + + + @SuppressWarnings("unchecked") + private static T[] copyPropertiesToBeanArray(Collection anns, Class beanClass) { + T[] beans = (T[]) Array.newInstance(beanClass, anns.size()); + int i = 0; + for (Annotation ann : anns) { + beans[i++] = copyPropertiesToBean(ann, beanClass); } - Annotation[] notifications = notificationsAnn.value(); - ManagedNotification[] result = new ManagedNotification[notifications.length]; - for (int i = 0; i < notifications.length; i++) { - Annotation notification = notifications[i]; - ManagedNotification managedNotification = new ManagedNotification(); - AnnotationBeanUtils.copyPropertiesToBean(notification, managedNotification); - result[i] = managedNotification; + return beans; + } + + private static T copyPropertiesToBean(Annotation ann, Class beanClass) { + if (ann == null) { + return null; } - return result; + T bean = BeanUtils.instantiate(beanClass); + AnnotationBeanUtils.copyPropertiesToBean(ann, bean); + return bean; } } diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedAttribute.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedAttribute.java index 544783d463..ccdfc0eebd 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedAttribute.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * JDK 1.5+ method-level annotation that indicates to expose a given bean - * property as JMX attribute, corresponding to the ManagedAttribute attribute. + * Method-level annotation that indicates to expose a given bean property as a + * JMX attribute, corresponding to the {@code ManagedAttribute} attribute. * Only valid when used on a JavaBean getter or setter. * * @author Rob Harrop diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedMetric.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedMetric.java index 5adfc012a9..49f0f5c040 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedMetric.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedMetric.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,9 +25,9 @@ import java.lang.annotation.Target; import org.springframework.jmx.support.MetricType; /** - * JDK 1.5+ method-level annotation that indicates to expose a given bean - * property as JMX attribute, with added Descriptor properties to indicate that - * it is a metric. Only valid when used on a JavaBean getter. + * Method-level annotation that indicates to expose a given bean property as a + * JMX attribute, with added descriptor properties to indicate that it is a metric. + * Only valid when used on a JavaBean getter. * * @author Jennifer Hickey * @since 3.0 diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotification.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotification.java index 02b4ed7bba..cccf54a2b0 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotification.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotification.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,15 @@ package org.springframework.jmx.export.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * JDK 1.5+ method-level annotation that indicates a JMX notification - * emitted by a bean. + * Type-level annotation that indicates a JMX notification emitted by a bean. + * + *

As of Spring Framework 4.2.4, this annotation is declared as repeatable. * * @author Rob Harrop * @since 2.0 @@ -35,6 +37,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented +@Repeatable(ManagedNotifications.class) public @interface ManagedNotification { String name(); diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotifications.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotifications.java index abffc3e08f..7c2f2aba41 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotifications.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotifications.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +24,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * JDK 1.5+ method-level annotation that indicates JMX notifications emitted by - * a bean, containing multiple {@link ManagedNotification ManagedNotifications} + * Type-level annotation that indicates JMX notifications emitted by a bean, + * containing multiple {@link ManagedNotification ManagedNotifications} * * @author Rob Harrop * @since 2.0 diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperation.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperation.java index 2d813b102c..c66fa981c4 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperation.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * JDK 1.5+ method-level annotation that indicates to expose a given method - * as JMX operation, corresponding to the ManagedOperation attribute. + * Method-level annotation that indicates to expose a given method as a + * JMX operation, corresponding to the {@code ManagedOperation} attribute. * Only valid when used on a method that is not a JavaBean getter or setter. * * @author Rob Harrop diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameter.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameter.java index 1ddbd3400f..c826969e5d 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameter.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,29 @@ package org.springframework.jmx.export.annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** - * JDK 1.5+ method-level annotation used to provide metadata about operation - * parameters, corresponding to a {@code ManagedOperationParameter} attribute. - * Used as part of a {@code ManagedOperationParameters} annotation. + * Method-level annotation used to provide metadata about operation parameters, + * corresponding to a {@code ManagedOperationParameter} attribute. + * Used as part of a {@link ManagedOperationParameters} annotation. + * + *

As of Spring Framework 4.2.4, this annotation is declared as repeatable. * * @author Rob Harrop * @since 1.2 * @see ManagedOperationParameters#value * @see org.springframework.jmx.export.metadata.ManagedOperationParameter */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Repeatable(ManagedOperationParameters.class) public @interface ManagedOperationParameter { String name(); diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameters.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameters.java index 8c01f19195..1f5d4b7942 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameters.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameters.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * JDK 1.5+ method-level annotation used to provide metadata about - * operation parameters, corresponding to an array of - * {@code ManagedOperationParameter} attributes. + * Method-level annotation used to provide metadata about operation parameters, + * corresponding to an array of {@code ManagedOperationParameter} attributes. * * @author Rob Harrop * @since 1.2 diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedResource.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedResource.java index 555a65d48f..071fce21c7 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedResource.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedResource.java @@ -26,8 +26,8 @@ import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; /** - * JDK 1.5+ class-level annotation that indicates to register instances of a - * class with a JMX server, corresponding to the ManagedResource attribute. + * Class-level annotation that indicates to register instances of a class + * with a JMX server, corresponding to the {@code ManagedResource} attribute. * *

Note: This annotation is marked as inherited, allowing for generic * management-aware base classes. In such a scenario, it is recommended to diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java index 191b2f9ae3..0618e8422c 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * 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 @@ -28,7 +28,7 @@ import org.springframework.stereotype.Service; @ManagedResource(objectName = "bean:name=testBean4", description = "My Managed Bean", log = true, logFile = "jmx.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200, persistLocation = "./foo", persistName = "bar.jmx") -@ManagedNotifications({@ManagedNotification(name="My Notification", notificationTypes={"type.foo", "type.bar"})}) +@ManagedNotification(name="My Notification", notificationTypes={"type.foo", "type.bar"}) public class AnnotationTestBean implements IJmxTestBean { private String name; @@ -91,9 +91,9 @@ public class AnnotationTestBean implements IJmxTestBean { } @Override - @org.springframework.jmx.export.annotation.ManagedOperation(description = "Add Two Numbers Together") - @ManagedOperationParameters({@ManagedOperationParameter(name="x", description="Left operand"), - @ManagedOperationParameter(name="y", description="Right operand")}) + @ManagedOperation(description = "Add Two Numbers Together") + @ManagedOperationParameter(name="x", description="Left operand") + @ManagedOperationParameter(name="y", description="Right operand") public int add(int x, int y) { return x + y; } @@ -117,6 +117,4 @@ public class AnnotationTestBean implements IJmxTestBean { return 3; } - - }