Saturday, 23 February 2013

Use JAXB to read and write xml in JAVA

JAXB is a powerful yet simple to use api to read and write xml in java . 

This is the sample xml which we want to read using java .
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<xmlObject>
    <auction>
        <auctionType>PUBLIC</auctionType>
        <description>this is auction from file</description>
        <product>
            <details>Product XML</details>
            <name>this is product from file</name>
        </product>
        <bids>
    <bid>
       <amount>23</amount>
       <time>23-12-2012</time>
       <user>abhishek</user>
    </bid>
    
    <bid>
       <amount>25</amount>
       <time>23-11-2012</time>
       <user>john</user>
    </bid>
</bids>
        <startDateTime>2012-10-30T23:46:13.394</startDateTime>
        <endDateTime>2012-12-30T23:46:13.394</endDateTime>
    </auction>
</xmlObject>

this is root class which is mapped to xmlObject element in the xml
package com.xml;

import java.io.File;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.Date;

import java.util.HashSet;

import java.util.LinkedList;

import java.util.List;

import java.util.Set;

import javax.xml.bind.JAXBContext;

import javax.xml.bind.JAXBException;

import javax.xml.bind.Marshaller;

import javax.xml.bind.Unmarshaller;

import javax.xml.bind.annotation.XmlRootElement;

import com.model.Auction;

import com.model.AuctionStatus;

import com.model.AuctionType;

import com.model.Bid;

import com.model.Product;

/**

 * JAXB class to create Java Objects from XML File

 * @author abhishek.somani

 *

 */

@XmlRootElement(name = "xmlObject")

public class XMLObject

{

private List<auction> auction;

public XMLObject()

{

auction = new ArrayList<auction>();

}

public List<auction> getAuction()

{

return auction;

}

public List<auction> setAuction(List<auction> aunctions)

{
return this.auction = aunctions;
}

}




This is Auction class which is mapped to auction element in xml.


package com.model;

import java.io.Serializable;

import java.util.Date;

import java.util.HashSet;

import java.util.Set;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlElementWrapper;

import javax.xml.bind.annotation.XmlRootElement;

import javax.xml.bind.annotation.XmlTransient;

/**

 * Model class Mapped to database table auction and XmlElement auction

 * @author abhishek.somani

 *

 */

@XmlRootElement

public class Auction implements Serializable

{

/**

* 

*/

private static final long serialVersionUID = 1L;

private Product product;

private int id;

private String auctionStatus;

private String auctionType;

private String description;

private Date startDateTime;

private Date endDateTime;

private Bid winnerBid;

private Set<Bid> bids = new HashSet<Bid>();

public static long getSerialversionuid()

{

return serialVersionUID;

}

public Bid getWinnerBid()

{

return winnerBid;

}

public void setWinnerBid(Bid winnerbid)

{

this.winnerBid = winnerbid;

}

public Auction()

{

}

public Auction(Product product, Date startTime, String type, String status)

{

this.product = product;

this.startDateTime = startTime;

this.auctionType = type;

this.auctionStatus = status;

}

public Set<Bid> getBids()

{

return bids;

}


@XmlElement(name = "bid")

@XmlElementWrapper(name = "bids")

public void setBids(Set<Bid> bids)

{

this.bids = bids;

}

public Product getProduct()

{

return product;

}

public void setProduct(Product product)

{

this.product = product;

}

public int getId()

{

return id;

}

@XmlTransient

public void setId(int id)

{

this.id = id;

}

public String getAuctionStatus()

{

return auctionStatus;

}

public void setAuctionStatus(String auctionStatus)

{

this.auctionStatus = auctionStatus;

}

public String getAuctionType()

{

return auctionType;

}

public void setAuctionType(String acutionType)

{

this.auctionType = acutionType;

}

public String getDescription()

{

return description;

}

public void setDescription(String description)

{

this.description = description;

}

public Date getStartDateTime()

{

return startDateTime;

}

public void setStartDateTime(Date startDateTime)

{

this.startDateTime = startDateTime;

}

public Date getEndDateTime()

{

return endDateTime;

}

public void setEndDateTime(Date endDateTime)

{

this.endDateTime = endDateTime;

}

public boolean isActive()

{

return this.auctionStatus.equals(AuctionStatus.ACTIVE.toString());

}

}

