Friday, February 12, 2010

JAXB 2.0's XmlJavaTypeAdapter

This is coming from Kawaguchi’s blog.

Sometimes when you are binding your own classes to XML, you hit with a situation where your class representation doesn't quite match what you'd like to see in the XML. Some other times, some of your classes hit the limitation in JAXB that the class must have a default constructor. XmlJavaTypeAdapter is a solution for those problems.

The problem happens when you have a code like this:

package com.tickets.common.util;

import java.util.Currency;

class Money {
Currency getCurrency() { ... }
}


Except a few classes that JAXB implementations would recognize out of the box, classes need to have a default no-argument constructor (because otherwise JAXB wouldn't know how to instanciate it.) java.util.Currency doesn't have one, hence the complaint.



To solve this problem, first, you write an 'adapter' class, that extends XmlAdapter. Your code will be converting Currency to something else that JAXB knows how to handle. I think you'd probably want currency to show up in XML as a string, so your adapter will be converting Currency and String. The adapter class would look like this:



public class CurrencyAdapter extends XmlAdapter<String,Currency> {
public Currency unmarshal(String val) throws Exception {
return Currency.getInstance(val);
}
public String marshal(Currency val) throws Exception {
return val.toString();
}
}


You can then put @XmlJavaTypeAdapter on a place where your code references Currency like this:



class Money {
@XmlJavaTypeAdapter(CurrencyAdapter.class)
Currency getCurrency() {...}
}


If you have a lot of properties it becomes tedious to annotate each currency property in this way. If so, you can place this annotation as a package. This you do in package-info.java like this:



@XmlJavaTypeAdapter(value=CurrencyAdapter.class,type=Currency.class)
package com.tickets.common.util;


This tells JAXB that every reference to Currency inside your util package needs to be adapted by the specified adapter.



Finally, if the Currency class is your own class (which is not in this case, but for others who may have a similar situation), you can place this annotation on the class directly:



@XmlJavaTypeAdapter(CurrencyAdapter.class)
class Currency {
...
}


... to indicate that all references to this class be using the adapter. That's the basics of using XmlAdapter.



==========================================================



This also could be used for data conversion. For example, you have <balance>1.01M</balance> in xml, but in the bean, you want it to be converted to 1010000 (a number).

No comments:

Post a Comment