Skip to content

Commit 9c55d22

Browse files
committed
MBeanExporter silently ignores null beans
Issue: SPR-15031
1 parent e0c43c4 commit 9c55d22

File tree

2 files changed

+88
-25
lines changed

2 files changed

+88
-25
lines changed

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
* via the {@link #setListeners(MBeanExporterListener[]) listeners} property, allowing
8484
* application code to be notified of MBean registration and unregistration events.
8585
*
86-
* <p>This exporter is compatible with MBeans and MXBeans on Java 6 and above.
86+
* <p>This exporter is compatible with MBeans as well as MXBeans.
8787
*
8888
* @author Rob Harrop
8989
* @author Juergen Hoeller
@@ -466,7 +466,7 @@ public ObjectName registerManagedResource(Object managedResource) throws MBeanEx
466466
objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
467467
}
468468
}
469-
catch (Exception ex) {
469+
catch (Throwable ex) {
470470
throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
471471
}
472472
registerManagedResource(managedResource, objectName);
@@ -578,7 +578,8 @@ protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, Stri
578578
* @param mapValue the value configured for this bean in the beans map;
579579
* may be either the {@code String} name of a bean, or the bean itself
580580
* @param beanKey the key associated with this bean in the beans map
581-
* @return the {@code ObjectName} under which the resource was registered
581+
* @return the {@code ObjectName} under which the resource was registered,
582+
* or {@code null} if the actual resource was {@code null} as well
582583
* @throws MBeanExportException if the export failed
583584
* @see #setBeans
584585
* @see #registerBeanInstance
@@ -599,12 +600,14 @@ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
599600
}
600601
else {
601602
Object bean = this.beanFactory.getBean(beanName);
602-
ObjectName objectName = registerBeanInstance(bean, beanKey);
603-
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
604-
return objectName;
603+
if (bean != null) {
604+
ObjectName objectName = registerBeanInstance(bean, beanKey);
605+
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
606+
return objectName;
607+
}
605608
}
606609
}
607-
else {
610+
else if (mapValue != null) {
608611
// Plain bean instance -> register it directly.
609612
if (this.beanFactory != null) {
610613
Map<String, ?> beansOfSameType =
@@ -621,10 +624,11 @@ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
621624
return registerBeanInstance(mapValue, beanKey);
622625
}
623626
}
624-
catch (Exception ex) {
627+
catch (Throwable ex) {
625628
throw new UnableToRegisterMBeanException(
626629
"Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
627630
}
631+
return null;
628632
}
629633

630634
/**
@@ -816,7 +820,7 @@ protected ModelMBean createAndConfigureMBean(Object managedResource, String bean
816820
mbean.setManagedResource(managedResource, MR_TYPE_OBJECT_REFERENCE);
817821
return mbean;
818822
}
819-
catch (Exception ex) {
823+
catch (Throwable ex) {
820824
throw new MBeanExportException("Could not create ModelMBean for managed resource [" +
821825
managedResource + "] with key '" + beanKey + "'", ex);
822826
}
@@ -984,7 +988,7 @@ private void registerNotificationListeners() throws MBeanExportException {
984988
}
985989
}
986990
}
987-
catch (Exception ex) {
991+
catch (Throwable ex) {
988992
throw new MBeanExportException("Unable to register NotificationListener", ex);
989993
}
990994
}
@@ -1004,7 +1008,7 @@ private void unregisterNotificationListeners() {
10041008
this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(),
10051009
bean.getNotificationFilter(), bean.getHandback());
10061010
}
1007-
catch (Exception ex) {
1011+
catch (Throwable ex) {
10081012
if (logger.isDebugEnabled()) {
10091013
logger.debug("Unable to unregister NotificationListener", ex);
10101014
}

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

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
import org.junit.rules.ExpectedException;
4040

4141
import org.springframework.aop.framework.ProxyFactory;
42+
import org.springframework.beans.factory.FactoryBean;
4243
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
4344
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
45+
import org.springframework.beans.factory.support.RootBeanDefinition;
4446
import org.springframework.context.ConfigurableApplicationContext;
4547
import org.springframework.context.support.ClassPathXmlApplicationContext;
4648
import org.springframework.jmx.AbstractMBeanServerTests;
@@ -68,7 +70,6 @@
6870
* @author Sam Brannen
6971
* @author Stephane Nicoll
7072
*/
71-
@SuppressWarnings("deprecation")
7273
public class MBeanExporterTests extends AbstractMBeanServerTests {
7374

7475
@Rule
@@ -235,7 +236,6 @@ public void testWithMBeanExporterListeners() throws Exception {
235236
assertListener(listener2);
236237
}
237238

238-
239239
@Test
240240
public void testExportJdkProxy() throws Exception {
241241
JmxTestBean bean = new JmxTestBean();
@@ -541,10 +541,7 @@ public void testNotRunningInBeanFactoryAndAutodetectionIsOn() throws Exception {
541541
start(exporter);
542542
}
543543

544-
/**
545-
* SPR-2158
546-
*/
547-
@Test
544+
@Test // SPR-2158
548545
public void testMBeanIsNotUnregisteredSpuriouslyIfSomeExternalProcessHasUnregisteredMBean() throws Exception {
549546
MBeanExporter exporter = new MBeanExporter();
550547
exporter.setBeans(getBeanMap());
@@ -561,10 +558,7 @@ public void testMBeanIsNotUnregisteredSpuriouslyIfSomeExternalProcessHasUnregist
561558
listener.getUnregistered().size());
562559
}
563560

564-
/**
565-
* SPR-3302
566-
*/
567-
@Test
561+
@Test // SPR-3302
568562
public void testBeanNameCanBeUsedInNotificationListenersMap() throws Exception {
569563
String beanName = "charlesDexterWard";
570564
BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class);
@@ -608,10 +602,7 @@ public void testWildcardCanBeUsedInNotificationListenersMap() throws Exception {
608602
start(exporter);
609603
}
610604

611-
/*
612-
* SPR-3625
613-
*/
614-
@Test
605+
@Test // SPR-3625
615606
public void testMBeanIsUnregisteredForRuntimeExceptionDuringInitialization() throws Exception {
616607
BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
617608
BeanDefinitionBuilder builder2 = BeanDefinitionBuilder
@@ -667,6 +658,37 @@ public void testIgnoreBeanName() throws MalformedObjectNameException {
667658
ObjectNameManager.getInstance(secondBeanName));
668659
}
669660

661+
@Test
662+
public void testRegisterFactoryBean() throws MalformedObjectNameException {
663+
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
664+
factory.registerBeanDefinition("spring:type=FactoryBean", new RootBeanDefinition(ProperSomethingFactoryBean.class));
665+
666+
MBeanExporter exporter = new MBeanExporter();
667+
exporter.setServer(getServer());
668+
exporter.setBeanFactory(factory);
669+
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
670+
671+
start(exporter);
672+
assertIsRegistered("Non-null FactoryBean object registered",
673+
ObjectNameManager.getInstance("spring:type=FactoryBean"));
674+
}
675+
676+
@Test
677+
public void testIgnoreNullObjectFromFactoryBean() throws MalformedObjectNameException {
678+
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
679+
factory.registerBeanDefinition("spring:type=FactoryBean", new RootBeanDefinition(NullSomethingFactoryBean.class));
680+
681+
MBeanExporter exporter = new MBeanExporter();
682+
exporter.setServer(getServer());
683+
exporter.setBeanFactory(factory);
684+
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
685+
686+
start(exporter);
687+
assertIsNotRegistered("Null FactoryBean object not registered",
688+
ObjectNameManager.getInstance("spring:type=FactoryBean"));
689+
}
690+
691+
670692
private ConfigurableApplicationContext load(String context) {
671693
return new ClassPathXmlApplicationContext(context, getClass());
672694
}
@@ -799,4 +821,41 @@ public boolean includeBean(Class<?> beanClass, String beanName) {
799821
}
800822
}
801823

824+
825+
public interface SomethingMBean {}
826+
827+
public static class Something implements SomethingMBean {}
828+
829+
830+
public static class ProperSomethingFactoryBean implements FactoryBean<Something> {
831+
832+
@Override public Something getObject() {
833+
return new Something();
834+
}
835+
836+
@Override public Class<?> getObjectType() {
837+
return Something.class;
838+
}
839+
840+
@Override public boolean isSingleton() {
841+
return true;
842+
}
843+
}
844+
845+
846+
public static class NullSomethingFactoryBean implements FactoryBean<Something> {
847+
848+
@Override public Something getObject() {
849+
return null;
850+
}
851+
852+
@Override public Class<?> getObjectType() {
853+
return Something.class;
854+
}
855+
856+
@Override public boolean isSingleton() {
857+
return true;
858+
}
859+
}
860+
802861
}

0 commit comments

Comments
 (0)