Skip to content

Commit

Permalink
MBeanExporter silently ignores null beans
Browse files Browse the repository at this point in the history
Issue: SPR-15031
(cherry picked from commit e9def51)
  • Loading branch information
jhoeller committed Dec 19, 2016
1 parent 6075c81 commit 8c26717
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 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.
Expand Down Expand Up @@ -446,7 +446,7 @@ public ObjectName registerManagedResource(Object managedResource) throws MBeanEx
objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
}
}
catch (Exception ex) {
catch (Throwable ex) {
throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
}
registerManagedResource(managedResource, objectName);
Expand Down Expand Up @@ -548,15 +548,16 @@ protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, Stri
* should be exposed to the {@code MBeanServer}. Specifically, if the
* supplied {@code mapValue} is the name of a bean that is configured
* for lazy initialization, then a proxy to the resource is registered with
* the {@code MBeanServer} so that the the lazy load behavior is
* the {@code MBeanServer} so that the lazy load behavior is
* honored. If the bean is already an MBean then it will be registered
* directly with the {@code MBeanServer} without any intervention. For
* all other beans or bean names, the resource itself is registered with
* the {@code MBeanServer} directly.
* @param mapValue the value configured for this bean in the beans map;
* may be either the {@code String} name of a bean, or the bean itself
* @param beanKey the key associated with this bean in the beans map
* @return the {@code ObjectName} under which the resource was registered
* @return the {@code ObjectName} under which the resource was registered,
* or {@code null} if the actual resource was {@code null} as well
* @throws MBeanExportException if the export failed
* @see #setBeans
* @see #registerBeanInstance
Expand All @@ -577,12 +578,14 @@ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
}
else {
Object bean = this.beanFactory.getBean(beanName);
ObjectName objectName = registerBeanInstance(bean, beanKey);
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
return objectName;
if (bean != null) {
ObjectName objectName = registerBeanInstance(bean, beanKey);
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
return objectName;
}
}
}
else {
else if (mapValue != null) {
// Plain bean instance -> register it directly.
if (this.beanFactory != null) {
Map<String, ?> beansOfSameType =
Expand All @@ -599,10 +602,11 @@ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey)
return registerBeanInstance(mapValue, beanKey);
}
}
catch (Exception ex) {
catch (Throwable ex) {
throw new UnableToRegisterMBeanException(
"Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
}
return null;
}

/**
Expand Down Expand Up @@ -794,7 +798,7 @@ protected ModelMBean createAndConfigureMBean(Object managedResource, String bean
mbean.setManagedResource(managedResource, MR_TYPE_OBJECT_REFERENCE);
return mbean;
}
catch (Exception ex) {
catch (Throwable ex) {
throw new MBeanExportException("Could not create ModelMBean for managed resource [" +
managedResource + "] with key '" + beanKey + "'", ex);
}
Expand Down Expand Up @@ -960,7 +964,7 @@ private void registerNotificationListeners() throws MBeanExportException {
}
}
}
catch (Exception ex) {
catch (Throwable ex) {
throw new MBeanExportException("Unable to register NotificationListener", ex);
}
}
Expand All @@ -980,7 +984,7 @@ private void unregisterNotificationListeners() {
this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(),
bean.getNotificationFilter(), bean.getHandback());
}
catch (Exception ex) {
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Unable to unregister NotificationListener", ex);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 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.
Expand Down Expand Up @@ -35,8 +35,10 @@
import org.junit.Test;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jmx.AbstractMBeanServerTests;
Expand Down Expand Up @@ -677,6 +679,37 @@ public void testMBeanIsUnregisteredForRuntimeExceptionDuringInitialization() thr
ObjectNameManager.getInstance(objectName2));
}

@Test
public void testRegisterFactoryBean() throws MalformedObjectNameException {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("spring:type=FactoryBean", new RootBeanDefinition(ProperSomethingFactoryBean.class));

MBeanExporter exporter = new MBeanExporter();
exporter.setServer(getServer());
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
exporter.afterPropertiesSet();

assertIsRegistered("Non-null FactoryBean object registered",
ObjectNameManager.getInstance("spring:type=FactoryBean"));
}

@Test
public void testIgnoreNullObjectFromFactoryBean() throws MalformedObjectNameException {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("spring:type=FactoryBean", new RootBeanDefinition(NullSomethingFactoryBean.class));

MBeanExporter exporter = new MBeanExporter();
exporter.setServer(getServer());
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
exporter.afterPropertiesSet();

assertIsNotRegistered("Null FactoryBean object not registered",
ObjectNameManager.getInstance("spring:type=FactoryBean"));
}


private Map<String, Object> getBeanMap() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(OBJECT_NAME, new JmxTestBean());
Expand Down Expand Up @@ -805,4 +838,41 @@ public boolean includeBean(Class<?> beanClass, String beanName) {
}
}


public interface SomethingMBean {}

public static class Something implements SomethingMBean {}


public static class ProperSomethingFactoryBean implements FactoryBean<Something> {

public Something getObject() {
return new Something();
}

public Class<?> getObjectType() {
return Something.class;
}

public boolean isSingleton() {
return true;
}
}


public static class NullSomethingFactoryBean implements FactoryBean<Something> {

public Something getObject() {
return null;
}

public Class<?> getObjectType() {
return Something.class;
}

public boolean isSingleton() {
return true;
}
}

}

0 comments on commit 8c26717

Please sign in to comment.