2016-08-22 11 views
0

docx4j의 V3.3.0의 효율적인 딥 카피는 JAXB 객체를 복제하려면 다음 코드를 사용합니다 (이 자바 6 지원하기 때문에, 우리가 사용하는)MOXY : JAXBElement 첨부

public static <T> T deepCopy(T value, JAXBContext jc) { 

    if (value==null) { 
     throw new IllegalArgumentException("Can't clone a null argument"); 
    } 

    try { 
     @SuppressWarnings("unchecked") 
     Class<T> clazz = (Class<T>) value.getClass(); 
     JAXBElement<T> contentObject = new JAXBElement<T>(new QName(clazz.getSimpleName()), clazz, value); 
     JAXBSource source = new JAXBSource(jc, contentObject); 
     JAXBElement<T> elem = jc.createUnmarshaller().unmarshal(source, clazz); 

     T res; 
     if (value instanceof JAXBElement<?>) { 
      @SuppressWarnings("unchecked") 
      T resT = (T) elem; 
      res = resT; 
     } else { 
      @SuppressWarnings("unchecked") 
      T resT = (T) elem.getValue(); 
      res = resT; 
     } 

     return res; 
    } catch (JAXBException ex) { 
     throw new IllegalArgumentException(ex); 
    } 
} 

MOXY의 v2.5.2로를 최신 2.6.3, 예를 들어, JAXBElement 첨부를 복제하려고 :에

public void testIssue212() { 

    CTBookmark bookmark = Context.getWmlObjectFactory().createCTBookmark(); 
    JAXBElement<CTBookmark> el =Context.getWmlObjectFactory().createBodyBookmarkStart(bookmark); 

    Object o = XmlUtils.deepCopy(el); 
} 

결과 :

[Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.XMLMarshalException 
    Exception Description: A descriptor for class javax.xml.bind.JAXBElement was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.] 
     at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:980) 
     at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:303) 
     at org.docx4j.XmlUtils.deepCopy(XmlUtils.java:974) 
     ... 25 more 
    Caused by: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.XMLMarshalException 
    Exception Description: A descriptor for class javax.xml.bind.JAXBElement was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter. 
     at org.eclipse.persistence.exceptions.XMLMarshalException.descriptorNotFoundInProject(XMLMarshalException.java:140) 
     at org.eclipse.persistence.internal.oxm.Context$ContextState.getSession(Context.java:145) 
     at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:795) 
     at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:1) 
     at org.eclipse.persistence.internal.oxm.Context.getSession(Context.java:466) 
     at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:364) 
     at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:1) 
     at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:466) 
     at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:695) 
     at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:655) 
     at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:301) 
     ... 26 more 

것은 우리는이 지혜를 해결할 수 있습니다 h는 다음과 같습니다.

 JAXBElement<T> elem; 

     if (Context.getJaxbImplementation().equals(JAXBImplementation.ECLIPSELINK_MOXy) 
       && value instanceof JAXBElement<?>) { 

      elem = (JAXBElement<T>) value; 
      Class<?> valueClass = elem.getDeclaredType(); 

      Marshaller mar = jc.createMarshaller(); 
      ByteArrayOutputStream bout = new ByteArrayOutputStream(256); 
      mar.marshal(elem, bout); 

      Unmarshaller unmar = jc.createUnmarshaller(); 
      elem = (JAXBElement<T>)unmar.unmarshal(new StreamSource(new ByteArrayInputStream(
        bout.toByteArray())), valueClass); 

     } 

더 좋은 방법이 있습니까?

답변

0

면책 조항 : 내가 꽤 잘 작업에 맞는 생각 Copyable Plugin '를 포함 JAXB2-Basics의 저자입니다.

Copyable Plugin에 관심이있을 수 있습니다. 반사없는 전략적 복사 방법을 생성합니다. 메이븐에서

활성화 (또한 Using JAXB2 Basics Plugins 참조)

 <plugin> 
      <groupId>org.jvnet.jaxb2.maven2</groupId> 
      <artifactId>maven-jaxb2-plugin</artifactId> 
      <configuration> 
       <extension>true</extension> 
       <args> 
        <arg>-Xcopyable</arg> 
       </args> 
       <plugins> 
        <plugin> 
         <groupId>org.jvnet.jaxb2_commons</groupId> 
         <artifactId>jaxb2-basics</artifactId> 
        </plugin> 
       </plugins> 
      </configuration> 
     </plugin> 

플러그인은 깊이 반성없는 전략 기반 clonecopyTo 방법 (아래 참조)를 생성한다. 이것은 매우 효율적인 복사를 제공합니다. 또한 기존 인스턴스에 "복사"하거나 자신의 전략을 지정하여 복사 할 대상과 방법을 사용자 정의 할 수 있습니다. 예를 들어, id 필드 또는 이와 유사한 것을 복사하지 않을 수 있습니다. 또한 생성 된 코드는 JAXBElement을 처리하는 방법을 알고 있습니다.

public Object clone() { 
    return copyTo(createNewInstance()); 
} 

public Object copyTo(Object target) { 
    final CopyStrategy2 strategy = JAXBCopyStrategy.INSTANCE; 
    return copyTo(null, target, strategy); 
} 

public Object copyTo(ObjectLocator locator, Object target, CopyStrategy2 strategy) { 
    final Object draftCopy = ((target == null)?createNewInstance():target); 
    if (draftCopy instanceof IssueJIIB35) { 
     final IssueJIIB35 copy = ((IssueJIIB35) draftCopy); 
     { 
      Boolean nameShouldBeCopiedAndSet = strategy.shouldBeCopiedAndSet(locator, this.isSetName()); 
      if (nameShouldBeCopiedAndSet == Boolean.TRUE) { 
       String sourceName; 
       sourceName = this.getName(); 
       String copyName = ((String) strategy.copy(LocatorUtils.property(locator, "name", sourceName), sourceName, this.isSetName())); 
       copy.setName(copyName); 
      } else { 
       if (nameShouldBeCopiedAndSet == Boolean.FALSE) { 
        copy.name = null; 
       } 
      } 
     } 
     // ... 
    } 
    return draftCopy; 
} 

public Object createNewInstance() { 
    return new IssueJIIB35(); 
} 

이 조금/이상한 복잡 보일 수 있지만, 계정에 꽤 많은 JAXB의 특수성을 취

이 생성 된 코드의 일종이다.

+0

감사합니다. iirc, 과거에 여러 확장 프로그램을 한꺼번에 사용하려고 할 때 곤란했습니다. docx4j는 parent-pointer-plugin을 사용합니다. – JasonPlutext