Date
1 - 5 of 5
Is it possible to register global XmlAdapters or at least provide additional "built-in" types in JAXB?
kalgon@...
With JAXB, you can marshal some built-in types like
String or int like this:
which produces the following XML: <result>some string</result> Is it possible to register other built-in types like LocalDate (or other custom ones)? I would like to do the following but it does not work:
This code currently throws: javax.xml.bind.JAXBException: java.time.LocalDate is not known to this context Thanks, Xavier ( hoping somebody actually reads those messages :-) )
|
|
bernhard.wege@...
Hi Xavier,
you need to introduce an adapter and custom bindings for your type. Here is a great example that will map to LocalDate: http://bedtimestoriesforprogrammers.blogspot.de/2015/03/generating-jaxb-classes-with-date-or.html Kind regards Bernhard
|
|
kalgon@...
Here is an example of what I am trying to do (I would like to make the 2 commented lines work): @XmlJavaTypeAdapter(type = LocalDate.class, value = LocalDateXmlAdapter.class) package mypackage; public class Test { public static void main(String... args) throws JAXBException { JAXBContext context = JAXBContext.newInstance(ObjectFactory.class); Marshaller marshaller = context.createMarshaller(); marshaller.marshal(new JAXBElement<>(new QName("Anything"), Integer.class, 42), System.out); // OK marshaller.marshal(new JAXBElement<>(new QName("Whatever"), Date.class, new Date(100, 0, 1)), System.out); // OK // marshaller.marshal(new JAXBElement<>(new QName("YouNameIt"), LocalDate.class, LocalDate.of(2000, 1, 1)), System.out); // Does not work marshaller.marshal(new JAXBElement<>(new QName("LocalDate"), LocalDate.class, LocalDate.of(2000, 1, 1)), System.out); // OK but must always be <LocalDate> (see ObjectFactory) Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.unmarshal(new StreamSource(new StringReader("<Anything>42</Anything>")), Integer.class).getValue(); // OK unmarshaller.unmarshal(new StreamSource(new StringReader("<Whatever>hello world</Whatever>")), String.class).getValue(); // OK // unmarshaller.unmarshal(new StreamSource(new StringReader("<YouNameIt>2000-01-01</YouNameIt>")), LocalDate.class).getValue(); // Does not work ((JAXBElement<?>) unmarshaller.unmarshal(new StringReader("<LocalDate>2000-01-01</LocalDate>"))).getValue(); // OK but must always be <LocalDate> (see ObjectFactory) }
|
|
kalgon@...
Hi Bernard,
Using an XmlAdapter is only possible when marshalling a LocalDate which is contained in a bean (there you can either annotate the property/field or the package with the correct XmlAdapter ).In my case, I want to marshal a LocalDate without any scope/context provided by some outer bean (~ global scope).This is possible for some basic types ( java.util.Date , int , String ...) but there does not seem to be a way to register additional types:marshaller.marshal(new JAXBElement<>(new QName("value"), java.util.Date.class, new java.util.Date(100, 0, 1)), target); // works marshaller.marshal(new JAXBElement<>(new QName("value"), LocalDate.class, LocalDate.of(2000, 1, 1)), target); // does not work I also need to be able to unmarshal the result like this: unmarshaller.unmarshal(new StreamSource(new StringReader("<value>42</value>")), Integer.class); // works unmarshaller.unmarshal(new StreamSource(new StringReader("<value>2001-01-01</value>")), LocalDate.class); // does not work I tried doing the following in the ObjectFactory :@XmlRegistry public class ObjectFactory { @XmlElementDecl(name = "localDate") @XmlJavaTypeAdapter(LocalDateXmlAdapter.class) public JAXBElement<LocalDate> createLocalDate(LocalDate value) { ... } }which allows me to marshal a standalone local date like this (but it needs to be <localDate> and not anything else):marshaller.marshal(new JAXBElement<>(new QName("localDate"), LocalDate.class, LocalDate.of(2000, 1, 1)), target); // gives <localDate>2001-01-01</localDate> But then, it's not possible to unmarshal it: unmarshaller.unmarshal(new StreamSource(new StringReader("<localDate>2001-01-01<localDate>")), LocalDate.class); // error: LocalDate not known in this context For more information, I posted this stackoverflow question: https://stackoverflow.com/questions/48264321/marshalling-directly-non-built-in-value-types-with-jaxb The reason I want to do that is because I am making some framework which stores changes (in XML format) made to an object graph and I would like to treat entities/beans (which are @XmlType ) and value objects (which have a corresponding XmlAdapter ) the same way... and I have a lot of custom value objects (SocialSecurityNumber , VATNumber ...) which I need to be able to store independently.Regards, Xavier
|
|
bernhard.wege@...
Hello Xavier,
I may have misunderstood what you want to do, but as far as I understand all you have to do is provide a scope in your XmlElementDecl. There is an example in the javadocs (https://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlElementDecl.html): @XmlElementDecl(scope=Pea.class,name="foo")
|
|