/* * 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. * 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; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.management.Attribute; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.modelmbean.ModelMBeanInfo; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; 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.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jmx.AbstractMBeanServerTests; import org.springframework.jmx.IJmxTestBean; import org.springframework.jmx.JmxTestBean; import org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler; import org.springframework.jmx.export.assembler.MBeanInfoAssembler; import org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler; import org.springframework.jmx.export.naming.SelfNaming; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.jmx.support.RegistrationPolicy; import org.springframework.tests.aop.interceptor.NopInterceptor; import org.springframework.tests.sample.beans.TestBean; import static org.junit.Assert.*; /** * Integration tests for the {@link MBeanExporter} class. * * @author Rob Harrop * @author Juergen Hoeller * @author Rick Evans * @author Mark Fisher * @author Chris Beams * @author Sam Brannen * @author Stephane Nicoll */ public class MBeanExporterTests extends AbstractMBeanServerTests { @Rule public final ExpectedException thrown = ExpectedException.none(); private static final String OBJECT_NAME = "spring:test=jmxMBeanAdaptor"; @Test public void testRegisterNullNotificationListenerType() throws Exception { Map<String, NotificationListener> listeners = new HashMap<>(); // put null in as a value... listeners.put("*", null); MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setNotificationListenerMappings(listeners); } @Test public void testRegisterNotificationListenerForNonExistentMBean() throws Exception { Map<String, NotificationListener> listeners = new HashMap<>(); NotificationListener dummyListener = new NotificationListener() { @Override public void handleNotification(Notification notification, Object handback) { throw new UnsupportedOperationException(); } }; // the MBean with the supplied object name does not exist... listeners.put("spring:type=Test", dummyListener); MBeanExporter exporter = new MBeanExporter(); exporter.setBeans(getBeanMap()); exporter.setServer(server); exporter.setNotificationListenerMappings(listeners); try { start(exporter); fail("Must have thrown an MBeanExportException when registering a " + "NotificationListener on a non-existent MBean."); } catch (MBeanExportException expected) { assertTrue(expected.contains(InstanceNotFoundException.class)); } } @Test public void testWithSuppliedMBeanServer() throws Exception { MBeanExporter exporter = new MBeanExporter(); exporter.setBeans(getBeanMap()); exporter.setServer(server); try { start(exporter); assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME)); } finally { exporter.destroy(); } } @Test public void testUserCreatedMBeanRegWithDynamicMBean() throws Exception { Map<String, Object> map = new HashMap<>(); map.put("spring:name=dynBean", new TestDynamicMBean()); InvokeDetectAssembler asm = new InvokeDetectAssembler(); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(server); exporter.setBeans(map); exporter.setAssembler(asm); try { start(exporter); Object name = server.getAttribute(ObjectNameManager.getInstance("spring:name=dynBean"), "Name"); assertEquals("The name attribute is incorrect", "Rob Harrop", name); assertFalse("Assembler should not have been invoked", asm.invoked); } finally { exporter.destroy(); } } @Test public void testAutodetectMBeans() throws Exception { ConfigurableApplicationContext ctx = load("autodetectMBeans.xml"); try { ctx.getBean("exporter"); MBeanServer server = ctx.getBean("server", MBeanServer.class); ObjectInstance instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=true")); assertNotNull(instance); instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean2=true")); assertNotNull(instance); instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean3=true")); assertNotNull(instance); } finally { ctx.close(); } } @Test public void testAutodetectWithExclude() throws Exception { ConfigurableApplicationContext ctx = load("autodetectMBeans.xml"); try { ctx.getBean("exporter"); MBeanServer server = ctx.getBean("server", MBeanServer.class); ObjectInstance instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=true")); assertNotNull(instance); thrown.expect(InstanceNotFoundException.class); server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=false")); } finally { ctx.close(); } } @Test public void testAutodetectLazyMBeans() throws Exception { ConfigurableApplicationContext ctx = load("autodetectLazyMBeans.xml"); try { ctx.getBean("exporter"); MBeanServer server = ctx.getBean("server", MBeanServer.class); ObjectName oname = ObjectNameManager.getInstance("spring:mbean=true"); assertNotNull(server.getObjectInstance(oname)); String name = (String) server.getAttribute(oname, "Name"); assertEquals("Invalid name returned", "Rob Harrop", name); oname = ObjectNameManager.getInstance("spring:mbean=another"); assertNotNull(server.getObjectInstance(oname)); name = (String) server.getAttribute(oname, "Name"); assertEquals("Invalid name returned", "Juergen Hoeller", name); } finally { ctx.close(); } } @Test public void testAutodetectNoMBeans() throws Exception { ConfigurableApplicationContext ctx = load("autodetectNoMBeans.xml"); try { ctx.getBean("exporter"); } finally { ctx.close(); } } @Test public void testWithMBeanExporterListeners() throws Exception { MockMBeanExporterListener listener1 = new MockMBeanExporterListener(); MockMBeanExporterListener listener2 = new MockMBeanExporterListener(); MBeanExporter exporter = new MBeanExporter(); exporter.setBeans(getBeanMap()); exporter.setServer(server); exporter.setListeners(listener1, listener2); start(exporter); exporter.destroy(); assertListener(listener1); assertListener(listener2); } @Test public void testExportJdkProxy() throws Exception { JmxTestBean bean = new JmxTestBean(); bean.setName("Rob Harrop"); ProxyFactory factory = new ProxyFactory(); factory.setTarget(bean); factory.addAdvice(new NopInterceptor()); factory.setInterfaces(IJmxTestBean.class); IJmxTestBean proxy = (IJmxTestBean) factory.getProxy(); String name = "bean:mmm=whatever"; Map<String, Object> beans = new HashMap<>(); beans.put(name, proxy); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(server); exporter.setBeans(beans); exporter.registerBeans(); ObjectName oname = ObjectName.getInstance(name); Object nameValue = server.getAttribute(oname, "Name"); assertEquals("Rob Harrop", nameValue); } @Test public void testSelfNaming() throws Exception { ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME); SelfNamingTestBean testBean = new SelfNamingTestBean(); testBean.setObjectName(objectName); Map<String, Object> beans = new HashMap<>(); beans.put("foo", testBean); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(server); exporter.setBeans(beans); start(exporter); ObjectInstance instance = server.getObjectInstance(objectName); assertNotNull(instance); } @Test public void testRegisterIgnoreExisting() throws Exception { ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME); Person preRegistered = new Person(); preRegistered.setName("Rob Harrop"); server.registerMBean(preRegistered, objectName); Person springRegistered = new Person(); springRegistered.setName("Sally Greenwood"); String objectName2 = "spring:test=equalBean"; Map<String, Object> beans = new HashMap<>(); beans.put(objectName.toString(), springRegistered); beans.put(objectName2, springRegistered); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(server); exporter.setBeans(beans); exporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING); start(exporter); ObjectInstance instance = server.getObjectInstance(objectName); assertNotNull(instance); ObjectInstance instance2 = server.getObjectInstance(new ObjectName(objectName2)); assertNotNull(instance2); // should still be the first bean with name Rob Harrop assertEquals("Rob Harrop", server.getAttribute(objectName, "Name")); } @Test public void testRegisterReplaceExisting() throws Exception { ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME); Person preRegistered = new Person(); preRegistered.setName("Rob Harrop"); server.registerMBean(preRegistered, objectName); Person springRegistered = new Person(); springRegistered.setName("Sally Greenwood"); Map<String, Object> beans = new HashMap<>(); beans.put(objectName.toString(), springRegistered); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(server); exporter.setBeans(beans); exporter.setRegistrationPolicy(RegistrationPolicy.REPLACE_EXISTING); start(exporter); ObjectInstance instance = server.getObjectInstance(objectName); assertNotNull(instance); // should still be the new bean with name Sally Greenwood assertEquals("Sally Greenwood", server.getAttribute(objectName, "Name")); } @Test public void testWithExposeClassLoader() throws Exception { String name = "Rob Harrop"; String otherName = "Juergen Hoeller"; JmxTestBean bean = new JmxTestBean(); bean.setName(name); ObjectName objectName = ObjectNameManager.getInstance("spring:type=Test"); Map<String, Object> beans = new HashMap<>(); beans.put(objectName.toString(), bean); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); exporter.setBeans(beans); exporter.setExposeManagedResourceClassLoader(true); start(exporter); assertIsRegistered("Bean instance not registered", objectName); Object result = server.invoke(objectName, "add", new Object[] {new Integer(2), new Integer(3)}, new String[] { int.class.getName(), int.class.getName()}); assertEquals("Incorrect result return from add", result, new Integer(5)); assertEquals("Incorrect attribute value", name, server.getAttribute(objectName, "Name")); server.setAttribute(objectName, new Attribute("Name", otherName)); assertEquals("Incorrect updated name.", otherName, bean.getName()); } @Test public void testBonaFideMBeanIsNotExportedWhenAutodetectIsTotallyTurnedOff() throws Exception { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition("^&_invalidObjectName_(*", builder.getBeanDefinition()); String exportedBeanName = "export.me.please"; factory.registerSingleton(exportedBeanName, new TestBean()); MBeanExporter exporter = new MBeanExporter(); Map<String, Object> beansToExport = new HashMap<>(); beansToExport.put(OBJECT_NAME, exportedBeanName); exporter.setBeans(beansToExport); exporter.setServer(getServer()); exporter.setBeanFactory(factory); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_NONE); // MBean has a bad ObjectName, so if said MBean is autodetected, an exception will be thrown... start(exporter); } @Test public void testOnlyBonaFideMBeanIsExportedWhenAutodetectIsMBeanOnly() throws Exception { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); String exportedBeanName = "spring:type=TestBean"; factory.registerSingleton(exportedBeanName, new TestBean()); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName)); exporter.setBeanFactory(factory); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_MBEAN); start(exporter); assertIsRegistered("Bona fide MBean not autodetected in AUTODETECT_MBEAN mode", ObjectNameManager.getInstance(OBJECT_NAME)); assertIsNotRegistered("Bean autodetected and (only) AUTODETECT_MBEAN mode is on", ObjectNameManager.getInstance(exportedBeanName)); } @Test public void testBonaFideMBeanAndRegularBeanExporterWithAutodetectAll() throws Exception { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); String exportedBeanName = "spring:type=TestBean"; factory.registerSingleton(exportedBeanName, new TestBean()); String notToBeExportedBeanName = "spring:type=NotToBeExported"; factory.registerSingleton(notToBeExportedBeanName, new TestBean()); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName)); exporter.setBeanFactory(factory); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL); start(exporter); assertIsRegistered("Bona fide MBean not autodetected in (AUTODETECT_ALL) mode", ObjectNameManager.getInstance(OBJECT_NAME)); assertIsRegistered("Bean not autodetected in (AUTODETECT_ALL) mode", ObjectNameManager.getInstance(exportedBeanName)); assertIsNotRegistered("Bean autodetected and did not satisfy the autodetect info assembler", ObjectNameManager.getInstance(notToBeExportedBeanName)); } @Test public void testBonaFideMBeanIsNotExportedWithAutodetectAssembler() throws Exception { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); String exportedBeanName = "spring:type=TestBean"; factory.registerSingleton(exportedBeanName, new TestBean()); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName)); exporter.setBeanFactory(factory); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER); start(exporter); assertIsNotRegistered("Bona fide MBean was autodetected in AUTODETECT_ASSEMBLER mode - must not have been", ObjectNameManager.getInstance(OBJECT_NAME)); assertIsRegistered("Bean not autodetected in AUTODETECT_ASSEMBLER mode", ObjectNameManager.getInstance(exportedBeanName)); } /** * Want to ensure that said MBean is not exported twice. */ @Test public void testBonaFideMBeanExplicitlyExportedAndAutodetectionIsOn() throws Exception { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(OBJECT_NAME, builder.getBeanDefinition()); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); Map<String, Object> beansToExport = new HashMap<>(); beansToExport.put(OBJECT_NAME, OBJECT_NAME); exporter.setBeans(beansToExport); exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(OBJECT_NAME)); exporter.setBeanFactory(factory); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER); start(exporter); assertIsRegistered("Explicitly exported bona fide MBean obviously not exported.", ObjectNameManager.getInstance(OBJECT_NAME)); } @Test public void testSetAutodetectModeToOutOfRangeNegativeValue() { MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setAutodetectMode(-1); } @Test public void testSetAutodetectModeToOutOfRangePositiveValue() { MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setAutodetectMode(5); } @Test public void testSetAutodetectModeNameToNull() { MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setAutodetectModeName(null); } @Test public void testSetAutodetectModeNameToAnEmptyString() { MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setAutodetectModeName(""); } @Test public void testSetAutodetectModeNameToAWhitespacedString() { MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setAutodetectModeName(" \t"); } @Test public void testSetAutodetectModeNameToARubbishValue() { MBeanExporter exporter = new MBeanExporter(); thrown.expect(IllegalArgumentException.class); exporter.setAutodetectModeName("That Hansel is... *sssooo* hot right now!"); } @Test public void testNotRunningInBeanFactoryAndPassedBeanNameToExport() throws Exception { MBeanExporter exporter = new MBeanExporter(); Map<String, Object> beans = new HashMap<>(); beans.put(OBJECT_NAME, "beanName"); exporter.setBeans(beans); thrown.expect(MBeanExportException.class); start(exporter); } @Test public void testNotRunningInBeanFactoryAndAutodetectionIsOn() throws Exception { MBeanExporter exporter = new MBeanExporter(); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL); thrown.expect(MBeanExportException.class); start(exporter); } @Test // SPR-2158 public void testMBeanIsNotUnregisteredSpuriouslyIfSomeExternalProcessHasUnregisteredMBean() throws Exception { MBeanExporter exporter = new MBeanExporter(); exporter.setBeans(getBeanMap()); exporter.setServer(this.server); MockMBeanExporterListener listener = new MockMBeanExporterListener(); exporter.setListeners(listener); start(exporter); assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME)); this.server.unregisterMBean(new ObjectName(OBJECT_NAME)); exporter.destroy(); assertEquals("Listener should not have been invoked (MBean previously unregistered by external agent)", 0, listener.getUnregistered().size()); } @Test // SPR-3302 public void testBeanNameCanBeUsedInNotificationListenersMap() throws Exception { String beanName = "charlesDexterWard"; BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(beanName, testBean.getBeanDefinition()); factory.preInstantiateSingletons(); Object testBeanInstance = factory.getBean(beanName); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); Map<String, Object> beansToExport = new HashMap<>(); beansToExport.put("test:what=ever", testBeanInstance); exporter.setBeans(beansToExport); exporter.setBeanFactory(factory); StubNotificationListener listener = new StubNotificationListener(); exporter.setNotificationListenerMappings(Collections.singletonMap(beanName, listener)); start(exporter); } @Test public void testWildcardCanBeUsedInNotificationListenersMap() throws Exception { String beanName = "charlesDexterWard"; BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(beanName, testBean.getBeanDefinition()); factory.preInstantiateSingletons(); Object testBeanInstance = factory.getBean(beanName); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); Map<String, Object> beansToExport = new HashMap<>(); beansToExport.put("test:what=ever", testBeanInstance); exporter.setBeans(beansToExport); exporter.setBeanFactory(factory); StubNotificationListener listener = new StubNotificationListener(); exporter.setNotificationListenerMappings(Collections.singletonMap("*", listener)); start(exporter); } @Test // SPR-3625 public void testMBeanIsUnregisteredForRuntimeExceptionDuringInitialization() throws Exception { BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.rootBeanDefinition(Person.class); BeanDefinitionBuilder builder2 = BeanDefinitionBuilder .rootBeanDefinition(RuntimeExceptionThrowingConstructorBean.class); String objectName1 = "spring:test=bean1"; String objectName2 = "spring:test=bean2"; DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(objectName1, builder1.getBeanDefinition()); factory.registerBeanDefinition(objectName2, builder2.getBeanDefinition()); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); Map<String, Object> beansToExport = new HashMap<>(); beansToExport.put(objectName1, objectName1); beansToExport.put(objectName2, objectName2); exporter.setBeans(beansToExport); exporter.setBeanFactory(factory); try { start(exporter); fail("Must have failed during creation of RuntimeExceptionThrowingConstructorBean"); } catch (RuntimeException expected) { } assertIsNotRegistered("Must have unregistered all previously registered MBeans due to RuntimeException", ObjectNameManager.getInstance(objectName1)); assertIsNotRegistered("Must have never registered this MBean due to RuntimeException", ObjectNameManager.getInstance(objectName2)); } @Test public void testIgnoreBeanName() throws MalformedObjectNameException { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); String firstBeanName = "spring:type=TestBean"; factory.registerSingleton(firstBeanName, new TestBean("test")); String secondBeanName = "spring:type=TestBean2"; factory.registerSingleton(secondBeanName, new TestBean("test2")); MBeanExporter exporter = new MBeanExporter(); exporter.setServer(getServer()); exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(firstBeanName, secondBeanName)); exporter.setBeanFactory(factory); exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL); exporter.addExcludedBean(secondBeanName); start(exporter); assertIsRegistered("Bean not autodetected in (AUTODETECT_ALL) mode", ObjectNameManager.getInstance(firstBeanName)); assertIsNotRegistered("Bean should have been excluded", ObjectNameManager.getInstance(secondBeanName)); } @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); start(exporter); 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); start(exporter); assertIsNotRegistered("Null FactoryBean object not registered", ObjectNameManager.getInstance("spring:type=FactoryBean")); } private ConfigurableApplicationContext load(String context) { return new ClassPathXmlApplicationContext(context, getClass()); } private Map<String, Object> getBeanMap() { Map<String, Object> map = new HashMap<>(); map.put(OBJECT_NAME, new JmxTestBean()); return map; } private void assertListener(MockMBeanExporterListener listener) throws MalformedObjectNameException { ObjectName desired = ObjectNameManager.getInstance(OBJECT_NAME); assertEquals("Incorrect number of registrations", 1, listener.getRegistered().size()); assertEquals("Incorrect number of unregistrations", 1, listener.getUnregistered().size()); assertEquals("Incorrect ObjectName in register", desired, listener.getRegistered().get(0)); assertEquals("Incorrect ObjectName in unregister", desired, listener.getUnregistered().get(0)); } private static class InvokeDetectAssembler implements MBeanInfoAssembler { private boolean invoked = false; @Override public ModelMBeanInfo getMBeanInfo(Object managedResource, String beanKey) throws JMException { invoked = true; return null; } } private static class MockMBeanExporterListener implements MBeanExporterListener { private List<ObjectName> registered = new ArrayList<>(); private List<ObjectName> unregistered = new ArrayList<>(); @Override public void mbeanRegistered(ObjectName objectName) { registered.add(objectName); } @Override public void mbeanUnregistered(ObjectName objectName) { unregistered.add(objectName); } public List<ObjectName> getRegistered() { return registered; } public List<ObjectName> getUnregistered() { return unregistered; } } private static class SelfNamingTestBean implements SelfNaming { private ObjectName objectName; public void setObjectName(ObjectName objectName) { this.objectName = objectName; } @Override public ObjectName getObjectName() throws MalformedObjectNameException { return this.objectName; } } public static interface PersonMBean { String getName(); } public static class Person implements PersonMBean { private String name; @Override public String getName() { return name; } public void setName(String name) { this.name = name; } } public static final class StubNotificationListener implements NotificationListener { private List<Notification> notifications = new ArrayList<>(); @Override public void handleNotification(Notification notification, Object handback) { this.notifications.add(notification); } public List<Notification> getNotifications() { return this.notifications; } } private static class RuntimeExceptionThrowingConstructorBean { @SuppressWarnings("unused") public RuntimeExceptionThrowingConstructorBean() { throw new RuntimeException(); } } private static final class NamedBeanAutodetectCapableMBeanInfoAssemblerStub extends SimpleReflectiveMBeanInfoAssembler implements AutodetectCapableMBeanInfoAssembler { private Collection<String> namedBeans; public NamedBeanAutodetectCapableMBeanInfoAssemblerStub(String... namedBeans) { this.namedBeans = Arrays.asList(namedBeans); } @Override public boolean includeBean(Class<?> beanClass, String beanName) { return this.namedBeans.contains(beanName); } } public interface SomethingMBean {} public static class Something implements SomethingMBean {} public static class ProperSomethingFactoryBean implements FactoryBean<Something> { @Override public Something getObject() { return new Something(); } @Override public Class<?> getObjectType() { return Something.class; } @Override public boolean isSingleton() { return true; } } public static class NullSomethingFactoryBean implements FactoryBean<Something> { @Override public Something getObject() { return null; } @Override public Class<?> getObjectType() { return Something.class; } @Override public boolean isSingleton() { return true; } } }