8

Here's a trivial excerpt from my XSD file

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="ns"
    xmlns:tns="sns" elementFormDefault="qualified">

  <element name="document">
        <attribute name="title" use="required"/>
  </element>
</schema>

I use the maven-jaxb2-plugin to generate Java classes from this. The Document class has a getTitle() method to return the text of the title attribute.

I want to add an additional method to Document:

public String getStrippedTitle() {
   return getTitle().replaceAll("\\s+", "");
}

I want my extra method to appear on the unmarshalled object (rather than me just calling it or writing a wrapper class) because I want to pass the top-level unmarshalled object off to a string template and have it iterate over sub-elements calling my extra method.

I found instructions but they tell me to set a property on the Unmarshaller and my (Mac OS X, Java 7) implementation doesn't appear to support any properties.

How should I do this?

Roman C
  • 49,761
  • 33
  • 66
  • 176
Nathaniel Waisbrot
  • 23,261
  • 7
  • 71
  • 99

2 Answers2

8

Following the link the Brian Henry gave, I found I could perform binding customization inline in my schema file to do what I wanted. The effect is exactly the same as Brian's solution, but it doesn't require a reference to a reference to com.sun.xml.internal.

First, the schema file gets modified somewhat:

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="ns"
    xmlns:tns="sns" elementFormDefault="qualified"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">

  <element name="document">
      <annotation>
          <appinfo>
              <jaxb:class implClass="DocumentEx" />
          </appinfo>
      </annotation>
      <attribute name="title" use="required"/>
  </element>
</schema>

When the schema gets compiled into Java code, the generated ObjectFactory will refer to DocumentEx instead of Document. DocumentEx is a class I create, which looks like this:

public class DocumentEx extends Document {
   public String getStrippedTitle() {
       return getTitle().replaceAll("\\s+", "");
   }
}

Document (the class I'm extending) is still generated by the schema-to-Java compiler. Now when I unmarshall a document I actually get a DocumentEx object:

    JAXBContext jaxbContext = JAXBContext.newInstance("com.example.xml");
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    unmarshaller.setSchema(testSchema);
    DocumentEx doc = (DocumentEx)unmarshaller.unmarshal(xmlFile);

There is some (hard-to-parse) documentation for this at Oracle and some helpful examples at O'Reilly.

Nathaniel Waisbrot
  • 23,261
  • 7
  • 71
  • 99
  • This doesn't work for me: ` ` A class/interface with the same name "br.ufop.decom.Task" is already in use. Use a class customization to resolve this conflict. – Michael Pacheco Nov 02 '18 at 19:58
  • I don't know. Your `implClass` and the class in the error message don't match, so I suspect the problem is beyond the scope of the snippit you pasted here? You might need to ask this as its own question to get enough space to describe your problem. – Nathaniel Waisbrot Nov 04 '18 at 11:52
  • 1
    The problem is that the XSD generated by the Intellij seems not to be compatible with the jaxb annotations. I generated the XSD in another format `Global elements/Local types` and the annotation works well – Michael Pacheco Nov 04 '18 at 18:26
2

You could try to update the property name you're seeing in the linked doc. try this instead:

com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.FACTORY

or

"com.sun.xml.internal.bind.ObjectFactory"

I'd guess that will get you past the PropertyException I figure you're seeing. The most thorough answer here, suggests this is not guaranteed to work, but worth trying since you've come this far. Source code, as far as I looked (not far) appears to support this property.

Community
  • 1
  • 1
Brian Henry
  • 3,161
  • 1
  • 16
  • 17
  • This works. Thanks! Do you have any suggestions for a better overall method of unmarshalling an XML file into Java classes with some extra methods? I was trying SAX before JAXB, but it felt like I was just writing my own (crummy) JAXB implementation. – Nathaniel Waisbrot Jan 11 '13 at 20:55
  • 1
    @NathanielWaisbrot - You don't need to generate the JAXB model from an XML schema. You can start from whatever object model you want and use the JAXB annotations to configure the XML mapping. – bdoughan Jan 11 '13 at 21:19