2011-12-31 1 views
1

Я использую Javassist для добавления и изменения аннотаций на package-info «класс».Почему Javassist настаивает на поиске значения аннотации по умолчанию, если он явно указан?

В некоторых случаях мне нужно иметь дело со следующим краевым корпусом. Кто-то (неправильно) указал аннотацию @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()@XmlJavaTypeAdapters представляет собой массив из @XmlJavaTypeAdapter. Я указал свой тип массива, пытаясь угадать намерение Zen-подобной документации —, кажется, что если вы добавите еще один MemberValue, то это MemberValue будет каким-то образом служить типом массива. В моем случае я хочу, чтобы тип массива был @XmlJavaTypeAdapter, что является аннотацией, поэтому единственным видом MemberValue, который, как представляется, был AnnotationMemberValue. Поэтому я создал пустую одну из них и задал ее как тип массива.

Это работает прекрасно, насколько это возможно, до тех пор, пока вы остаетесь «внутри» джавассиста.

Однако, похоже, что-то пошло не так. Если я попрошу Javassist преобразовать все свои проприетарные аннотации в подлинную Java java.lang.annotation.Annotation, тогда, когда я попытаюсь получить доступ к атрибуту value() этой аннотации @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 
    } 
} 

Так почему же Javassist ищет значение по умолчанию в этом случае?

Моя более крупная проблема, конечно, относится к этому (к сожалению, довольно общему) случаю, где @XmlJavaTypeAdapters указан без дополнительной информации. Мне нужно добавить значение члена value, которое может содержать массив аннотаций @XmlJavaTypeAdapter. Я не могу понять, как это сделать с Джавасистом. Как всегда, вся помощь ценится.

ответ

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, жалуясь на отсутствие значения по умолчанию.

Надеюсь, это поможет другим хавасистским хакерам.

Смежные вопросы