[SPR-3635] [SPR-5039] [SPR-5813] JMX annotation inheritance fixed

This commit is contained in:
Rob Harrop 2009-09-08 21:37:02 +00:00
parent 7f7173f790
commit 8f6a42bf64
10 changed files with 177 additions and 11 deletions

View File

@ -7,7 +7,7 @@ ivy.cache.dir=${basedir}/../ivy-cache
integration.repo.dir=${basedir}/../integration-repo integration.repo.dir=${basedir}/../integration-repo
javadoc.exclude.package.names=org/springframework/samples/** javadoc.exclude.package.names=org/springframework/samples/**
javadoc.max.memory=256M javadoc.max.memory=256M
test.vm.args=-XX:MaxPermSize=128M test.vm.args=-Xmx1024M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError
compiler.args=-enableJavadoc -warn:none compiler.args=-enableJavadoc -warn:none
# For when releasing # For when releasing

View File

@ -225,7 +225,6 @@ public class GenericBean<T> {
this.customEnum = customEnum; this.customEnum = customEnum;
} }
public static GenericBean createInstance(Set<Integer> integerSet) { public static GenericBean createInstance(Set<Integer> integerSet) {
return new GenericBean(integerSet); return new GenericBean(integerSet);
} }

View File

@ -63,7 +63,7 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource {
public ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException { public ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException {
org.springframework.jmx.export.annotation.ManagedAttribute ann = org.springframework.jmx.export.annotation.ManagedAttribute ann =
AnnotationUtils.getAnnotation(method, org.springframework.jmx.export.annotation.ManagedAttribute.class); AnnotationUtils.findAnnotation(method, org.springframework.jmx.export.annotation.ManagedAttribute.class);
if (ann == null) { if (ann == null) {
return null; return null;
} }
@ -77,7 +77,7 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource {
public ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException { public ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException {
org.springframework.jmx.export.annotation.ManagedMetric ann = org.springframework.jmx.export.annotation.ManagedMetric ann =
AnnotationUtils.getAnnotation(method, org.springframework.jmx.export.annotation.ManagedMetric.class); AnnotationUtils.findAnnotation(method, org.springframework.jmx.export.annotation.ManagedMetric.class);
if (ann == null) { if (ann == null) {
return null; return null;
} }
@ -92,7 +92,7 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource {
throw new InvalidMetadataException( throw new InvalidMetadataException(
"The ManagedOperation attribute is not valid for JavaBean properties. Use ManagedAttribute instead."); "The ManagedOperation attribute is not valid for JavaBean properties. Use ManagedAttribute instead.");
} }
Annotation ann = AnnotationUtils.getAnnotation(method, org.springframework.jmx.export.annotation.ManagedOperation.class); Annotation ann = AnnotationUtils.findAnnotation(method, org.springframework.jmx.export.annotation.ManagedOperation.class);
if (ann == null) { if (ann == null) {
return null; return null;
} }
@ -104,7 +104,7 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource {
public ManagedOperationParameter[] getManagedOperationParameters(Method method) public ManagedOperationParameter[] getManagedOperationParameters(Method method)
throws InvalidMetadataException { throws InvalidMetadataException {
ManagedOperationParameters params = AnnotationUtils.getAnnotation(method, ManagedOperationParameters.class); ManagedOperationParameters params = AnnotationUtils.findAnnotation(method, ManagedOperationParameters.class);
ManagedOperationParameter[] result = null; ManagedOperationParameter[] result = null;
if (params == null) { if (params == null) {
result = new ManagedOperationParameter[0]; result = new ManagedOperationParameter[0];

View File

@ -16,17 +16,32 @@
package org.springframework.jmx.export.annotation; package org.springframework.jmx.export.annotation;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.springframework.jmx.IJmxTestBean; import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.export.assembler.AbstractMetadataAssemblerTests; import org.springframework.jmx.export.assembler.AbstractMetadataAssemblerTests;
import org.springframework.jmx.export.metadata.JmxAttributeSource; import org.springframework.jmx.export.metadata.JmxAttributeSource;
/** /** @author Rob Harrop */
* @author Rob Harrop
*/
public class AnnotationMetadataAssemblerTests extends AbstractMetadataAssemblerTests { public class AnnotationMetadataAssemblerTests extends AbstractMetadataAssemblerTests {
private static final String OBJECT_NAME = "bean:name=testBean4"; private static final String OBJECT_NAME = "bean:name=testBean4";
public void testAttributeFromInterface() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute("Colour");
assertTrue("The name attribute should be writable", attr.isWritable());
assertTrue("The name attribute should be readable", attr.isReadable());
}
public void testOperationFromInterface() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanOperationInfo op = inf.getOperation("fromInterface");
assertNotNull(op);
}
protected JmxAttributeSource getAttributeSource() { protected JmxAttributeSource getAttributeSource() {
return new AnnotationJmxAttributeSource(); return new AnnotationJmxAttributeSource();
} }
@ -36,11 +51,20 @@ public class AnnotationMetadataAssemblerTests extends AbstractMetadataAssemblerT
} }
protected IJmxTestBean createJmxTestBean() { protected IJmxTestBean createJmxTestBean() {
return new AnnotationTestBean(); return new AnnotationTestSubBean();
} }
protected String getApplicationContextPath() { protected String getApplicationContextPath() {
return "org/springframework/jmx/export/annotation/annotations.xml"; return "org/springframework/jmx/export/annotation/annotations.xml";
} }
@Override
protected int getExpectedAttributeCount() {
return super.getExpectedAttributeCount() + 1;
}
@Override
protected int getExpectedOperationCount() {
return super.getExpectedOperationCount() + 3;
}
} }

