【问题标题】:Abstract types in MXBean operation signaturesMXBean 操作签名中的抽象类型
【发布时间】:2014-12-08 10:42:02
【问题描述】:

我正在尝试创建一个 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)

似乎我可以用普通的MBeans 和Serializable 做一些事情,但不能用MXBeans 和CompositeDataView。还是我错了?

【问题讨论】:

    标签: java jmx mxbean


    【解决方案1】:

    您可以或多或少地做您想做的事,尽管不是那么简单。关键是 MXBean 规范要求 CompositeData 至少有一项。你可以通过在你的基类中拥有一个属性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) 方法知道所有子类。

    【讨论】:

    • 谢谢埃蒙!我想借此机会感谢您在 java.net/blogs/emcmanus 上在 JMX 上发表的博客文章——它们真的很棒,我在日常工作中使用它们。
    猜你喜欢
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    相关资源
    最近更新 更多