モジュール java.management
パッケージ javax.management

注釈インタフェースMXBean


@Documented @Retention(RUNTIME) @Target(TYPE) public @interface MXBean

インタフェースに対して、MXBeanインタフェースである、またはMXBeanインタフェースではないというマークを明示的に付けるための注釈です。 デフォルトでは、インタフェースがpublicで、SomethingMXBeanのように名前の末尾がMXBeanの場合、MXBeanインタフェースです。 次に示すインタフェースは、MXBeanインタフェースです。

    public interface WhatsitMXBean {}

    @MXBean
    public interface Whatsit1Interface {}

    @MXBean(true)
    public interface Whatsit2Interface {}
    

次に示すインタフェースは、MXBeanインタフェースではありません。

    interface NonPublicInterfaceNotMXBean{}

    public interface Whatsit3Interface{}

    @MXBean(false)
    public interface MisleadingMXBean {}
    

MXBean仕様

MXBeanの概念を使用すると、javax.management.openmbeanにより定義された、定義済みの型セットだけを参照するMBeanを簡単にコーディングできます。 この方法なら、リモート・クライアントを含むクライアントは、MBeanの型を示すモデル固有のクラスにアクセスしなくても、MBeanを利用できます。

この概念は、Standard MBeanの概念と比べて、理解しやすいものです。 ここでは、管理対象オブジェクトをStandard MBeanおよびMXBeanとして表現する方法について説明します。

Standard MBean

public interface MemoryPoolMBean {
    String getName();
    MemoryUsage getUsage();
    // ...
}
          

MXBean

public interface MemoryPoolMXBean {
    String getName();
    MemoryUsage getUsage();
    // ...
}
          

上記の記述から、定義は非常に類似していることがわかります。 唯一の相違点は、インタフェースの命名規則として、Standard MBeanではSomethingMBeanを使用するのに対して、MXBeanではSomethingMXBeanを使用するという点です。

この管理対象オブジェクトでは、MemoryUsage型のUsageという名前の属性があります。 この種の属性の特徴は、データ項目セットの一貫したスナップショットを提供する点です。 たとえば、メモリー・プール内の現在の使用済みメモリー容量や、現在のメモリー・プールの最大値を含めることができます。 これらが別の項目になっていると、getAttributeを個別に呼び出して項目を取得するため、さまざまな時点の一貫性のない値を取得する可能性があります。 max値よりも大きいused値を取得する可能性もあります。

このため、次のようにMemoryUsageを定義できます。

Standard MBean

public class MemoryUsage implements Serializable {
    // standard JavaBean conventions with getters

    public MemoryUsage(long init, long used,
                       long committed, long max) {...}
    long getInit() {...}
    long getUsed() {...}
    long getCommitted() {...}
    long getMax() {...}
}
        

MXBean

public class MemoryUsage {
    // standard JavaBean conventions with getters
    @ConstructorParameters({"init", "used", "committed", "max"})
    public MemoryUsage(long init, long used,
                       long committed, long max) {...}
    long getInit() {...}
    long getUsed() {...}
    long getCommitted() {...}
    long getMax() {...}
}
        

MXBeanではMemoryUsageSerializableのマークを付ける必要がないことを除けば、どちらの場合も定義は同じです(ただし、Serializableのマークを付けることは可能)。 一方、コンストラクタ・パラメータを対応するgetterにリンクする@ConstructorParameters注釈を追加しました。 この点については、あとで詳しく説明します。

MemoryUsageは、モデル固有クラスです。 Standard MBeanでは、MemoryUsageクラスが不明な場合、MBeanサーバーのクライアントはUsage属性にアクセスできません。 クライアントが、JMX技術に基づくジェネリック・コンソールである場合を考えてみましょう。 この場合、コンソールは、接続先の各アプリケーションのモデル固有クラスを使って設定する必要があります。 Java言語で記述されていないクライアントの場合、問題は一層難しくなります。 この場合、MemoryUsageの内容についてクライアントに知らせる方法がない可能性があります。

このような場合に、MXBeanはStandard MBeanと異なります。 管理インタフェースの定義方法はほとんど同じですが、MXBeanフレームワークでは、モデル固有クラスがJavaプラットフォームの標準クラスに変換されます。 配列および標準javax.management.openmbeanパッケージのCompositeDataクラスとTabularDataクラスを使用することで、標準クラスだけを使用して任意の複雑さのデータ構造を構築できます。

この点は、2つのモデルのクライアントを比較することでより明確になります。

Standard MBean

String name = (String)
    mbeanServer.getAttribute(objectName, "Name");
MemoryUsage usage = (MemoryUsage)
    mbeanServer.getAttribute(objectName, "Usage");
long used = usage.getUsed();
        

MXBean

String name = (String)
    mbeanServer.getAttribute(objectName, "Name");
