0

I have to communicate with Web Service which WSDL contains the following complexType:

    <complexType name="KlarigoField">
        <complexContent>
          <sequence>
             <element name="Value" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
             <element name="Metadata" type="{http://klarigo.ru/main}KlarigoFieldMetadata" minOccurs="0"/>
           </sequence>
        </complexContent>
   </complexType>

According with this part, JAXB generates the following class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "KlarigoField", propOrder = {
    "value",
    "metadata"
})
public class KlarigoField {

    @XmlElement(name = "Value", nillable = true)
    protected Object value;
    @XmlElement(name = "Metadata", nillable = true)
    protected KlarigoFieldMetadata metadata;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    public KlarigoFieldMetadata getMetadata() {
        return metadata;
    }

    public void setMetadata(KlarigoFieldMetadata value) {
        this.metadata = value;
    }

}

During one operation I have to assign java.util.Date value to the "Value" element where I get the following output:

<Value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:dateTime">
2017-01-25T00:00:00+03:00
</Value>

But I need to get a value of type "xs:date", something like that:

<Value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:date">
2017-01-25
</Value>

JAXB marshalls java.util.Date into xs:dateTime by default. I have read that we can create a custom adapter which marshalls java.util.Date into xs:date like answered here. The problem is that we can apply this adapter only to java.util.Date fields, not to java.lang.Object (xs:anyType), moreover this field is supposed to be container for values of different types. What can I do to solve my issue?


UPDATE: I have managed to get needed result through creating a custom "date" type which wraps java.util.Date:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "date", namespace = "http://www.w3.org/2001/XMLSchema", propOrder = {
        "value"
    })
    public class Date {

        @XmlValue
        @XmlJavaTypeAdapter(DateAdapter.class)
        @XmlSchemaType(name = "date")
        protected java.util.Date value;

        public java.util.Date getValue() {
            return value;
        }

        public void setValue(java.util.Date value) {
            this.value = value;
        }

    }

Date adapter:

public class DateAdapter extends XmlAdapter<String, Date> {

        private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public Date unmarshal(String stringDate) throws Exception {
            return DatatypeConverter.parseDate(stringDate).getTime();
        }

        @Override
        public String marshal(Date date) throws Exception {
            synchronized (dateFormat) {
                return dateFormat.format(date);
            }
        }
    }

I create object of my custom type, set a real java.util.Date object there and finally set it into "Object value" field:

my.custom.Date customDate = new my.custom.Date();
customDate.setValue(new java.util.Date(....));
klarigoField.setValue(customDate);

Finally, I added my custom Date type to WSDL for automatic generation:

<schema targetNamespace="http://www.w3.org/2001/XMLSchema">
    <complexType name="date">
        <simpleContent>
             <extension base="xs:date"/>
        <simpleContent>
    <complexType>
<schema>
Community
  • 1
  • 1

1 Answers1

1

Yes, you get the right direction, you need a XmlAdapter:

class DateAdapter extends XmlAdapter<String, Object> {

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public String marshal(Object v) throws Exception {
        if (v.getClass() == Date.class) {
            synchronized (dateFormat) {
                return dateFormat.format(v);
            }
        }
        return v.toString();
    }
    // ...    
}

And as long as all your different types override toString correctly, you can marshal easily.

More:

Tony
  • 5,972
  • 2
  • 39
  • 58
  • Thanks for answer! I have already tried to use this adapter and applied it to "Object value" field. The problem was that the output was without needed type i.e xsi:type="xs:date". Also, I was not able to correctly realize the overrided unmarshal method. – Rafael Irgalin Jan 26 '17 at 11:58
  • @RafaelIrgalin I am glad you find answer :). Sorry not help you out. – Tony Jan 26 '17 at 14:05
  • Oh, no problem, thank you! Your answer will be helpful for others ;) – Rafael Irgalin Jan 26 '17 at 14:15