我正在尝试创建一个MXBean操作,该操作将返回一个抽象类型w / o属性(实际类型及其属性将在运行时确定)。我的数据模型可以简单地说如下:
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) {/* ... */}
}
...并且MXBean操作签名是:
@MXBean
public interface Baz {
I f();
}
该操作可以返回具有A
属性的foo
实例,或具有B
属性的bar
实例。
当然,我立即向我提出了一个闪亮的NotCompliantMBeanException
我尝试注册MBean
实例:
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)
似乎我可以使用常规MBean
和Serializable
执行某些操作,但不能使用MXBean
和CompositeDataView
。或者我错了吗?
答案 0 :(得分:1)
可以做多或少或多或少的事情,尽管不是那么简单。关键是MXBean规范要求CompositeData至少有一个项目。您可以通过在基类中使用属性type
来满足此要求,我在此处将其称为AnyCompositeData
。 type
属性还可用于决定如何从CompositeData
转换回特定类型,例如Foo
和Bar
。在这里的代码中,我将所有内容都填入了AnyCompositeData
类,但更实际的是它当然是单独的类。我只详细说明了具体的类Foo
,但显然如何扩展模式以支持其他类。
public abstract class AnyCompositeData implements CompositeDataView {
private final String type;
public AnyCompositeData(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static AnyCompositeData from(CompositeData cd) {
switch ((String) cd.get("type")) {
case "Foo":
return new Foo((String) cd.get("foo"));
default:
throw new IllegalArgumentException("Don't know how to reconstruct: " + cd.get("type"));
}
}
public static class Foo extends AnyCompositeData {
private final String foo;
Foo(String foo) {
super("Foo");
this.foo = foo;
}
public String getFoo() {
return foo;
}
@Override
public CompositeData toCompositeData(CompositeType ct) {
try {
String[] items = {"type", "foo"};
OpenType<?>[] itemTypes = {SimpleType.STRING, SimpleType.STRING};
Object[] itemValues = {"Foo", foo};
CompositeType compositeType = new CompositeType("Foo", "Foo", items, items, itemTypes);
return new CompositeDataSupport(compositeType, items, itemValues);
} catch (OpenDataException e) {
throw new RuntimeException(e);
}
}
}
@MXBean
public interface Baz {
AnyCompositeData f();
}
static class BazImpl implements Baz {
@Override
public AnyCompositeData f() {
return new Foo("whatever");
}
}
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName("test:baz=baz");
mbs.registerMBean(new BazImpl(), objectName);
Baz bazProxy = JMX.newMXBeanProxy(mbs, objectName, Baz.class);
AnyCompositeData result = bazProxy.f();
assert result instanceof Foo;
assert ((Foo) result).getFoo().equals("whatever");
}
}
如果您有很多子类,如Foo
,那么您可能需要考虑以某种方式使用反射,而不是让from(CompositeData)
方法了解所有子类。