CompositeData usage = (CompositeData)
    mbeanServer.getAttribute(objectName, "Usage");
long used = (Long) usage.get("used");
        

Stringなどの単純な型の属性の場合、コードは同じです。 ただし、複雑な型の属性の場合、Standard MBeanのコードではクライアントがモデル固有クラスMemoryUsageを認識する必要があるのに対し、MXBeanのコードでは非標準クラスは必要ありません。

ここに示すクライアント・コードでは、MXBeanクライアントの方がいくらか複雑になっています。 ただし、クライアントがモデル(ここでは、MemoryPoolMXBeanインタフェースとMemoryUsageクラス)を実際に認識している場合は、プロキシの構築が可能です。 モデルが事前にわかる場合には、Standard MBeanを使用するかMXBeanを使用するかに関係なく、この方法で管理対象オブジェクトとのやり取りを行うことをお勧めします。

Standard MBean

MemoryPoolMBean proxy =
    JMX.newMBeanProxy(
        mbeanServer,
        objectName,
        MemoryPoolMBean.class);
String name = proxy.getName();
MemoryUsage usage = proxy.getUsage();
long used = usage.getUsed();
          

MXBean

MemoryPoolMXBean proxy =
    JMX.newMXBeanProxy(
        mbeanServer,
        objectName,
        MemoryPoolMXBean.class);
String name = proxy.getName();
MemoryUsage usage = proxy.getUsage();
long used = usage.getUsed();
          

MemoryPoolオブジェクトの実装の動作は、Standard MBeanでもMXBeanでも同様です。

Standard MBean

public class MemoryPool
        implements MemoryPoolMBean {
    public String getName() {...}
    public MemoryUsage getUsage() {...}
    // ...
}
        

MXBean

public class MemoryPool
        implements MemoryPoolMXBean {
    public String getName() {...}
    public MemoryUsage getUsage() {...}
    // ...
}
        

MBean ServerへのMBeanの登録の動作は、どちらの場合も同じです。

Standard MBean

{
    MemoryPoolMBean pool = new MemoryPool();
    mbeanServer.registerMBean(pool, objectName);
}
        

MXBean

{
    MemoryPoolMXBean pool = new MemoryPool();
    mbeanServer.registerMBean(pool, objectName);
}
        

MXBeanの定義

MXBeanは、MBeanの一種です。 MXBeanオブジェクトは、MBeanサーバーに直接登録することも、StandardMBeanの引数として使用し、結果のMBeanをMBeanサーバーに登録することもできます。

MBeanServerインタフェースのregisterMBeancreateMBeanメソッドを使ってオブジェクトをMBeanサーバーに登録すると、MBeanの型を判別するためにオブジェクトのクラスが検査されます。

  • クラスがDynamicMBeanインタフェースを実装する場合、MBeanはDynamic MBeanです。 StandardMBeanクラスはこのインタフェースを実装します。このため、これはStandardMBeanクラスを使って作成されたStandard MBeanまたはMXBeanに適用されます。
  • それ以外で、クラスがStandard MBeanの命名規則に一致する場合、MBeanはStandard MBeanです。
  • 上記のいずれにも当てはまらない場合は、MXBeanの可能性があります。 次のインタフェースがあるかどうか、オブジェクトにより実装されたインタフェースのセットが検査されます。
    • クラス名がSMXBeanのインタフェース(Sは空ではない文字列であり、注釈@MXBean(false)を含まない); および/または
    • @MXBean(true)または単に@MXBeanという注釈を含むインタフェース。
    そのようなインタフェースがちょうど1つだけ存在するか、そのようなインタフェースが1つあってほかのすべてのインタフェースのサブインタフェースである場合、そのオブジェクトはMXBeanです。 問題のインタフェースはMXBeanインタフェースになります。 上記の例では、MXBeanインタフェースはMemoryPoolMXBeanです。
  • これらの条件に当てはまるものがない場合、MBeanは無効であり、登録を試みるとNotCompliantMBeanExceptionが生成されます。

MXBeanインタフェース内でメソッドのパラメータまたは戻り値の型として示されるすべてのJava型が、次のルールに従って変換可能である必要があります。 また、パラメータが次の定義に従って再構築可能である必要があります。

上記のルールに準拠しないMXBeanを構築しようとすると、例外がスローされます。

命名規則

MXBean内のメソッドには、Standard MBean内のメソッドと同じ命名規則が適用されます。

  1. T getN()メソッド(TvoidではないJava型、Nは空でない文字列)は、Nという名前の読取り可能な属性が存在することを示します。 属性のJava型および公開型は、次のマッピング・ルールに従って決定されます。 Objectから継承したfinal Class getClass()メソッドは、getterの検索時には無視されます。
  2. boolean isN()メソッドは、Java型booleanおよび公開型SimpleType.Booleanの読取り可能属性Nが存在することを示します。
  3. void setN(T x)メソッドは、書込み可能属性Nが存在することを示します。 属性のJava型および公開型は、次のマッピング・ルールに従って決定されます。 (パラメータの名前xは関係ありません。)
  4. ほかのすべてのメソッドは、メソッドと同じ名前の演算が存在することを示します。 戻り値および各パラメータのJava型および公開型は、次のマッピング・ルールに従って決定されます。

