We had problems using the "conversion" of JMS (from object to JMS message), we find it easier to use an XML to transfer the messages in the JMS queue. The object that I wanted to convert to XML was a value object (immutable no setters) and using static factory. The object is the following:
The implementation of the Castor is pretty simple using Spring 3:
I used the mapping, since I needed to pass three objects to the static factory to create my Redirection object (Authentication, OperatorAndService, and Textmessage). The mapping file was the following:
public final class Redirection {
private RegisteredDate registeredDate;
private Authentication authentication;
private OperatorAndService operatorService;
private TextMessage textMessage;
private Redirection() {}
private Redirection(Authentication authentication,
OperatorAndService operatorService, TextMessage textMessage, Date date) {
this.authentication = authentication;
this.operatorService = operatorService;
this.textMessage = textMessage;
registeredDate = RegisteredDate.get( date!=null?date:new Date());
}
...
public static Redirection get(Authentication authentication,
OperatorAndService operatorService, TextMessage textMessage, Date date) {
return new Redirection(authentication, operatorService, textMessage, date);
}
...
public Authentication getAuthentication() {
return authentication;
}
public OperatorAndService getOperatorAndService() {
return operatorService;
}
public TextMessage getTextMessage() {
return textMessage;
}
public RegisteredDate getRegisteredDate() {
return registeredDate;
}
@Override
public String toString() {
return "Authentication: " + authentication + ", operator service: "
+ operatorService + ", text message: " + textMessage +
", registed date: " + registeredDate;
}
}
The implementation of the Castor is pretty simple using Spring 3:
I used the mapping, since I needed to pass three objects to the static factory to create my Redirection object (Authentication, OperatorAndService, and Textmessage). The mapping file was the following:
Mapping for the redirection object
The "get-method" is exactly what it means, is the method that you will use to fetch the object. The set-method is in case you have any setters (perfect for DTOs). However, my class is immutable so there are no setters. Instead, there is one static method that contains the three parameters that I needed to pass. There is a way to create an object without a constructor "verify-construcable=false". I wanted to see if there is a way to pass all the four object to my static factory, however, this did not work. The creation of the XML worked but not the creation of the object from the XML. I got the following error:
Castor unmarshalling exception; nested exception is org.exolab.castor.xml.MarshalException: unable to find matching public constructor for class
I try to look for a solution, but I had to tweak a lot of things to create a Redirection object. I then decided to look at Groovy's MarkupBuilder.
class XmlService {
private XmlService() {}
public static String getXml(Redirection redirect) {
if(redirect == null) {
throw new IllegalArgumentException("Redirection is invalid or null")
}
Authentication credentials = redirect.getAuthentication()
OperatorAndService operAndServ = redirect.getOperatorAndService()
TextMessage sms = redirect.getTextMessage()
def xml = new groovy.xml.StreamingMarkupBuilder()
xml.encoding = "UTF-8"
def redirection = {
mkp.xmlDeclaration()
redirection() {
authentication() {
username(credentials.getUsername())
password(credentials.getPassword())
}
operatorAndservice() {
serviceId(operAndServ.getServiceId())
operatorId(operAndServ.getOperatorId())
}
textmessage(){
phone(sms.getPhone())
shortcode(sms.getShortcode())
message(sms.getMessage())
}
registerdate(date:redirect.getRegisteredDate())
}
}
return xml.bind(redirection);
}
public static Redirection toRedirection(String xml) {
if(Validation.isEmpty(xml)) {
throw new IllegalArgumentException("The application needs to have an xml")
}
def redirectionXml = new XmlParser().parseText(xml)
//Authentication
String username = redirectionXml.authentication.username.text()
String password = redirectionXml.authentication.password.text()
def authentication = Authentication.get(username, password)
//Operator and service
String serviceId = redirectionXml.operatorAndservice.serviceId.text()
String operatorId = redirectionXml.operatorAndservice.operatorId.text()
def operatorAndService = OperatorAndService.get(operatorId, serviceId)
//Text message
String phone = redirectionXml.textmessage.phone.text()
String shortcode = redirectionXml.textmessage.shortcode.text()
String message = redirectionXml.textmessage.message.text()
def textMessage = TextMessage.get(phone, shortcode, message)
String registerDate = redirectionXml.registerdate[0].'@date'
def registeredDate = RegisteredDate.get(registerDate)
return Redirection.get(authentication,
operatorAndService, textMessage,
registeredDate.getRegisteredDate());
}
}
Groovy is a better candidate for this application. Its simplicity and flexibility beats Castor. The only thing that concerned me is the performance. I did noticed that the test cases using Castor were much faster. In case that performance is an issue, consider using Castor or other type of XML marshaling. I heard from one of my coworkers that xstream is very fast.
Marcelo, I was just about to do this comparison myself. You beat me by a year, and I will take your advice. I am a bit concern about performance. I will let you know.
ReplyDeleteJorgito, I'm glad...sorry, I just catching up with the blog.
Delete