Skip to content

Commit 8c26717

Browse files
committed
MBeanExporter silently ignores null beans
Issue: SPR-15031 (cherry picked from commit e9def51)
1 parent 6075c81 commit 8c26717

File tree

2 files changed

+87
-13
lines changed

2 files changed

+87
-13
lines changed

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

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 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.
@@ -446,7 +446,7 @@ public ObjectName registerManagedResource(Object managedResource) throws MBeanEx
446446
objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
447447
}
448448
}
449-
catch (Exception ex) {
449+
catch (Throwable ex) {
450450
throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
451451
}
452452
registerManagedResource(managedResource, objectName);
@@ -548,15 +548,16 @@ protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, Stri
548548
* should be exposed to the {@code MBeanServer}. Specifically, if the
549549
* supplied {@code mapValue} is the name of a bean that is configured
550550
* for lazy initialization, then a proxy to the resource is registered with
551-
* the {@code MBeanServer} so that the the lazy load behavior is
551+
* the {@code MBeanServer} so that the lazy load behavior is
552552
* honored. If the bean is already an MBean then it will be registered
553553
* directly with the {@code MBeanServer} without any intervention. For
554554
* all other beans or bean names, the resource itself is registered with
555555
* the {@code MBeanServer} directly.
556556
* @param mapValue the value configured for this bean in the beans map;
557557
* may be either the {@code String} name of a bean, or the bean itself
558558
* @param beanKey the key associated with this bean in the beans map
559-
* @return the {@code ObjectName} under which the resource was registered
559+
* @return the {@code ObjectName} under which the resource was registered,
560+
* or {@code null} if the actual resource was {@code null} as well
560561
* @throws MBeanExportException if the export failed
561562
* @see #setBeans
562563
* @see #registerBeanInstance
@@ -577,12 +578,14 @@ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
577578
}
578579
else {
579580
Object bean = this.beanFactory.getBean(beanName);
580-
ObjectName objectName = registerBeanInstance(bean, beanKey);
581-
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
582-
return objectName;
581+
if (bean != null) {
582+
ObjectName objectName = registerBeanInstance(bean, beanKey);
583+
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
584+
return objectName;
585+
}
583586
}
584587
}
585-
else {
588+
else if (mapValue != null) {
586589
// Plain bean instance -> register it directly.
587590
if (this.beanFactory != null) {
588591
Map<String, ?> beansOfSameType =
@@ -599,10 +602,11 @@ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
599602
return registerBeanInstance(mapValue, beanKey);
600603
}
601604
}
602-
catch (Exception ex) {
605+
catch (Throwable ex) {
603606
throw new UnableToRegisterMBeanException(
604607
"Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
605608
}
609+
return null;
606610
}
607611

608612
/**
@@ -794,7 +798,7 @@ protected ModelMBean createAndConfigureMBean(Object managedResource, String bean
794798
mbean.setManagedResource(managedResource, MR_TYPE_OBJECT_REFERENCE);
795799
return mbean;
796800
}
797-
catch (Exception ex) {
801+
catch (Throwable ex) {
798802
throw new MBeanExportException("Could not create ModelMBean for managed resource [" +
799803
managedResource + "] with key '" + beanKey + "'", ex);
800804
}
@@ -960,7 +964,7 @@ private void registerNotificationListeners() throws MBeanExportException {
960964
}
961965
}
962966
}
963-
catch (Exception ex) {
967+
catch (Throwable ex) {
964968
throw new MBeanExportException("Unable to register NotificationListener", ex);
965969
}
966970
}
@@ -980,7 +984,7 @@ private void unregisterNotificationListeners() {
980984
this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(),
981985
bean.getNotificationFilter(), bean.getHandback());
982986
}
983-
catch (Exception ex) {
987+
catch (Throwable ex) {
984988
if (logger.isDebugEnabled()) {
985989
logger.debug("Unable to unregister NotificationListener", ex);
986990
}

spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 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.
@@ -35,8 +35,10 @@
3535
import org.junit.Test;
3636

3737
import org.springframework.aop.framework.ProxyFactory;
38+
import org.springframework.beans.factory.FactoryBean;
3839
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3940
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
41+
import org.springframework.beans.factory.support.RootBeanDefinition;
4042
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
4143
import org.springframework.core.io.ClassPathResource;
4244
import org.springframework.jmx.AbstractMBeanServerTests;
@@ -677,6 +679,37 @@ public void testMBeanIsUnregisteredForRuntimeExceptionDuringInitialization() thr
677679
ObjectNameManager.getInstance(objectName2));
678680
}
679681

682+
@Test
683+
public void testRegisterFactoryBean() throws MalformedObjectNameException {
684+
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
685+
factory.registerBeanDefinition("spring:type=FactoryBean", new RootBeanDefinition(ProperSomethingFactoryBean.class));
686+
687+
MBeanExporter exporter = new MBeanExporter();
688+
exporter.setServer(getServer());
689+
exporter.setBeanFactory(factory);
690+
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
691+
exporter.afterPropertiesSet();
692+
693+
assertIsRegistered("Non-null FactoryBean object registered",
694+
ObjectNameManager.getInstance("spring:type=FactoryBean"));
695+
}
696+
697+
@Test
698+
public void testIgnoreNullObjectFromFactoryBean() throws MalformedObjectNameException {
699+
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
700+
factory.registerBeanDefinition("spring:type=FactoryBean", new RootBeanDefinition(NullSomethingFactoryBean.class));
701+
702+
MBeanExporter exporter = new MBeanExporter();
703+
exporter.setServer(getServer());
704+
exporter.setBeanFactory(factory);
705+
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
706+
exporter.afterPropertiesSet();
707+
708+
assertIsNotRegistered("Null FactoryBean object not registered",
709+
ObjectNameManager.getInstance("spring:type=FactoryBean"));
710+
}
711+
712+
680713
private Map<String, Object> getBeanMap() {
681714
Map<String, Object> map = new HashMap<String, Object>();
682715
map.put(OBJECT_NAME, new JmxTestBean());
@@ -805,4 +838,41 @@ public boolean includeBean(Class<?> beanClass, String beanName) {
805838
}
806839
}
807840

841+
842+
public interface SomethingMBean {}
843+
844+
public static class Something implements SomethingMBean {}
845+
846+
847+
public static class ProperSomethingFactoryBean implements FactoryBean<Something> {
848+
849+
public Something getObject() {
850+
return new Something();
851+
}
852+
853+
public Class<?> getObjectType() {
854+
return Something.class;
855+
}
856+
857+
public boolean isSingleton() {
858+
return true;
859+
}
860+
}
861+
862+
863+
public static class NullSomethingFactoryBean implements FactoryBean<Something> {
864+
865+
public Something getObject() {
866+
return null;
867+
}
868+
869+
public Class<?> getObjectType() {
870+
return Something.class;
871+
}
872+
873+
public boolean isSingleton() {
874+
return true;
875+
}
876+
}
877+
808878
}

0 commit comments

Comments
 (0)