getNおよびisNのルールにより、getterの概念がまとめて定義されます。 setNのルールにより、setterの概念が定義されます。

同名のgetterが2つ存在するか、同名のsetterが2つ存在するとエラーになります。 同名のgetterとsetterが存在する場合は、両方のT型を同じにします。 この場合、属性は読み取り/書込み属性になります。 getterとsetterのいずれか一方が1つだけ存在する場合、属性はそれぞれ読取り専用または書込み専用になります。

型マッピング・ルール

javax.management.openmbeanパッケージで定義されているように、MXBeanはOpen MBeanの一種です。 これは、属性、演算パラメータ、および演算の戻り値がすべて、公開型 (つまりOpenTypeの4つの標準サブクラス)を使って記述可能でなければならないことを意味します。 MXBeanでは、Java型を公開型にマッピングすることでこれを実現します。

すべてのJava型Jで、MXBeanマッピングの記述に次の情報が使用されます。

  • 対応する公開型であるopentype(J) これは、OpenTypeのサブクラスのインスタンスです。
  • マップされたJava型opendata(J)。これはどのopentype(J)についても、1つのopendata(J)に対しては常に同じです。 これはJavaクラスです。
  • 値をJ型からopendata(J)型に変換する方法。
  • 値をopendata(J)型からJ型に変換する方法(可能な場合)。

たとえば、Java型List<String>について考えてみましょう。

  • 公開型、opentype( List<String>)ArrayType(1, SimpleType.STRING)であり、1次元のString配列を表します。
  • マップされたJava型、opendata( List<String>)String[]です。
  • List<String>は、List.toArray(new String[0])を使ってString[]に変換できます。
  • String[]は、Arrays.asListを使ってList<String>に変換できます。

Jからopentype(J)を派生させるマッピング・ルールが存在しない場合、JをMXBeanインタフェース内のメソッド・パラメータまたは戻り値の型にすることはできません。

opendata(J)Jに再変換する方法がある場合、J再構築可能であると言います。 MXBeanインタフェース内のすべてのメソッド・パラメータは、再構築可能である必要があります。これは、MXBeanフレームワークがメソッドを呼び出す際に、これらのパラメータをopendata(J)からJに変換する必要があるためです。 JMX.newMXBeanProxyにより生成されたプロキシでは、これは、再構築可能でなければならないMXBeanインタフェース内のメソッドの戻り値です。

null値を使用できないプリミティブJava型を除く、すべてのJava型と公開型で、null値が許可されます。 J型をopendata(J)型に変換したり、opendata(J)型をJ型に変換したりする場合は、null値とnull値がマッピングされます。

次の表に、型マッピング・ルールの概要を示します。

型マッピング・ルール
Java型J opentype(J) opendata(J)
intbooleanなど
(8つのプリミティブJava型)
SimpleType.INTEGER
SimpleType.BOOLEANなど
IntegerBooleanなど
(対応するboxed型)
IntegerObjectNameなど
(SimpleTypeの適用範囲内の型)
対応するSimpleType J、同じ型
int[]など
(プリミティブ型の1ディメンション配列)
ArrayType.getPrimitiveArrayType(int[].class)など J、同じ型
E[]
(非プリミティブ要素型Eの配列、int[][]を含む。Eint[])
ArrayType.getArrayType(opentype(E)) opendata(E)[]
List<E>
Set<E>
SortedSet<E> (下記を参照)
E[]に対するものと同じ E[]に対するものと同じ
列挙E
(Java内でenum E {...}として宣言される)
SimpleType.STRING String
Map<K,V>
SortedMap<K,V>
TabularType
(下記を参照)
TabularData
(下記を参照)
レコード・クラス 可能な場合にはCompositeType
(下記を参照)
CompositeData
(下記参照)
MXBeanインタフェース SimpleType.OBJECTNAME
(下記を参照)
ObjectName
(下記を参照)
その他の型 可能な場合にはCompositeType
(下記を参照)
CompositeData
(下記参照)

以降のセクションでは、これらのルールについて詳しく説明します。

プリミティブ型のマッピング

8つのプリミティブJava型(booleanbyteshortint longfloatdoublechar)は、java.langから BooleanByteなどの対応するboxed型にマッピングされます。公開型は、対応するSimpleTypeです。 このため、opentype( long)SimpleType.LONGに、opendata(long) java.lang.Longになります。

