Package info. Cannot be modified using java 8 Java comments
I'm facing a problem. I have to modify the package information
package-info. java
@javax.xml.bind.annotation.XmlSchema(namespace = "http://some.url/soap/style/document_literal") package org.example.wsdl.wsdl;
The following codes apply to 1.7 0_ forty-five
// 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];
Use 1.8 0_ 05 when compiling and executing the same code, I receive the following error message:
java.lang.NoSuchFieldException: annotations
at java.lang.Class.getDeclaredField(Class.java:2057)
I know it's a Huck, at least it looks like a Huck But does Java 8 work as expected? How do I change the code that it uses with Java 8?
Javassist's answer is also very popular;)
Solution
Java 8 has changed the way annotations are stored internally Because you are using a malicious reflection hacker with hard coded field names, any Java update may re destroy your code
java. In 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;
}
}
I think you can use the new field values to fix your code temporarily A permanent fix is to change the annotation itself, not dynamically modify it at run time
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];
