Personal notes on Java
For other technologies like HTML, CSS, .NET, PHP, etc. check my other blog

Java Architecture for XML Binding (JAXB) provides a fast and convenient way to bind XML schemas and Java representations, making it easy for Java developers to incorporate XML data and processing functions in Java applications. As part of this process, JAXB provides methods for unmarshalling (reading) XML instance documents into Java content trees, and then marshalling (writing) Java content trees back into XML instance documents. JAXB also provides a way to generate XML schema from Java objects.
Ref: Trail: Java Architecture for XML Binding

Marshal/UnMarshall with JAXB Example

Marshalling to XML is very easy through the use of annotations like:
This example is fully functional and uses two example classes:
JaxbTest.java

package test.jaxb;
package test.jaxb;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;

/**
 * @author Antero Mano
 */
@XmlRootElement(name = "myRootElement")
public class JaxbTest {

    //NOTE: The List field below is annotated with JAXB tags bc it doesnt have 
    //set/get (not a property).
    //It doesnt have set/get on purpose bc we dont want to set/get the entire 
    //list - we just want to add objects to it:
    @XmlElementWrapper(name = "myListElementWrapper")
    @XmlElement(name = "myListElement")
    private List<Other> lista = new ArrayList<Other>();
    //Properties (= fields with set/get) are automatically mapped:
    private String greating = "Hello ";
    //fields with (no JAXB tags) and (no set/get) are ignored:
    private static final String FILENAME = "myxml.xml";

    //FINAL NOTE: dont tag fields that have set/get (properties). Since it has 
    //set/get it will automatically be mapped. If you tag the field you can get
    //double output or a JAXB compile error.
    //like any JavaBean, JAXB needs the class to have a no-arg default constructor.
    public JaxbTest() {
    }

    private JaxbTest(String someString, Other myObj) {
        this.greating += someString;
        this.lista.add(myObj);
    }

    public String getGreating() {
        return greating;
    }

    public void setGreating(String greating) {
        this.greating = greating;
    }

    public void add(Other obj) {
        this.lista.add(obj);
    }
    
        public boolean marshallToXmlFile() {
        try {
            JAXBContext context = JAXBContext.newInstance(JaxbTest.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            //if you want you can add a XSL to the resulting xml doc (Java 6):
            //m.setProperty("com.sun.xml.internal.bind.xmlHeaders", 
            //      "<?xml-stylesheet type=\"text/xsl\" href=\"my_xslt.xsl\"?>");            
            //if you want you can add a XSL to the resulting xml doc (Java 5):            
            //m.setProperty("com.sun.xml.bind.xmlHeaders",
            //      "<?xml-stylesheet type=\"text/xsl\" href=\"my_xslt.xsl\"?>");

            //print XML doc on screen:
            m.marshal(this, System.out);
            //save XML doc to file:
            m.marshal(this, new File(JaxbTest.FILENAME));

            return true;
        } catch (JAXBException ex) {
            ex.printStackTrace();
        }
        return false;
    }

    public static JaxbTest unMarshallFromXmlFile() {
        try {
            JAXBContext jc = JAXBContext.newInstance(JaxbTest.class);
            Unmarshaller u = jc.createUnmarshaller();

            //print all known type for this JAXBContext
            String allJAXBContextKnownTypes = jc.toString();
            System.out.println(allJAXBContextKnownTypes);

            File file = new File(JaxbTest.FILENAME);
            JAXBElement<JaxbTest> root = u.unmarshal(new StreamSource(file), JaxbTest.class);
            
            return root.getValue();
        } catch (JAXBException e) {
            //e.printStackTrace();
        }
        return null;
    }

    public static void main(String args[]) {
        JaxbTest jaxbTest = JaxbTest.unMarshallFromXmlFile();
        
        if (jaxbTest == null) {
            System.out.println("xml file doesnt exist yet. A new one will be created.");
            jaxbTest = new JaxbTest("World", new Other(0.5, "1/2"));
        }
        
        jaxbTest.add(new Other(1.5, "one and a half"));
        jaxbTest.add(new Other(2.2, "two something... who cares?!"));
        jaxbTest.marshallToXmlFile();
    }
}


Other.java
package test.jaxb;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * @author Antero Mano
 */
@XmlRootElement(name = "myInnerClassRootElement")
public class Other {