long[]などのプリミティブ型の配列は、公開型として直接表現できます。 従って、openType( long[] ) ArrayType.getPrimitiveArrayType(long[].class)であり、opendata( long[] ) long[]です。

JMX API内の演算はプリミティブではなく常にJavaオブジェクト上で実行されるため、実際には、プレーンなint Integerの違いなどが明確になることはありません。 ただし、配列で違いが明らかになります

コレクションのマッピング(List<E>など)

List<String>または Set<ObjectName>のようなList< E >または Set< E >は、String[]または ObjectName[]のような同じ要素型の配列と同じ方法でマッピングされます。

SortedSet<E>E[]と同じ方法でマッピングされます。ただし、これが変換可能なのは、EComparableを実装するクラスまたはインタフェースである場合のみです。 このため、SortedSet<String>SortedSet<Integer>は変換可能ですが、 SortedSet<int[]>SortedSet<List<String>>は変換不可能です。 SortedSetインスタンスの変換は、null以外のcomparator()が存在すると、IllegalArgumentExceptionをスローして失敗します。

List<E>java.util.ArrayList<E>として、Set<E>java.util.HashSet<E>として、SortedSet<E>java.util.TreeSet<E>としてそれぞれ再構築されます。

マップのマッピング(Map<K,V>など)

Map<K,V>または SortedMap<K,V> ( Map<String,ObjectName>など)は、公開型TabularTypeを持ち、TabularDataにマッピングされます。 TabularTypeには、keyおよびvalueという名前の2つの項目が含まれます。 keyの公開型はopentype(K)valueの公開型はopentype(V)です。 TabularTypeのインデックスは、単一の項目keyです。

たとえば、 Map<String,ObjectName>TabularTypeは、次のようなコードを使って構築できます。

String typeName =
    "java.util.Map<java.lang.String, javax.management.ObjectName>";
String[] keyValue =
    new String[] {"key", "value"};
OpenType[] openTypes =
    new OpenType[] {SimpleType.STRING, SimpleType.OBJECTNAME};
CompositeType rowType =
    new CompositeType(typeName, typeName, keyValue, keyValue, openTypes);
TabularType tabularType =
    new TabularType(typeName, typeName, rowType, new String[] {"key"});
    

typeNameは、次に詳述する型名ルールに従って決定されます。

SortedMap<K,V>は同じ方法でマッピングされます。ただし、これが変換可能なのは、KComparableを実装するクラスまたはインタフェースである場合のみです。 このため、SortedMap<String,int[]>は変換可能ですが、SortedMap<int[],String>は変換不可能です。 SortedMapインスタンスの変換は、null以外のcomparator()が存在すると、 IllegalArgumentExceptionをスローして失敗します。

Map<K,V>java.util.HashMap<K,V>として、SortedMap<K,V>java.util.TreeMap<K,V>としてそれぞれ再構築されます。

TabularDataはインタフェースです。 Map<K,V>を公開データとして表現するのに使用される具象クラスはTabularDataSupport、またはTabularDataSupportとして直列化する TabularDataを実装する別のクラスです。

レコードのマッピング

「レコード」クラスJは、componentsがすべてオープン・タイプに変換可能な場合にのみCompositeTypeに変換できます。 それ以外の場合は、変換できません。 コンポーネントを持たないレコードは変換できません。

レコード・クラスのCompositeTypeへのマッピング

すべてのコンポーネントがオープン・タイプに変換可能なレコードは、それ自体がCompositeTypeに変換できます。 レコード・クラスは、次のようにCompositeTypeに変換されます。

  • CompositeTypeのタイプ名はレコード・クラスの名前です。
  • レコードgetterは、「レコード・コンポーネント」のアクセサです。
  • タイプがTのレコード・コンポーネントごとに、CompositeTypeのアイテムはレコード・コンポーネントと同じ名前になり、そのタイプは前述の「タイプ・マッピング・ルール」で定義されているopentype(T)になります。

レコード・クラスのインスタンスのCompositeDataへのマッピング

CompositeTypeに対応するレコード・クラスのインスタンスからCompositeDataへのマッピングは、「その他のタイプ」に指定されているものと同じです。

CompositeDataからのレコード・クラスのインスタンスの再構築

レコードは、その標準コンストラクタを使用して再構築されます。 標準コンストラクタでは、@javax.management.ConstructorParametersまたは@java.beans.ConstructorProperties注釈が存在する必要はありません。 これらの注釈が標準コンストラクタに存在する場合は、無視されます。

レコード・クラスJのインスタンスをCompositeDataから再構築する方法の詳細は、次のCompositeDataからのJavaタイプまたはレコード・クラスJのインスタンスの再構築」を参照してください。

MXBeanインタフェースのマッピング

