1

Javassistを使用して、 package-info「クラス」の注釈を追加および変更しています。

場合によっては、次のエッジ ケースに対処する必要があります。誰かが (誤って)パッケージに@XmlJavaTypeAdapters注釈を指定しましたが、属性 (必須であると定義されています) を提供していません。したがって、次のようになります。package-infovalue

@XmlJavaTypeAdapters // XXX incorrect; value() is required, but javac has no problem
package com.foobar;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;

Javassist では、これは少し奇妙に行われます。

javassist.bytecode.annotation.Annotation予想どおり、注釈を表す にはメンバー値 (戻り値)@XmlJavaTypeAdaptersがありません。getMemberValue("value")null

もちろん、メンバー値を追加することは可能value()であり、それが私が行ったことです:

if (adaptersAnnotation.getMemberValue("value") == null) {
    final ArrayMemberValue amv = new ArrayMemberValue(new AnnotationMemberValue(constantPool), constantPool);
    adaptersAnnotation.addMemberValue("value", amv);
    annotationsAttribute.addAnnotation(adaptersAnnotation);
}

上記のコード スニペットでは、 のvalue()属性@XmlJavaTypeAdaptersが の配列であるため、注釈の配列を保持する新しいメンバー値を作成しました@XmlJavaTypeAdapter。Zen に似たドキュメントの意図を推測するために、配列の型を指定しました。別の型を指定するとMemberValue、これMemberValueが何らかの形で配列の型として機能するようです。私の場合、配列の型を@XmlJavaTypeAdapter注釈である にしたいので、MemberValue適切と思われる唯一の種類は でしたAnnotationMemberValue。だから私はそれらの空のものを作成し、それを配列型として設定しました。

これは、Javassist の「範囲内」にとどまっている限り、問題なく機能します。

しかし、何かがうまくいかなかったようです。Javassist に独自のアノテーションをすべて本物の Java に変換するように依頼した場合、このアノテーションの属性java.lang.annotation.Annotationにアクセスしようとすると、Javassist はデフォルト値がないことを教えてくれます。は?value()@XmlJavaTypeAdapters

言い換えれば、それで問題ありませんが (実際にはありません)、希望していた長さ 0 の配列を指定しました (つまり、既定値は使用しないでください。代わりに、明示的に指定した長さ 0 の配列を使用する必要があります)。 ):

final List<Object> annotations = java.util.Arrays.asList(packageInfoClass.getAnnotations());
for (final Object a : annotations) {
  System.out.println("*** class annotation: " + a); // OK; one of these is @XmlJavaTypeAdapters
  System.out.println("    ...of type: " + a.getClass()); // OK; resolves to XmlJavaTypeAdapters
  System.out.println("    ...assignable to java.lang.annotation.Annotation? " + java.lang.annotation.Annotation.class.isInstance(a)); // OK; returns true

  if (a instanceof XmlJavaTypeAdapters) {
    final XmlJavaTypeAdapters x = (XmlJavaTypeAdapters)a;
    System.out.println("    ...value: " + java.util.Arrays.asList(x.value())); // XXX x.value() throws an exception
  }
}

この場合、なぜ Javassist はデフォルト値を探しているのでしょうか?

私のより大きな問題はもちろん、@XmlJavaTypeAdaptersそれ以上の情報なしで が指定されているこの (残念ながらやや一般的な) ケースを処理することです。注釈valueの配列を保持できるメンバー値を追加する必要があります。@XmlJavaTypeAdapterJavassist でこれを達成する方法がわかりません。いつものように、すべての助けに感謝します。

4

1 に答える 1

2

後世のために、この特定のケースでは( aNullPointerExceptionおよび/または aを避けるためにRuntimeException)、これを行う必要があるようです:

if (adaptersAnnotation.getMemberValue("value") == null) {
    final ArrayMemberValue amv = new ArrayMemberValue(constantPool);
    amv.setValue(new AnnotationMemberValue[0]);
    adaptersAnnotation.addMemberValue("value", amv);
    annotationsAttribute.addAnnotation(adaptersAnnotation);
}

特に、ビルド時に配列タイプを意図的に省略していることに注意してくださいArrayMemberValue(任意の種類の配列を含めると、例外が発生します)。次に、その値を type の空の配列に明示的に設定しますAnnotationMemberValue。ここで他の組み合わせを使用すると、例外が発生します。

さらに、非常に奇妙なことに、そのifブロックの最後の行が重要です。この特定のケースでは、注釈自体が見つかったため、既に に存在していましたがAnnotationsAttribute再度追加する必要があります。そうしないRuntimeExceptionと、デフォルト値がないという苦情が寄せられます。

これが他の Javassist ハッカーに役立つことを願っています。

于 2011-12-31T16:31:48.570 に答える