13

Is there a way to change the default way jaxb serialize/deserialize types, dates in my case, without specifying it through annotation and/or through xml jaxb binding as mentioned here http://jaxb.java.net/guide/Using_different_datatypes.html

I'd basically like to do something like:

    JAXBContext jaxbContext = ...;
    Marshaller marshaller = jaxbContext.createMarshaller().setAdapter(new DateAdapter(dateFormat));

To have a preconfigured JaxBContext or Marshaller/Unmarshaller that serialize/deserialize dates in a customized way..

Couldn't find any resource that shows how to do expect through annotations or statically with the xml binding file.. Thanks!

zhk
  • 161
  • 1
  • 1
  • 5
  • does `javax.xml.bind.Marshaller.setAdapter(XmlAdapter)` not work for you? – lexicore Jun 17 '11 at 06:34
  • 1
    @lexicore - `javax.xml.bind.Marshaller.setAdapter(XmlAdapter)` is for passing in an initialized `XmlAdapter` when the model is already configured to use an `XmlAdapter` and not to introduce an `XmlAdapter`. For an example see: http://stackoverflow.com/questions/5319024/using-jaxb-to-cross-reference-xmlids-from-two-xml-files/5327425#5327425 – bdoughan Jun 28 '11 at 16:02
  • The fact that the `@XmlJavaTypeAdapter(s)` annotations are unavoidable are a big pain for frameworks. For XStream, we can register a converter to apply to all Foo fields, but for jaxb we can't because it expects us to change the user's domain package-info.java file... – Geoffrey De Smet Jun 22 '16 at 13:11

3 Answers3

14

This isn't exactly what you're looking for but it beats annotating every Date field individually. You can set a XmlJavaTypeAdapter at the package level so that every reference to Date within your package will use it. If your objects are in the com.example package, you should add a package-info.java file to it with the following contents:

@XmlJavaTypeAdapter(value=MyCustomDateAdapter.class,type=Date.class)
package com.example;
Patrick Marchwiak
  • 1,072
  • 2
  • 11
  • 24
8

Try this:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement(name = "event")
public class Event {

    private Date date;
    private String description;

    @XmlJavaTypeAdapter(DateFormatterAdapter.class)
    public Date getDate() {
        return date;
    }

    public void setDate(final Date date) {
        this.date = date;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(final String description) {
        this.description = description;
    }

    private static class DateFormatterAdapter extends XmlAdapter<String, Date> {
        private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd_mm_yyyy");

        @Override
        public Date unmarshal(final String v) throws Exception {
            return dateFormat.parse(v);
        }

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

    public static void main(final String[] args) throws Exception {
        final JAXBContext context = JAXBContext.newInstance(Event.class);
        final Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        final Event event = new Event();
        event.setDate(new Date());
        event.setDescription("im rick james");

        marshaller.marshal(event, System.out);
    }
}

This produces:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<event>
    <date>16_05_2011</date>
    <description>im rick james</description>
</event>
chahuistle
  • 2,627
  • 22
  • 30
  • 3
    That's not what I'm looking for, your Event object has already an annotation that specifies how to serialize the date (@XmlJavaTypeAdapter). What I need is a pre-configured jaxb (un)marshaller that already knows how to (de)serialize some types without the need to pre-annotate the objects passed to it.. – zhk Jun 16 '11 at 21:51
  • 5
    Be aware, that the SimpleDateFormat "dd_mm_yyyy" will display days, MINUTES and years. Probably "dd_MM_yyyy" is the better choice. – slartidan Dec 12 '13 at 17:25
  • Is it possible to do the marshal with validation ? – Aguid Oct 10 '17 at 13:12
0

After searching whole jaxb documentation and many tutorials, I did not find any answer that can configure dates apart from what we hard code in XMLAdapter. I put a property file in classpath having date formats as for example: dateFormat=mm-dd-YYYY

Now your XMLAdapter implementation goes as below:

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ConfigurableAdapterForDate extends XmlAdapter<String, Date>{

    private static final String FORMAT = "yyyy-mm-dd";
    private String formatFromFile =  null;
    private SimpleDateFormat format = new SimpleDateFormat();

    private void setFormatFromFile() throws IOException {
        //load property file
        Properties prop = new Properties();
        InputStream is = this.getClass().getResourceAsStream("<path to your property file>");
        prop.load(is);

        //get the format from loaded property file
        formatFromFile = prop.getPropertyValue("dateFormat");

        if(formatFromFile != null) {
            format.applyPattern(formatFromFile);
        }
        else {
            format.applyPattern(FORMAT );
        }
    }

    @Override
    public Date unmarshal(String v) throws Exception {
        this.setFormatFromFile();
        return format.parse(v);
    }

    @Override
    public String marshal(Date v) throws Exception {
        this.setFormatFromFile();
        return format.format(v);
    }

}

Now you can use @XmlJavaTypeAdapter(ConfigurableAdapterForDate.class)for date objects which you want to serialize/deserialize. One is free to use spring also to load property file. Above code will configure your date accordingly.

  • The validation of the attribute will be failed because it is declared as String like following [ The date of the export ] . – Aguid Oct 10 '17 at 13:22