Page 1 of 1

Missing @XmlRootElement annotations; deepCopy (cloning)

PostPosted: Tue Sep 08, 2009 4:45 pm
by holgerschlegel
I just received an some exceptions saying that the @XmlRootElement is missing on some of the generated classes in the wml package. In my run I spotted the following classes:
org.docx4j.wml.CTTblCellMar
org.docx4j.wml.CTShortHexNumber
org.docx4j.wml.TblWidth
org.docx4j.wml.TblBorders
org.docx4j.wml.CTTblLayoutType

Once added the annotation manually the exceptions are gone but changing a generated class manually sounds like a very bad idea for me. Could you please regenerate that classes with the appropriate XmlRootElement anotations.

Re: Missing @XmlRootElement annotations

PostPosted: Wed Sep 09, 2009 1:03 am
by jason
I do add them manually, provided the complex type in the schema won't be used by multiple different tag names. I have a patch I apply to add the @XmlRootElement annotations in again after class regeneration.

I don't think there is a way to put the annotations in the XSD so that they are generated. (There is, or was, an aggressive optimization mode in XJC, but I haven't tried that)

See generally http://weblogs.java.net/blog/kohsuke/ar ... axb_p.html which includes instructions for marshalling an object without @XmlRootElement

cheers .. Jason

Re: Missing @XmlRootElement annotations

PostPosted: Wed Sep 09, 2009 10:31 am
by holgerschlegel
Thanks for the tip. I was able to write my version of XmlUtils.deepCopy that works for objects without the XmlRootElement anotation.

Not sure if it is the best way to do that, but the following works for me:
Code: Select all
   private <T> T deepCopy(T value) {
      try {
         JAXBElement<?> elem;
         Class<?> valueClass;
         if (value instanceof JAXBElement<?>) {
            elem = (JAXBElement<?>) value;
            valueClass = elem.getDeclaredType();
         } else {
            @SuppressWarnings("unchecked")
            Class<T> classT = (Class<T>) value.getClass();
            elem = new JAXBElement<T>(
                  new QName("temp"), classT, value);
            valueClass = classT;
         }
         
         Marshaller mar = Context.jc.createMarshaller();
         ByteArrayOutputStream bout = new ByteArrayOutputStream(256);
         mar.marshal(elem, bout);

         Unmarshaller unmar = Context.jc.createUnmarshaller();
         elem = unmar.unmarshal(
               new StreamSource(
                     new ByteArrayInputStream(bout.toByteArray())),
               valueClass);
         
         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);
      }
   }


I suitable, feel free to take it over into the XmlUtils class of docx4j. But I've not tested it very much, just with the classes I need in my current context (TblPr childs).

Regards
Holger

Re: Missing @XmlRootElement annotations

PostPosted: Fri Sep 11, 2009 3:15 am
by jason
Thanks for that Holger; it looks good to me, let me test it with a view to replacing the existing methods.

Re: Missing @XmlRootElement annotations

PostPosted: Wed Sep 16, 2009 7:47 am
by jason
holgerschlegel wrote:feel free to take it over into the XmlUtils class of docx4j


Now committed as revision 893; thanks again!