View File

@ -0,0 +1,51 @@
/*
* Copyright 2002-2009 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 the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jmx.export.annotation;
/**
* @author Rob Harrop
*/
public class AnnotationTestSubBean extends AnnotationTestBean implements IAnnotationTestBean {
private String colour;
@Override
public long myOperation() {
return 123L;
}
@Override
public void setAge(int age) {
super.setAge(age);
}
@Override
public int getAge() {
return super.getAge();
}
public String getColour() {
return this.colour;
}
public void setColour(String colour) {
this.colour = colour;
}
public void fromInterface() {
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2002-2009 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 the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jmx.export.annotation;
/**
* @author Rob Harrop
*/
public interface IAnnotationTestBean {
@ManagedAttribute
String getColour();
@ManagedAttribute
void setColour(String colour);
@ManagedOperation
void fromInterface();
}

View File

@ -19,7 +19,7 @@
</property> </property>
</bean> </bean>
<bean id="testBean" class="org.springframework.jmx.export.annotation.AnnotationTestBean"> <bean id="testBean" class="org.springframework.jmx.export.annotation.AnnotationTestSubBean">
<property name="name"> <property name="name">
<value>TEST</value> <value>TEST</value>
</property> </property>

View File

@ -18,6 +18,7 @@ package org.springframework.jmx.export.assembler;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Arrays;
import javax.management.Descriptor; import javax.management.Descriptor;
import javax.management.MBeanInfo; import javax.management.MBeanInfo;

View File

@ -101,6 +101,9 @@ public abstract class AnnotationUtils {
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) { public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
A annotation = getAnnotation(method, annotationType); A annotation = getAnnotation(method, annotationType);
Class<?> cl = method.getDeclaringClass(); Class<?> cl = method.getDeclaringClass();
if(annotation == null) {
annotation = searchForAnnotationOnInterfaces(method, annotationType, cl.getInterfaces());
}
while (annotation == null) { while (annotation == null) {
cl = cl.getSuperclass(); cl = cl.getSuperclass();
if (cl == null || cl == Object.class) { if (cl == null || cl == Object.class) {
@ -109,6 +112,9 @@ public abstract class AnnotationUtils {
try { try {
Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes()); Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());
annotation = getAnnotation(equivalentMethod, annotationType); annotation = getAnnotation(equivalentMethod, annotationType);
if(annotation == null) {
annotation = searchForAnnotationOnInterfaces(method, annotationType, cl.getInterfaces());
}
} }
catch (NoSuchMethodException ex) { catch (NoSuchMethodException ex) {
// We're done... // We're done...
@ -117,6 +123,24 @@ public abstract class AnnotationUtils {
return annotation; return annotation;
} }
private static <A extends Annotation> A searchForAnnotationOnInterfaces(Method method, Class<A> annotationType, Class[] ifaces) {
A annotation = null;
for (Class<?> iface : ifaces) {
Method equivalentMethod = null;
try {
equivalentMethod = iface.getDeclaredMethod(method.getName(), method.getParameterTypes());
annotation = getAnnotation(equivalentMethod, annotationType);
}
catch (NoSuchMethodException e) {
// skip this interface - it doesn't have the method
}
if (annotation != null) {
break;
}
}
return annotation;
}
/** /**
* Find a single {@link Annotation} of <code>annotationType</code> from the * Find a single {@link Annotation} of <code>annotationType</code> from the
* supplied {@link Class}, traversing its interfaces and super classes * supplied {@link Class}, traversing its interfaces and super classes

View File

@ -188,6 +188,22 @@ public class AnnotationUtilsTests {
assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(Order.class)); assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(Order.class));
} }
@Test
public void testFindAnnotationFromInterface() throws Exception {
Method method = ImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
Order order = findAnnotation(method, Order.class);
assertNotNull(order);
}
@Test
public void testFindAnnotationFromInterfaceOnSuper() throws Exception {
Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
Order order = findAnnotation(method, Order.class);
assertNotNull(order);
}
public static interface AnnotatedInterface { public static interface AnnotatedInterface {
@Order(0) @Order(0)
@ -286,6 +302,25 @@ public class AnnotationUtilsTests {
public static class SubNonInheritedAnnotationClass extends NonInheritedAnnotationClass { public static class SubNonInheritedAnnotationClass extends NonInheritedAnnotationClass {
} }
public static interface InterfaceWithAnnotatedMethod {
@Order
void foo();
}
public static class ImplementsInterfaceWithAnnotatedMethod implements InterfaceWithAnnotatedMethod {
public void foo() {
}
}
public static class SubOfImplementsInterfaceWithAnnotatedMethod extends ImplementsInterfaceWithAnnotatedMethod {
public void foo() {
}
}
} }
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)