I'm trying to create an MXBean operation which would return an abstract type w/o properties (the actual type and its attributes are to be determined at run time). My data model can be simply put as follows:
public interface I extends CompositeDataView {
// empty
}
public final class A implements I {
private final String foo;
@ConstructorProperties({"foo"})
public A(final String foo) {/* ... */}
public String getFoo() {/* ... */}
@Override
public CompositeData toCompositeData(CompositeType ct) {/* ... */}
public static A from(final CompositeData cd) {/* ... */}
}
public final class B implements I {
private final String bar;
@ConstructorProperties({"bar"})
public B(final String bar) {/* ... */}
public String getBar() {/* ... */}
@Override
public CompositeData toCompositeData(CompositeType ct) {/* ... */}
public static B from(final CompositeData cd) {/* ... */}
}
... and the MXBean operation signature is:
@MXBean
public interface Baz {
I f();
}
The operation can return either an instance of A
with a foo
attribute, or an instance of B
with a bar
attribute.
Of course I'm presented with a shiny NotCompliantMBeanException
immediately I try to register the MBean
instance:
Caused by: javax.management.openmbean.OpenDataException: Can't map I to an open data type
at com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeCompositeMapping(DefaultMXBeanMappingFactory.java:458)
at com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeMapping(DefaultMXBeanMappingFactory.java:292)
at com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:257)
It seems there's something I can do with regular MBean
s and Serializable
but can't with MXBean
s and CompositeDataView
. Or am I wrong?
It is possible to do more or less what you want, though not all that straightforward. The key point is that the MXBean spec requires a CompositeData to have at least one item. You can satisfy this requirement by having a property
type
in your base class, which I've calledAnyCompositeData
here. Thetype
property can also serve to decide how to translate back fromCompositeData
to the specific types such as yourFoo
andBar
. In the code here I stuffed everything into theAnyCompositeData
class, though more realistically it would be separate classes of course. I only spelled out the concrete classFoo
but it should be obvious how to extend the pattern to support other classes.If you had a lot of subclasses like
Foo
, then you might want to consider using reflection in some way rather than having thefrom(CompositeData)
method know about all the subclasses.