2014-07-02 47 views
5

का उपयोग कर पैकेज-info.java की एनोटेशन को संशोधित करने में असमर्थ, मुझे एक समस्या का सामना करना पड़ रहा है जहां मुझे पैकेज-जानकारी संशोधित करना है।जावा 8

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 साथ ठीक काम करता है।

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

मैं अपने जानते हैं कि एक हैक, कम से कम यह एक तरह लग रहा है:

//   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 के साथ एक ही कोड को क्रियान्वित मैं यह त्रुटि संदेश मिलता है। लेकिन क्या जावा 8 यहां अपेक्षित काम करता है? मुझे उस कोड को कैसे बदलना है कि यह जावा 8 के साथ काम करता है?

Javassist जवाब भी स्वागत कर रहे हैं;)

उत्तर

3

जावा 8 बदला, एनोटेशन आंतरिक रूप से जमा हो जाती है। चूंकि आप एक हार्डकोडेड फ़ील्ड नाम के साथ एक बुरा प्रतिबिंब हैक का उपयोग कर रहे हैं, इसलिए किसी भी जावा अपडेट में आपके कोड को फिर से चलाने की क्षमता है।

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

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

मुझे पता है कि कोई भी जावा अपडेट मेरे कोड को तोड़ सकता है। एक अलग तरीके के लिए कोई सुझाव? – Zarathustra

+0

@Zarathustra आप सिर्फ एनोटेशन क्यों नहीं बदल सकते? – Jeffrey

+0

इसके जेनरेट कोड। मैं विभिन्न सर्वरों पर एक एसओएपी सेवा के साथ संचार कर रहा हूं, सभी एक ही wsdl साझा करते हैं, लक्ष्य नामस्थान की अपेक्षा करते हैं क्योंकि इसमें होस्टनाम शामिल है। – Zarathustra