MXBeanインタフェース、またはMXBeanインタフェース内部で参照される型は、別のMXBeanインタフェースJを参照できます。 この場合、opentype(J)SimpleType.OBJECTNAMEopendata(J)ObjectNameです。

たとえば、次のような2つのMXBeanインタフェースが存在する場合を考えましょう。

public interface ProductMXBean {
    public ModuleMXBean[] getModules();
}

public interface ModuleMXBean {
    public ProductMXBean getProduct();
}
    

ModuleMXBeanインタフェースを実装するオブジェクトは、そのgetProductメソッドから、ProductMXBeanインタフェースを実装するオブジェクトを返します。 ModuleMXBeanオブジェクトと返される ProductMXBeanオブジェクトの両方を、同じMBeanサーバーのMXBeanとして登録する必要があります。

ModuleMXBean.getProduct()メソッドは、Productという名前の属性を定義します。 この属性の公開型はSimpleType.OBJECTNAMEです。対応するObjectName値は、参照されるProductMXBeanがMBeanサーバー内で登録される名前になります。

ModuleMXBean用のMXBeanプロキシを作成して、そのgetProduct()メソッドを呼び出す場合、別のMXBeanプロキシを作成することにより、プロキシがObjectNameProductMXBeanに再度マッピングします。 より正式には、JMX.newMXBeanProxy(mbeanServerConnection, objectNameX, interfaceX)で作成されたプロキシがobjectNameYを別のMXBeanインタフェースである interfaceYにマップする必要がある場合は、 JMX.newMXBeanProxy(mbeanServerConnection, objectNameY, interfaceY)を使用します。 この実装では、同じパラメータを使ってJMX.newMXBeanProxyを呼び出すことで、以前に作成されたプロキシが返されることがあります。また、新規プロキシが作成されることもあります。

ModuleMXBeanインタフェースを次のように変更することで、逆マッピングを実行できます。

public interface ModuleMXBean {
    public ProductMXBean getProduct();
    public void setProduct(ProductMXBean c);
}
    

setProductメソッドの存在は、Product属性が読み取り/書込みであることを示します。 以前と同様に、この属性の値はObjectNameになります。 この属性を設定する場合は、ObjectNamesetProductメソッドで必要なProductMXBeanオブジェクトに変換します。 このオブジェクトは、同じMBeanサーバー内の指定されたObjectNameのMXBeanプロキシになります。

ModuleMXBean用のMXBeanプロキシを作成してそのsetProductメソッドを呼び出す場合、プロキシはそのProductMXBean引数をObjectNameに再度マッピングします。 これが機能するのは、引数が実際に、同じ MBeanServerConnection内のProductMXBeanに対応する別のプロキシである場合のみです。 プロキシは、別のプロキシから返されることがあります(たとえば、ModuleMXBean.getProduct()ProductMXBean用のプロキシを返す)。また、JMX.newMXBeanProxyにより作成されることも、MBeanServerInvocationHandlerまたはサブクラスである呼出しハンドラを持つProxyを使って作成されることもあります。

2つの異なるObjectNameに同じMXBeanが登録されていると、別のMXBeanからそのMXBeanへの参照があいまいになります。 このため、MBeanサーバーに登録済のMXBeanオブジェクトを、別の名前で同じMBeanサーバーに登録しようとすると、InstanceAlreadyExistsExceptionがスローされます。 一般に、1つのMBeanオブジェクトを複数の名前で登録することは避けてください。特に、NotificationBroadcasterであるMBeanでは、正しく動作しません。

その他の型のマッピング

JavaクラスやインタフェースJが上記の表に示したそのほかのルールに当てはまらない場合、次に示すように、MXBeanフレームワークによりCompositeTypeへのマッピングが試みられます。 このCompositeTypeの型名は、次の型名ルールに従って決定されます。

JavaタイプJCompositeTypeへのマッピング

getterのクラスは、上記の規則を使って検査されます。 (getterはpublicインスタンス・メソッドでなければならない。) getterが存在しないか、getterの型が変換不可能な場合、Jは変換不可能です。

1つ以上のgetterが存在し、どのgetterにも変換可能な型が存在する場合、opentype(J)は各getter用の項目を1つ保持する CompositeTypeです。 次のgetterの場合、

T getName()
CompositeType内の項目はnameと呼ばれ、opentype(T)型を持ちます。 たとえば、次の項目の場合、
String getOwner()
項目はownerと呼ばれ、公開型 SimpleType.STRINGを持ちます。 次のgetterの場合、
boolean isName()
CompositeType内の項目はnameと呼ばれ、SimpleType.BOOLEAN型を持ちます。

最初の文字(コード・ポイント)が、小文字に変換されることに留意してください。 これはJava Beansの規則に従っています。歴史的な理由から、これはStandard MBeanの規則とは異なります。 標準のMBeanまたはMXBeanインタフェースでは、メソッドgetOwnerOwnerという属性を定義し、Java BeanまたはマップされたCompositeTypeではメソッド getOwnerownerというプロパティまたはアイテムを定義します。

