2015-10-15 53 views
0

我有以下问题:我有一些代码(我无法更改)父类的一个变量获取子类的变量的影子。当注释为@XmlAttribute并用JAXB编组时,这会导致非法XML,并且在解组时会导致异常(由于非法XML)。这里是一个小例子,示出了该问题:JAXB中的非法XML /异常取消/编组阴影变量

import java.io.ByteArrayInputStream; 
    import java.io.ByteArrayOutputStream; 
    import java.io.PrintStream; 

    import javax.xml.bind.JAXBContext; 
    import javax.xml.bind.Marshaller; 
    import javax.xml.bind.Unmarshaller; 
    import javax.xml.bind.annotation.XmlAccessType; 
    import javax.xml.bind.annotation.XmlAccessorType; 
    import javax.xml.bind.annotation.XmlAttribute; 
    import javax.xml.bind.annotation.XmlRootElement; 
    import javax.xml.bind.helpers.DefaultValidationEventHandler; 

    import org.junit.Test; 

    public class InheritanceJaxbTest { 

     @Test 
     public void testInheritanceField() { 
      B b = new B("value"); 
      String xml = toXML(b); 
      System.out.println(xml); 
      B b_out = fromXML(xml); 
      System.out.println(b_out.myField); 
     } 

     @XmlRootElement 
     @XmlAccessorType(XmlAccessType.FIELD) 
     private static class A { 

      public A() { 
      } 

      public A(String myField) { 
       this.myField = myField; 
      } 

      @XmlAttribute 
      private String myField; 
     } 

     @XmlRootElement 
     @XmlAccessorType(XmlAccessType.FIELD) 
     private static class B extends A { 

      public B() { 
       super(); 
      } 

      public B(String myField) { 
       super(myField); 
       this.myField = myField; 
      } 

      @XmlAttribute 
      private String myField; 
     } 

     public <T> T fromXML(String xml) { 
      try { 
       JAXBContext jc = JAXBContext.newInstance(A.class, B.class); 
       Unmarshaller unmarshaller = jc.createUnmarshaller(); 
       unmarshaller.setEventHandler(new DefaultValidationEventHandler()); 
       return (T) unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes())); 
      } catch (Exception exc) { 
       throw new RuntimeException(exc); 
      } 
     } 

     public String toXML(Object obj) { 
      try { 
       ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
       PrintStream ps = new PrintStream(baos); 
       JAXBContext jc = JAXBContext.newInstance(A.class, B.class); 
       Marshaller marshaller = jc.createMarshaller(); 
       marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
       marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); 
       marshaller.setEventHandler(new DefaultValidationEventHandler()); 
       marshaller.marshal(obj, ps); 
       return baos.toString(); 
      } catch (Exception exc) { 
       throw new RuntimeException(exc); 
      } 
     } 
    } 

这将产生以下(显然非法的)XML:

<b myField="value" myField="value"/> 

而其后的解组操作引发以下例外:

java.lang.RuntimeException: javax.xml.bind.UnmarshalException 
- with linked exception: 
[org.xml.sax.SAXParseException: Attribute "myField" was already specified for element "b".] 
at InheritanceJaxbTest.fromXML(InheritanceJaxbTest.java:67) 

由于我基本上不能更改底层的Java类,我想用某种XmlAdapter或自定义的XmlStreamWriter或类似的东西来解决这个问题。有关如何进行的任何建议?

This question是相关的,但仍然没有见识如何继续而不改变Java类。

回答

1

我会通过写一个自定义annotation reader来解决这个问题。注释阅读器基本上是读取类的注释的东西。所以你可以实现你自己的阅读器,它可以根据你的需要处理阴影字段。

public interface AnnotationReader<T,C,F,M> { 

// ... 

    /** 
    * Reads an annotation on a property that consists of a field. 
    */ 
    <A extends Annotation> A getFieldAnnotation(Class<A> annotation, 
               F field, Locatable srcpos); 

    /** 
    * Checks if the given field has an annotation. 
    */ 
    boolean hasFieldAnnotation(Class<? extends Annotation> annotationType, F field); 

// ... 

    /** 
    * Gets all the annotations on a field. 
    */ 
    Annotation[] getAllFieldAnnotations(F field, Locatable srcPos); 

// ... 

} 

创建JAXB上下文时,您可以再使用你的读者:

final AnnotationReader<Type, Class, Field, Method> annotationReader = new MyCustomAnnotationReader(); 

final Map<String, Object> properties = new HashMap<String, Object>(); 

properties.put(JAXBRIContext.ANNOTATION_READER, annotationReader); 

或者考虑使用MOXy XML bindings代替注释。

+0

非常感谢,这似乎是一个非常有希望的方向去调查。我会这样做,让你知道结果:-) – roesslerj