Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

I don't know DWR, but in looking at com.sun.org.apache.xerces.internal.jaxp.datatype.DurationImpl there is no public default constructor and I have see this type of issues with JAXB before in similar situations. In JAXB I use a package-info.java file in the package that contains the object definition that contains in your case duration (in my case java.util.Locale). My object is stored in com.foo.domain.

@XmlJavaTypeAdapter(type = java.util.Locale.class, value=com.foo.util.LocaleXmlAdapter.class)
package com.foo.domain;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

Now my LocaleXmlAdapter.class definition

public class LocaleXmlAdapter extends XmlAdapter<String, Locale> {
    @Override
    public Locale unmarshal(String localeString) throws Exception {
        {insert your impl}
    }

    @Override
    public String marshal(Locale locale) throws Exception {
        {insert your impl}
    }
}

This allows JAXB to solve the lack of a default constructor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top