2つのメソッドが同じアイテム名(たとえば、 getOwnerおよびisOwner、またはgetOwnerおよび getowner)を生成する場合、その型は変換可能ではありません。

Javaタイプまたはレコード・クラスJのインスタンスからCompositeDataへのマッピング

公開型がCompositeTypeの場合、対応するマップされたJava型(opendata(J))はCompositeDataになります。 Jのインスタンスから、上記のCompositeTypeに対応するCompositeDataへのマッピングは、次のように実行されます。 最初に、JCompositeDataViewインタフェースを実装する場合、そのインタフェースのtoCompositeDataメソッドが呼び出されて、変換が実行されます。 それ以外の場合は、項目ごとにgetterを呼び出して対応する公開データ型に変換することにより、CompositeDataが構築されます。 これにより、次のようなgetterが、

List<String> getNames() (または、レコードの場合はList<String> names())

名前「names」および公開型ArrayType(1, SimpleType.STRING)の項目にマッピングされます。 CompositeDataへの変換によりgetNames()が呼び出され、生成されたList<String>が項目「names」のString[]に変換されます。

CompositeDataはインタフェースです。 型をオープン・データとして表現するために使用される具象クラスは、CompositeDataSupport、または CompositeDataSupportとして直列化される CompositeDataを実装する別のクラスです。

CompositeDataからのJavaタイプまたはレコード・クラスJのインスタンスの再構築

opendata(J)がJava型JCompositeDataである場合、JのインスタンスをCompositeDataから再構築可能であるか、Jは再構築不可能であるかのどちらかになります。 CompositeData内のいずれかの項目が再構築不可能である場合、Jも再構築不可能です。

指定した任意のJに関して、CompositeDataからJのインスタンスを再構築する方法を決定する際、次のルールが適用されます。 リスト内で適用可能な最初のルールが使用されます。

  1. J
    public static J from(CompositeData cd)
    メソッドを持つ場合、そのメソッドを呼び出すことでJのインスタンスが再構築されます。

  2. それ以外の場合、JRecordクラスで、レコード標準コンストラクタが適用可能な場合、Jのインスタンスはレコードの標準コンストラクタを呼び出して再構築されます。 標準コンストラクタ(該当する場合)は、CompositeDataから適切な再構築アイテムを使用してコールされます。 レコード・コンポーネントで指定されたすべてのプロパティがCompositeDataに存在する場合は、標準コンストラクタはapplicableです。

  3. それ以外の場合、J@javax.management.ConstructorParametersまたは@java.beans.ConstructoProperties注釈を持つ少なくとも1つのパブリック・コンストラクタがある場合、Jのインスタンスを再構築するために、これらのコンストラクタの1つ(必ずしも常に同じではない)が呼び出されます。 コンストラクタに@javax.management.ConstructorParameters@java.beans.ConstructorPropertiesの両方が付いている場合、@javax.management.ConstructorParametersが使用され、@java.beans.ConstructorPropertiesは無視されます。 これらのすべての注釈は、コンストラクタが持つパラメータと同じだけの文字列をリストに含める必要があります。各文字列はJのgetterに対応するプロパティの名前にします。このgetterの型は、対応するコンストラクタ・パラメータと同じにする必要があります。 @ConstructorParametersまたは@ConstructorProperties注釈(これらは、オブジェクトを再構成するために必要とされない情報)に記載されていないゲッターが存在することは誤りではありません。

    Jのインスタンスは、CompositeDataから再構築された適切な項目を使ってコンストラクタを呼び出すことで再構築されます。 呼び出されるコンストラクタは、この CompositeDataがすべてのアイテムが存在しない以前のバージョンのJから来る可能性があるので、実際にCompositeDataに存在するアイテムに基づいて実行時に決定されます。 @ConstructorParametersまたは@ConstructorProperties注釈に指定されたすべてのプロパティがCompositeDataのアイテムとして存在する場合、コンストラクタはapplicableです。 適用可能なコンストラクタが存在しない場合は、Jを再構築する試みは失敗します。

    プロパティを任意に組み合せる場合は、次のいずれかが当てはまります。(a)適用可能なコンストラクタが存在しない、(b)適用可能なコンストラクタが1つだけ存在する、(c)適用可能なコンストラクタの1つが、他の適用可能な各コンストラクタが指定したプロパティの適切なスーパー・セットを指定する。 (つまり、選択するコンストラクタに関してあいまいさは存在しないことになります。) この条件がtrueでない場合、Jは再構築可能ではありません。

  4. それ以外で、Jが引数のないpublicコンストラクタを持ち、型がTで名前がNJ内の各getterに対して同じ名前と型の対応するsetterが存在する場合は、Jのインスタンスが引数のないコンストラクタを使って構築され、setterがCompositeDataから再構築された項目を使って呼び出されて値が復元されます。 たとえば、
    public List<String> getNames()
    メソッドが存在する場合、このルールが適用される
    public void setNames(List<String> names)
    メソッドも存在する必要があります。

    CompositeDataJの以前のバージョンに基づく場合、一部の項目が存在しない可能性があります。 この場合、対応するsetterは呼び出されません。

  5. それ以外で、Jがgetter以外のメソッドを持たないインタフェースである場合、Jのインスタンスは、Proxyを使って構築されます。その際、変換対象の CompositeDataを利用するCompositeDataInvocationHandlerが使用されます。

  6. それ以外の場合、Jは再構築不可能です。

