Thursday 28 February 2013

@XmlSeeAlso

This is quite simple but very handy.

I am working with an XML structure that doesn't lend itself particularly well to being implemented in JAXB. The XML has a common outer element but the content varies by message type. There is no XSD for the XML but a reference document that (roughly) describes the schema.

I modeled this as

@XmlRootElement(name="apimessage")
class Message
{
...
    @XmlAnyElement(lax=true)
    public MessageBody getBody()
   ...
}

interface MessageBody
{
}

Then I have sub-classes of MessageBody like this:

@XmlRootElement(name="bodya")
class BodyA implements MessageBody
{
}

I hit the first problem while testing which was that when decoding a message the decoder knew nothing about the body so you end up with errors like 


java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to com.xxx.MessageBody

I got around this by passing the sub-class types as parameters to the JAXBContext when I was initializing it.

Now this wasn't the end of my problems as these messages get passed over a web interface.. The error in that case was:

[com.sun.istack.SAXException2: class com.xxx.BodyA nor any of its super class is known to this context.

The solution is actually quite simple (although not very extensible) and that is you use the @XmlSeeAlso attribute to tell JAXB to register the sub-classes of MessageBody when the Message class is registered:


@XmlRootElement(name="apimessage")
@XmlSeeAlso({BodyA.class,BodyB.class})

class Message
{
...

And then it just works...

Thursday 21 February 2013

Spring Fakes

Ok this isn't rocket science but as it stumped me for a little while I thought I would share.

Essentially what I am trying to do is to replace a real interface with a fake so I can integrate the parts of my application without having the real implementation of the interface.

Specifically I am implementing a protocol for registering certificates but I don't have the implementation of the configuration yet. The interface is there but the implementation is ropey at best and the GUI for putting the configuration in the DB is a while off.

So I created a fake that hard-codes a configuration. The trick is how to wire this in without removing the real implementation jar (as the interface lives in there).

In Spring the XML configuration trumps the annotations. Most of the application uses the @Component and @Autowired annotations to tie it all together. I figured if I declared a bean in the XML it would override the real one.

Well yes but no. For some cases it seemed to work (that is some cases didn't throw errors) but in other cases it did. The trick it turns out is that even though auto-wiring is configured to be type based, the replacement is name based.

Basically to get it to work I had to make sure that the name of the config interface instance was always consistent and matched the bean ID in the XML. Then Spring would happily use the specified instance instead of getting confused over having multiple implementations.