为什么Javassist坚持在明确指定一个默认注释值时寻找它?

时间:2011-12-31 16:20:38

标签: javassist

我正在使用Javassistpackage-info“类”上添加和修改注释。

在某些情况下,我需要处理以下边缘情况。有人(错误地)在@XmlJavaTypeAdapters包上指定了package-info注释,但未提供value属性(defined as being required)。所以它看起来像这样:

@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()的{​​{1}}属性是@XmlJavaTypeAdapters的数组。我已经通过尝试神圣类似Zen文档的意图来指定它的数组类型 - 似乎如果你提供另一个@XmlJavaTypeAdapter,那么MemberValue将以某种方式作为数组的类型。在我的情况下,我希望数组的类型为MemberValue,这是一个注释,因此唯一合适的@XmlJavaTypeAdapter类型是MemberValue。所以我创建了一个空的,并将其设置为数组类型。

只要你留在“Javassist”中,这就可以正常工作。

但是,似乎出现了问题。如果我要求Javassist将其所有专有注释转换为真正的Java AnnotationMemberValue,那么当我尝试访问此java.lang.annotation.Annotation注释的value()属性时,Javassist告诉我没有默认值。咦?

换句话说,那很好 - 确实没有 - 但是我已经指定了我所希望的零长度数组(也就是说,不应该使用默认值;我明确指定的零长度数组应该改为使用):

@XmlJavaTypeAdapters

那么为什么Javassist会在这种情况下寻找默认值?

我的更大问题当然是处理这种情况(不幸的是有些常见),其中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 } } 被指定而没有关于它的进一步信息。我需要添加一个@XmlJavaTypeAdapters成员值,该值可以包含value个注释数组。我似乎无法弄清楚如何使用Javassist实现这一目标。一如往常,所有帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

对于后代,似乎在这种特殊情况下(为了避免使用NullPointerException和/或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时,我故意省略数组类型(包括任何类型之一都会导致异常)。然后我将其值显式设置为类型为AnnotationMemberValue的空数组。此处的任何其他组合都将导致异常。

此外,非常奇怪的是,if块中的最后一行非常重要。即使在这种特殊情况下,注释本身也被找到了,因此AnnotationsAttribute已经存在,必须重新添加。如果不这样做,您将收到RuntimeException抱怨缺少默认值的信息。

我希望这有助于其他Javassist黑客。