无法使用Java 8修改package-info.java的注释

前端之家收集整理的这篇文章主要介绍了无法使用Java 8修改package-info.java的注释前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正面临一个问题,我必须修改包信息.

package-info.java

@javax.xml.bind.annotation.XmlSchema(namespace = "http://some.url/soap/style/document_literal")
package org.example.wsdl.wsdl;

以下代码适用于1.7.0_45.

//          do not load any classes before,this could break the following code.
            Class<?> pkgInfo = Class.forName("org.example.wsdl.package-info",true,NameSpaceModifier.class.getClassLoader());
            Field field = Class.class.getDeclaredField("annotations");
            field.setAccessible(true);

            final XmlSchema oldAnnotation = (XmlSchema) pkgInfo.getAnnotations()[0];
            logger.debug("Old Annotation namespace value was: " + oldAnnotation.namespace());
            XmlSchema newAnnotation = new XmlSchema() {

                @Override
                public XmlNs[] xmlns() {
                    return oldAnnotation.xmlns();
                }

                @Override
                public String namespace() {
                    return "newNs";
                }

                @Override
                public XmlNsForm elementFormDefault() {
                    return oldAnnotation.elementFormDefault();
                }

                @Override
                public XmlNsForm attributeFormDefault() {
                    return oldAnnotation.attributeFormDefault();
                }

                @Override
                public String location() {
                    return oldAnnotation.location();
                }

                @Override
                public Class<? extends Annotation> annotationType() {
                    return oldAnnotation.annotationType();
                }
            };

            @SuppressWarnings("unchecked")
            Map<Class<? extends Annotation>,Annotation> annotations = (Map<Class<? extends Annotation>,Annotation>) field.get(pkgInfo);
            annotations.put(XmlSchema.class,newAnnotation);

            XmlSchema modifiedAnnotation = (XmlSchema) pkgInfo.getAnnotations()[0];

使用1.8.0_05编译和执行相同的代码时,我收到以下错误消息:

java.lang.NoSuchFieldException: annotations
    at java.lang.Class.getDeclaredField(Class.java:2057)

我知道它是一个哈克,至少它看起来像一个.但Java 8是否按预期工作?
我如何更改它与Java 8一起使用的代码呢?

Javassist的答案也很受欢迎;)

解决方法

Java 8改变了内部存储注释的方式.由于您使用的是具有硬编码字段名称的恶意反射黑客,因此任何Java更新都有可能重新破坏您的代码.

java.lang.Class中:

/**
 * @since 1.5
 */
public Annotation[] getAnnotations() {
    return AnnotationParser.toArray(annotationData().annotations);
}

private volatile transient AnnotationData annotationData;

private AnnotationData annotationData() {
    while (true) { // retry loop
        AnnotationData annotationData = this.annotationData;
        int classRedefinedCount = this.classRedefinedCount;
        if (annotationData != null &&
            annotationData.redefinedCount == classRedefinedCount) {
            return annotationData;
        }
        // null or stale annotationData -> optimistically create new instance
        AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
        // try to install it
        if (Atomic.casAnnotationData(this,annotationData,newAnnotationData)) {
            // successfully installed new AnnotationData
            return newAnnotationData;
        }
    }
}

private static class AnnotationData {
    final Map<Class<? extends Annotation>,Annotation> annotations;
    final Map<Class<? extends Annotation>,Annotation> declaredAnnotations;

    // Value of classRedefinedCount when we created this AnnotationData instance
    final int redefinedCount;

    AnnotationData(Map<Class<? extends Annotation>,Annotation> annotations,Map<Class<? extends Annotation>,Annotation> declaredAnnotations,int redefinedCount) {
        this.annotations = annotations;
        this.declaredAnnotations = declaredAnnotations;
        this.redefinedCount = redefinedCount;
    }
}

我想你可以使用新的字段值来临时修复你的代码.永久修复是更改注释本身,而不是在运行时动态修改它.

Field annotationDataField = Class.class.getDeclaredField("annotationData");
annotationDataField.setAccessible(true);

Object annotationData = annotationDataField.get(pkgInfo);

Field annotationsField = annotationData.getClass().getDeclaredField("annotations");
annotationsField.setAccessible(true);

Map<Class<? extends Annotation>,Annotation>) annotationsField
        .get(annotationData);
annotations.put(XmlSchema.class,newAnnotation);

XmlSchema modifiedAnnotation = (XmlSchema) pkgInfo.getAnnotations()[0];

猜你在找的Java相关文章