I've been given a pretty complex stack of generated classes and need to send it between the server and the client using DWR. One of the classes uses a jax.xml.datatype.Duration. Here is the Java code where I create a bean with test data using the duration:
DatatypeFactory df = DatatypeFactory.newInstance();
Duration duration = df.newDuration(RANDOM.nextLong());
testObject.setDuration(duration);
DWR doesn't like that duration in the object:
ERROR [org.directwebremoting.dwrp.DefaultConverterManager] - No converter found for 'com.sun.org.apache.xerces.internal.jaxp.datatype.DurationImpl'
and occasionally I see the same message (I think it was when I was going from JavaScript back to Java) for the class com.sun.org.apache.xerces.internal.jaxp.datatype.DurationImpl
Defining a regular converter doesn't help:
<dwr:convert type="bean" match="com.sun.org.apache.xerces.internal.jaxp.datatype.DurationImpl"/>
<dwr:convert type="bean" match="javax.xml.datatype.Duration"/>
I'm sure the above doesn't work because they're not really beans. But I'm at a loss as to how to get it to work. I've read in several places that you can define a custom converter, but the details seem very vague and in most cases out dated. The DWR website says there's a link that explains it all, but it just links you to the javadoc which doesn't help me with the actual implementation.
Can anybody help me figure out how to handle a duration?
I couldn't find one place that provided the answer, so I had to piece bits of information together from different places -- the spring-dwr schema, examples of classes that extend the provided, etc.
For starters, this was the proper way to configure spring.xml:
<dwr:configuration>
<dwr:init>
<dwr:converter id="durationConverter" class="com.foo.DurationConverter"/>
</dwr:init>
<dwr:convert class="com.sun.org.apache.xerces.internal.jaxp.datatype.DurationImpl" type="durationConverter"/>
<dwr:convert class="javax.xml.datatype.Duration" type="durationConverter"/>
...
</dwr:configuration>
I'm not really sure if I needed both the DurationImpl and the Duration convert declarations, but I've seen messages for both of them, so I put them both in.
Here was how I built my converter:
public class DurationConverter extends BeanConverter {
@Override
public Duration convertInbound(Class<?> type, InboundVariable iv, InboundContext ic) throws MarshallException {
String value = iv.getValue();
// If the text is null then the whole bean is null
if (value == null) {
return null;
}
Duration duration = null;
try {
DatatypeFactory df = DatatypeFactory.newInstance();
duration = df.newDuration(Long.valueOf(value));
} catch (DatatypeConfigurationException ex) {
Logger.getLogger(DurationConverter.class.getName()).log(Level.SEVERE, null, ex);
}
return duration;
}
@Override
public OutboundVariable convertOutbound(Object o, OutboundContext oc) throws MarshallException {
Duration duration = (Duration) o;
String varname = oc.getNextVariableName();
Map<String, OutboundVariable> ovs = new TreeMap<>();
OutboundVariable durationOV = getConverterManager().convertOutbound(duration.getSeconds(), oc);
ovs.put("duration", durationOV);
ObjectJsonOutboundVariable oj = new ObjectJsonOutboundVariable();
oj.setChildren(ovs);
return oj;
}
}
Hope this helps somebody else struggling with the same thing.