java.beans.ConstructorPropertiesが(例えば、java.desktopモジュールが読み込み不可能な場合や、ランタイム・イメージにjava.desktopモジュールが含まれていない場合)でない場合、ルール2は適用されません。 java.beansパッケージが含まれないランタイムを対象とするときに、コンパイル時と実行時の環境に不一致があることにより、JがpublicコンストラクタおよびConstructorProperties注釈を使用してコンパイルされる場合、別のルールが適用されないかぎり、Jは再構築不可能になります。

次の例では、intおよび Stringで構成される NamedNumber型をコーディングするいくつかの方法を示します。 いずれの場合でも、CompositeTypeは次のようになります。

CompositeType(
    "NamedNumber",                      // typeName
    "NamedNumber",                      // description
    new String[] {"number", "name"},    // itemNames
    new String[] {"number", "name"},    // itemDescriptions
    new OpenType[] {SimpleType.INTEGER,
                    SimpleType.STRING}  // itemTypes
);
      
  1. static fromメソッド:
    public class NamedNumber {
        public int getNumber() {return number;}
        public String getName() {return name;}
        private NamedNumber(int number, String name) {
            this.number = number;
            this.name = name;
        }
        public static NamedNumber from(CompositeData cd) {
            return new NamedNumber((Integer) cd.get("number"),
                                   (String) cd.get("name"));
        }
        private final int number;
        private final String name;
    }
              
  2. レコード:
     public record NamedNumber(int number, String name) {}
              
  3. @ConstructorParameters注釈付きのパブリック・コンストラクタ:
    public class NamedNumber {
        public int getNumber() {return number;}
        public String getName() {return name;}
        @ConstructorParameters({"number", "name"})
        public NamedNumber(int number, String name) {
            this.number = number;
            this.name = name;
        }
        private final int number;
        private final String name;
    }
              
  4. 各getter用のsetter:
    public class NamedNumber {
        public int getNumber() {return number;}
        public void setNumber(int number) {this.number = number;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
        public NamedNumber() {}
        private int number;
        private String name;
    }
              
  5. getterのみを持つインタフェース:
    public interface NamedNumber {
        public int getNumber();
        public String getName();
    }
              

データのコレクションを表現するだけのクラスは、通常、不変にしておくことをお薦めします。 不変クラスのインスタンスは、構築後に変更することはできません。 CompositeData自体は不変であることに留意してください。 不変であることには多数の利点があります。特にスレッドの安全性やセキュリティ面で大きなメリットがあります。 このため、setterの使用は、可能な場合は避けるようにしてください。

再帰型

再帰(自己参照)型をMXBeanインタフェース内で使用することはできません。 これは、CompositeTypeの不変性によるものです。 たとえば、次の型は自身を参照するため、属性の型になることはできません。

public interface Node {
    public String getName();
    public int getPriority();
    public Node getNext();
}

このような再帰型を書き換えて、再帰型でなくすることはいつでも可能です。 それには、新しい型を導入することが必要な場合があります。 たとえば、

public interface NodeList {
    public List<Node> getNodes();
}

public interface Node {
    public String getName();
    public int getPriority();
}

MXBeanに対応したMBeanInfoの内容

MXBeanは、Open MBeanの一種です。 ただし、互換性を保つために、MBeanInfoOpenMBeanInfoではありません。 特に、属性、パラメータ、オペレーションの戻り値の型がintなどのプリミティブ型またはvoid (戻り値の型)である場合、属性、パラメータ、オペレーションはそれぞれMBeanAttributeInfoMBeanParameterInfoMBeanOperationInfoで表されます。これらのgetType()または getReturnType()はプリミティブ名(「int」など)を返します。 前述のマッピング・ルールで、opendataマッピングがラップされる型(Integerなど)と指定される場合でも、これは当てはまります。

MXBeanのMBeanInfo.getConstructors()が返すpublicコンストラクタの配列(MBeanサーバーに直接登録される)には、そのMXBeanのpublicコンストラクタがすべて含まれます。 MXBeanのクラスがpublicではない場合、コンストラクタもpublicでないとみなされます。 StandardMBeanクラスを使って構築されるMXBeanに対して返されるリストは、Standard MBeanと同じ方法で取得されます。 MXBeanの構築方法に関係なく、コンストラクタ・パラメータはMXBeanマッピング・ルールの影響を受けず、対応するOpenTypeを持ちません。

MBeanサーバー内に直接登録されるMXBeanがNotificationBroadcasterインタフェースを実装しない場合、そのMXBeanのMBeanInfo.getNotifications()が返す通知型の配列は空になります。 それ以外の場合、これは、MXBeanの登録時にNotificationBroadcaster.getNotificationInfo()を呼び出した結果になります。 その後、このメソッドの結果が変わっても、MBeanInfo.getNotifications()の結果は変わりません。 StandardMBeanまたはStandardEmitterMBeanクラスを使って構築されるMXBeanに対して返されるリストは、Standard MBeanと同じ方法で取得されます。

MBeanInfoに含まれるすべてのMBeanAttributeInfoMBeanParameterInfo、およびMBeanOperationInfoオブジェクトのDescriptorは、上記のマッピング・ルールで指定されたOpenTypeを値とするフィールドopenTypeを持ちます。 このため、getType()が「int」であっても、getDescriptor().getField("openType")SimpleType.INTEGERになります。

これらの各オブジェクトのDescriptorも、MXBeanインタフェース内に表示されるJava型を表す文字列であるoriginalTypeフィールドを持ちます。 この文字列の書式については、下記の「型名」セクションを参照してください。

MBeanInfoDescriptorは、文字列「true」を値とするmxbeanフィールドを持ちます。

型名

MXBean内のメソッド・パラメータや戻り値のマップされていない型Tを文字列として表現することが必要な場合があります。 Tがジェネリック型でない場合、この文字列はClass.getName()により返される値になります。 それ以外の場合、これはgenericstring(T)の値になります。次にこの定義を示します。

  • Tがジェネリック型でも配列型でもない場合、genericstring(T)Class.getName()により返される値になります("int" "java.lang.String"など)。
  • Tが配列E[]である場合、genericstring(T)genericstring(E)のあとに"[]"を付加したものになります。 たとえば、genericstring(int[])"int[]"genericstring( List<String>[][]) "java.util.List<java.lang.String>[][]"になります。
  • それ以外の場合、Tは、 List<String>などのパラメータ化された型になります。genericstring(T)Class.getName()により返されるパラメータ化された型の完全指定名、左山括弧( "<")、genericstring(A) (Aは最初の型パラメータ)、2番目の型パラメータBが存在する場合は", " (カンマと空白文字1つ)とgenericstring(B)、および右山括弧(">")で構成されます。

メソッドがint[]を返す場合は、これは、 Class.getName()により返される文字列"[I"で表されます。ただし、メソッドがList<int[]>を返す場合、これは文字列 "java.util.List<int[]>"で表されます。

例外

Java型から公開型のマッピングで問題が発生すると、OpenDataExceptionにより通知されます。 これは、getterを持たないjava.util.Randomなどの型を参照する場合など、MXBeanインタフェースの分析中に発生することがあります。 また、インスタンスの変換中(MXBean内のメソッドからの戻り値またはMXBeanプロキシ内のメソッドへのパラメータ)に発生することもあります。たとえば、SortedSetがnull以外の Comparatorを持つ場合に、SortedSet<String>から String[]に変換するときに発生します。

公開型から Java型のマッピングで問題が発生すると、InvalidObjectExceptionにより通知されます。 これは、再構築可能な型が必須のコンテキストで、上記のルールに従うと再構築可能ではない型を参照する場合など、MXBeanインタフェースの分析中に発生することがあります。 また、該当する名前のEnum定数が存在しない状況でStringからEnumへの変換を行う場合のように、インスタンスの変換中(MXBean内のメソッドへのパラメータまたはMXBeanプロキシ内のメソッドからの戻り値)に発生することもあります。

コンテキストに応じて、OpenDataExceptionまたはInvalidObjectExceptionを、RuntimeMBeanExceptionUndeclaredThrowableExceptionなどの別の例外内にラップできます。 スローされる各例外で、条件Cがtrueになります。「e OpenDataExceptionまたはInvalidObjectException (必要に応じて)。あるいはe.getCause()Cはtrue」。

導入されたバージョン:
1.6
  • オプション要素のサマリー

    オプションの要素
    修飾子と型
    オプション要素
    説明
    boolean
    注釈付きインタフェースがMXBeanインタフェースである場合、trueになります。
  • 要素の詳細

    • value

      boolean value
      注釈付きインタフェースがMXBeanインタフェースである場合、trueになります。
      戻り値:
      注釈付きインタフェースがMXBeanインタフェースである場合はtrue
      デフォルト:
      true