    //fields with no set/get and no JAXB annotation are ignored:
    private String example = "will be ignored by JAXB!";
    
    //next field has set/get (a property) so its automatically mapped:
    private double number;
    
    //next field needs the @XmlElement tag bc it doesn't have set/get (not a property):
    @XmlElement
    private String txt;

    //like any JavaBean JAXB needs the class to have a no-arg default constructor.
    public Other() {
    }

    public Other(double number, String txt) {
        this.number = number;
        this.txt = txt;
    }

    public double getNumber() {
        return number;
    }

    public void setNumber(double number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return Double.toString(this.number);
    }
}

Resulting xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myRootElement>
    <myListElementWrapper>
        <myListElement>
            <txt>1/2</txt>
            <number>0.5</number>
        </myListElement>
        <myListElement>
            <txt>one and a half</txt>
            <number>1.5</number>
        </myListElement>
        <myListElement>
            <txt>two something... who cares?!</txt>
            <number>2.2</number>
        </myListElement>
    </myListElementWrapper>
    <greating>Hello World</greating>
</myRootElement>

Things to test:
If you remove @XmlElementWrapper(name = "myListElementWrapper")
JAXB wont put any wrapper around the list elements:

<myRootElement>
    <myListElement>
        <txt>1/2</txt>
        <number>0.5</number>
    </myListElement>
    <myListElement>
        <txt>one and a half</txt>
        <number>1.5</number>
    </myListElement>
    <myListElement>
        <txt>two something... who cares?!</txt>
        <number>2.2</number>
    </myListElement>
    <greating>Hello World</greating>
</myRootElement>
If you remove @XmlElement(name = "myListElement")
JAXB will use the field variable name as default:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myRootElement>
    <myListElementWrapper>
        <lista>
            <txt>1/2</txt>
            <number>0.5</number>
        </lista>
        <lista>
            <txt>one and a half</txt>
            <number>1.5</number>
        </lista>
        <lista>
            <txt>two something... who cares?!</txt>
            <number>2.2</number>
        </lista>
    </myListElementWrapper>
    <greating>Hello World</greating>
</myRootElement>
If you remove the @XmlRootElement(name = "myInnerClassRootElement")
Nothing will change. The annotation is not necessary for our result.
It would only be usefull if you wanted to map this class directly using a method like marshallToXmlFile().

Mapping Enumerations

Ref: how to use enum in jaxb unmarshalling
    @XmlEnum
    public enum Estado {

        @XmlEnumValue("pending")
        PENDING,
        @XmlEnumValue("aproved")
        APROVED,
        @XmlEnumValue("canceled")
        CANCELLED,
        @XmlEnumValue("notfound")
        NOT_FOUND
    }

Mapping List, ArrayList, and other Collection objects

Option 1:

@XmlElementWrapper(name = "myListElementWrapper")
@XmlElement(name = "myListElement")
private List<Other> lista = new ArrayList<Other>();
Option 2 (for ex. when you have a object that extends a Collection):
Ref. stackoverflow
@XmlRootElement(name = "db")
class Database extends ArrayList<Encomenda> {
    @XmlElement(name = "encomenda")
    public List<Encomenda> getDatabase() {
        return this; //"self-getter"
    }
}
Then in another class we could do (Recal that Database extends an ArrayList so it already implements interface List):

public class DaoImpl implements IDao {
    private final String FILENAME = "dbMock.xml";
    private List<Encomenda> db;
 
  public DaoImpl() {
        db = unMarshallFromXmlFile();;
    }

