2014-07-02 9 views
5

Sono di fronte a un problema in cui devo modificare un pacchetto di informazioni.Impossibile modificare l'annotazione di package-info.java utilizzando Java 8

package-info.java

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

Il seguente codice funziona bene con 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]; 

Quando la compilazione e l'esecuzione dello stesso codice con 1.8.0_05 ottengo questo messaggio di errore:

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

So che è un Hack, almeno sembra che uno. Ma Java 8 funziona qui come previsto? Come devo cambiare quel codice che funziona con Java 8 allora?

Javassist risposte sono i benvenuti;)

risposta

3

Java 8 cambiato il modo annotazioni vengono memorizzati internamente. Dal momento che stai usando un brutto ragionamento con un nome di campo hardcoded, qualsiasi aggiornamento Java ha il potenziale per rompere il tuo codice.

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; 
    } 
} 

suppongo che si possa utilizzare i nuovi valori di campo per risolvere temporaneamente il codice. Una correzione permanente consiste nel modificare l'annotazione stessa, invece di modificarla dinamicamente in fase di runtime.

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> annotations = (Map<Class<? extends Annotation>, Annotation>) annotationsField 
     .get(annotationData); 
annotations.put(XmlSchema.class, newAnnotation); 

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

So che qualsiasi aggiornamento java potrebbe rompere il mio codice. Qualche suggerimento per un altro modo? – Zarathustra

+0

@Zarathustra Perché non puoi semplicemente modificare l'annotazione? – Jeffrey

+0

il suo codice generato. Sto comunicando con un servizio SOAP su diversi server, tutti condividono lo stesso wsdl, aspetto lo spazio dei nomi target perché include il nome host. – Zarathustra

Problemi correlati