javajmxmbeans

Java MXBean custom types


I am trying to create an MXBean with a custom attribute, but I get javax.management.NotCompliantMBeanException IJmsDestinationMBean.getAttributes has parameter or return type that cannot be translated into an open type

I have read that MXBean attributes have to be OpenType compatible. How would I make my attribute work this way? All the classes below are in the same package.

class JmsDestinationMBean implements IJmsDestinationMBean{

  protected JmsDestinationAttributes attributes = new JmsDestinationAttributes();

  @Override
  public JmsDestinationAttributes getAttributes() {
    return this.attributes;
  }
}

@MXBean
interface IJmsDestinationMBean {
  JmsDestinationAttributes getAttributes()
}

class JmsDestinationAttributes {

  protected String name
  protected int messagesCurrentCount
  protected int consumersCurrentCount

  String getName() {
    this.name;
  }

  int getMessagesCurrentCount() {
    this.messagesCurrentCount;
  }

  int getConsumersCurrentCount() {
    this.consumersCurrentCount;
  }
}

Solution

  • The problem is the interface IJmsDestinationMBean. It returns a type JmsDestinationAttributes which is not an open type. Here's the rules-of-thumb I follow when doing this:

    So (for this example) the "host" MBean needs to be an MXBean in order to support complex types , and the complex type needs to have an interface called <ClassName>MBean. Note that one has the MXBean interface, and the other has the MBean interface.

    Here's my example:

    ...apologies for the loose case standard. It's an on the fly example.

    Here the JMSDestination code, with a main to create and register. I am simply using the user name property to provide the name.:

    public class JmsDestination implements JmsDestinationMXBean {
        protected JmsDestinationAttributes attrs = new JmsDestinationAttributes(System.getProperty("user.name"));
    
        public JmsDestinationAttributes getAttributes() {
            return attrs;
        }
    
        public static void main(String[] args) {
            JmsDestination impl = new JmsDestination();
            try {
                ManagementFactory.getPlatformMBeanServer().registerMBean(impl, new ObjectName("org.jms.impl.test:name=" + impl.attrs.getName()));
                Thread.currentThread().join();
            } catch (Exception ex) {
                ex.printStackTrace(System.err);
            }
        }
    }
    

    The JMSDestinationMXBean code:

    public interface JmsDestinationMXBean {
        public JmsDestinationAttributes getAttributes();
    }
    

    The JmsDestinationAttributes code which uses the same name and random numbers for the values:

    public class JmsDestinationAttributes implements JmsDestinationAttributesMBean {
        protected final String name;
        protected final Random random = new Random(System.currentTimeMillis());
        public JmsDestinationAttributes(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    
        public int getMessagesCurrentCount() {
            return Math.abs(random.nextInt(100));
        }
    
        public int getConsumersCurrentCount() {
            return Math.abs(random.nextInt(10));
        }
    }
    

    .... and the JmsDestinationAttributesMBean:

    public interface JmsDestinationAttributesMBean {
        public String getName();
        public int getMessagesCurrentCount();
        public int getConsumersCurrentCount();
    }
    

    The JConsole view looks like this:

    JConsole view of the MXBean

    The JConsole view of the MXBean's attributes looks like this:

    JConsole view of the MXBean's Attributes

    Make sense ?