    private List<Encomenda> unMarshallFromXmlFile() {      
        try {
            JAXBContext jc = JAXBContext.newInstance(Database.class);
            Unmarshaller u = jc.createUnmarshaller();
            File file = new File(this.FILENAME);
            JAXBElement<Database> root = u.unmarshal(new StreamSource(file), Database.class);
            return root.getValue();
        } catch (JAXBException e) {
            //e.printStackTrace();
        }
        return null;
    }
 ...
}

JAXB

Tutorials and Documentation:

Using only annotations you can easily marshal and unmarshal objects to and from XML

Another Example: Marshall (Serialize/write) Java Objects to a XML doc

The main class (BookSearchXML) has a List of Livro objects:
@XmlRootElement(name = "Biblioteca")
public class BookSearchXML {

    //@XmlElementWrapper(name = "Biblioteca")
    @XmlElement(name = "Livro")
    private List<Livro> livros = new ArrayList<Livro>();
    ...
    
    private void marshallToXmlFile(String fileName) {
        try {
            JAXBContext context = JAXBContext.newInstance(BookSearchXML.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            //if you want to add an XSL to the generated XML doc:
            m.setProperty("com.sun.xml.internal.bind.xmlHeaders", 
                        "<?xml-stylesheet type=\"text/xsl\" href=\"my_xslt.xsl\"?>");
            m.marshal(this, System.out);//prints XML doc to screen
            m.marshal(this, new File(fileName)); //saves XML doc to file
        } catch (JAXBException ex) {
            Logger.getLogger(BookSearchXML.class.getName()).log(Level.SEVERE, null, ex);
        }
    }    
}

Class Livro is a very basic JavaBean:
@XmlRootElement(name = "Livro")
public class Livro {
    private String titulo, ano, editora, paginas, isbn, descricao, url, capa;

    @XmlElementWrapper(name = "autor")
    @XmlElement(name = "nome")
    ArrayList<String> autores;
    ...
} 

Generated XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="my_xslt.xsl"?>
<Biblioteca>
    <Livro>
        <autor>
            <nome>James Gosling</nome>
        </autor>
        <ano>2000</ano>
        <capa>http://</capa>
        <descricao>For nearly five years..</descricao>
        <editora>Addison-Wesley Professional</editora>
        <ISBN>9780201310085</ISBN>
        <paginas>505</paginas>
        <titulo>The Java Language Specification</titulo>
        <URL>http://books.google.co.uk/books?id=Ww1B9O_yVGsC&amp;amp;dq=java&amp;amp</URL>
    </Livro>
    <Livro>
        <autor>
            <nome>Herbert Schildt</nome>
        </autor>
        <ano>2002</ano>
        <capa>http://</capa>
        <descricao></descricao>
        <editora>McGraw-Hill Professional</editora>
        <ISBN>9780072225136</ISBN>
        <paginas>565</paginas>
        <titulo>Java 2</titulo>
        <URL>http://books.google.co.uk/books?id=YWDJJGYaLG4C&amp;amp;dq=java&amp;amp</URL>
    </Livro>
</Biblioteca> 


Add a xml-stylesheet (XSL) to the generated XML doc

You just need to set a property on your Marshaller object:
m.setProperty("com.sun.xml.internal.bind.xmlHeaders",
  "<?xml-stylesheet type=\"text/xsl\" href=\"my_xslt.xsl\"?>");

Note: There are different names to accomplish this in Java5 and Java 6
Lets consider an object Marshaller m:
  • Java5:
    m.setProperty("com.sun.xml.bind.xmlHeaders",
  • Java6:
    m.setProperty("com.sun.xml.internal.bind.xmlHeaders",

dasfg asdf


todo
code
todo
code
todo
code
todo
code
todo
code

1 comentário:

Unknown disse...

Thanks for your sharing,i learn a lot from your post.There is a lot of very useful knowledge in your post.I enjoy reading it and hope to see more.There is guy here swearing up and down that JAXB is the greatest thing since sliced bread. I am curious to see what stackoverflow users think the use case is for JAXB and what makes it a good or a bad solution for that case.
java barcode maker

Enviar um comentário