MXBean 操作签名中的抽象类型



我正在尝试创建一个MXBean操作,该操作将返回一个没有属性的抽象类型(实际类型及其属性将在运行时确定)。我的数据模型可以简单地放如下:

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();
}

该操作可以返回具有foo属性的A实例,也可以返回具有bar属性的B实例。当然,当我尝试注册MBean实例时,我会看到一个闪亮的NotCompliantMBeanException

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 s 和 Serializable 做一些事情,但不能用 MXBean s 和 CompositeDataView 做。还是我错了?

可以或多或少地做你想做的事情,尽管不是那么简单。关键点是MXBean规范要求复合数据至少有一个项目。您可以通过在基类中type属性来满足此要求,我在这里称之为AnyCompositeDatatype属性还可以用于决定如何将CompositeData转换回特定类型,例如FooBar。在这里的代码中,我将所有内容都塞进了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)方法知道所有的子类。

相关内容

  • 没有找到相关文章

最新更新