@XmlElementWrapper is used to create a list object containing the inner JAXB elements . like in xml bids element contains zero or more bid element , where bid also can be mapped to another JAXB class . By default if you don't specify @XmlElement on every getter method , it map every member field to xml. @XmlTransient is used if we want to skip some fields not to be mapped in xml . Bid class which is mapped to bid element in xml.
package com.model;

import java.util.Date;

import java.util.HashSet;

import java.util.Set;

import javax.xml.bind.annotation.XmlRootElement;

import javax.xml.bind.annotation.XmlTransient;

/**

 * Model class for bid table

 * @author abhishek.somani

 *

 */

@XmlRootElement

public class Bid implements Comparable

{

private int id;

private String user;

private Auction auction;

private double amount;

private Date time;

private Set auctions = new HashSet(0);

public Bid()

{

}

public Bid(Auction auction, String user, double amount, Date time)

{

this.auction = auction;

this.user = user;

this.amount = amount;

this.time = time;

}

public int getId()

{

return id;

}

@XmlTransient

public void setId(int id)

{

this.id = id;

}

public String getUser()

{

return user;

}

public void setUser(String user)

{

this.user = user;

}

public Auction getAuction()

{

return auction;

}

public void setAuction(Auction auction)

{

this.auction = auction;

}

public Double getAmount()

{

return amount;

}

public void setAmount(Double amount)

{

this.amount = amount;

}

public Date getTime()

{

return time;

}

public void setTime(Date time)

{

this.time = time;

}

//compareto method determines which bid is higher

@Override

public int compareTo(Bid o)

{

int compare = 0;

if (this.amount > o.amount)

compare = 1;

else if (this.amount < o.amount)

compare = -1;

else if (this.amount == o.amount)

{

//if amount is same then compare time , bid with more time is smaller 

compare = this.time.compareTo(o.time) >= 0 ? -1 : 1;

}

return compare;

}

public Set getAuctions()

{

return this.auctions;

}

public void setAuctions(Set auctions)

{

this.auctions = auctions;

}

}
Product class which is mapped to product element in xml.
package com.model;

import java.util.HashSet;

import java.util.Set;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement

public class Product

{

private int id;

private String name;

private String details;

private Set auctions = new HashSet(0);

public Product()

{

}

public Product(String name, String details)

{

this.name = name;

this.details = details;

}

public int getId()

{

return id;

}

public void setId(int id)

{

this.id = id;

}

public String getName()

{

return name;

}

public void setName(String name)

{

this.name = name;

}

public String getDetails()

{

return details;

}

public void setDetails(String details)

{

this.details = details;

}

public Set getAuctions()

{

return this.auctions;

}

public void setAuctions(Set auctions)

{

this.auctions = auctions;

}

}


Main class to read and write

 public static void main(String args[]) throws JAXBException

{

new XMLObject().writeXml(null, null);

}

public List readXml(File file) throws JAXBException

{

JAXBContext jaxbContext = JAXBContext.newInstance(XMLObject.class);

Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

XMLObject a = (XMLObject) jaxbUnmarshaller.unmarshal(file);

for (Auction au : a.getAuction())

{

au.setAuctionStatus(AuctionStatus.ACTIVE.name());

au.setEndDateTime(null);

}

return null;

}

public List readXml(InputStream is) throws JAXBException

{

JAXBContext jaxbContext = JAXBContext.newInstance(XMLObject.class);

Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

XMLObject a = (XMLObject) jaxbUnmarshaller.unmarshal(is);

return a.getAuction();

}

public void writeXml(List list,File f) throws JAXBException

{

XMLObject root = new XMLObject();

List auctions = new LinkedList();

Auction a = new Auction();

a.setAuctionType(AuctionType.PUBLIC.toString());

a.setDescription("test");

Set bids = new HashSet();

Bid b = new Bid();

b.setAmount(new Double(233));

b.setTime(new Date());

bids.add(b);

a.setBids(bids);

Product p = new Product();

p.setName("p1");

p.setDetails("details");

a.setProduct(p);

a.setStartDateTime(new Date());

auctions.add(a);

root.setAuction(auctions);

File file = new File("F:/Workspace/testing/wfile.xml");

JAXBContext jaxbContext = JAXBContext.newInstance(XMLObject.class);

Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

// output pretty printed

jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

jaxbMarshaller.marshal(root, file);

jaxbMarshaller.marshal(root, System.out);

}


Common Exception : JAXBException :Class has two properties of the same name To resolve this error , we have to use annotations on getter method rather than field methods