Datums ongedaan maken met JAXB

1. Inleiding

In deze tutorial we gaan zien hoe we datumobjecten met verschillende formaten kunnen unmarshal met behulp van JAXB.

Eerst behandelen we de standaard datumnotatie van het schema. Vervolgens onderzoeken we hoe u verschillende indelingen kunt gebruiken. We zullen ook zien hoe we kunnen omgaan met een veelvoorkomende uitdaging die zich bij deze technieken voordoet.

2. Schema naar Java-binding

Eerste, we moeten de relatie tussen de gegevenstypen XML-schema en Java begrijpen. We zijn in het bijzonder geïnteresseerd in de koppeling tussen een XML-schema en Java-datumobjecten.

Volgens de Schema naar Java-mapping, zijn er drie schemagegevenstypen waarmee we rekening moeten houden: xsd: datum, xsd: tijd en xsd: dateTime. Zoals we kunnen zien, zijn ze allemaal in kaart gebracht javax.xml.datatype.XMLGregorianCalendar.

We moeten ook de standaardindelingen voor deze XML-schematypes begrijpen. De xsd: datum en xsd: tijd gegevenstypen hebben 'JJJJ-MM-DD ' en "uu: mm: ss ' formaten. De xsd: dateTime formaat is 'JJJJ-MM-DDTuu: mm: ss " waar 'T " is een scheidingsteken dat het begin van het tijdgedeelte aangeeft.

3. De standaard datumnotatie van het schema gebruiken

We gaan een voorbeeld bouwen dat dateringsobjecten unmarshals. Laten we ons concentreren op de xsd: dateTime gegevenstype omdat het een superset is van de andere typen.

Laten we een eenvoudig XML-bestand gebruiken dat een boek beschrijft:

 Boek1 1979-10-21T03: 31: 12 

We willen het bestand toewijzen aan de overeenkomstige Java Boek voorwerp:

@XmlRootElement (naam = "boek") openbare klasse Boek {@XmlElement (naam = "titel", vereist = true) privé String-titel; @XmlElement (naam = "gepubliceerd", vereist = waar) privé XMLGregorianCalendar gepubliceerd; @Override public String toString () {return "[title:" + title + "; gepubliceerd:" + gepubliceerd.toString () + "]"; }}

Ten slotte moeten we een clienttoepassing maken die de XML-gegevens converteert naar JAXB-afgeleide Java-objecten:

openbare statische Book unmarshalDates (InputStream inputFile) gooit JAXBException {JAXBContext jaxbContext = JAXBContext.newInstance (Book.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller (); return (Boek) jaxbUnmarshaller.unmarshal (inputFile); }

In de bovenstaande code hebben we een JAXBContext dat is het toegangspunt tot de JAXB API. Vervolgens hebben we een JAXB gebruikt Unmarshaller op een invoerstroom om ons object te lezen:

Als we de bovenstaande code uitvoeren en het resultaat afdrukken, krijgen we het volgende Boek voorwerp:

[titel: Boek1; gepubliceerd: 1979-11-28T02: 31: 32]

We moeten er rekening mee houden dat, ook al is de standaardtoewijzing voor xsd: dateTime is de XMLGregorianCalendar, hadden we ook de meer gebruikelijke Java-typen kunnen gebruiken: java.util.Date en java.util.Calendar, volgens de JAXB-gebruikershandleiding.

4. Een aangepaste datumnotatie gebruiken

Het bovenstaande voorbeeld werkt omdat we de standaard datumnotatie van het schema gebruiken, "JJJJ-MM-DDTuu: mm: ss".

Maar wat als we een ander formaat willen gebruiken, zoals "JJJJ-MM-DD uu: mm: ss", het verwijderen van de "T" scheidingsteken? Als we het scheidingsteken zouden vervangen door een spatie in ons XML-bestand, zou de standaard unmarshalling mislukken.

4.1. Bouwen aan een Custom XmlAdapter

Om een ​​andere datumnotatie te gebruiken, moeten we een XmlAdapter.

Laten we ook kijken hoe we het xsd: dateTime typ naar een java.util.Date object met onze gewoonte XmlAdapter:

openbare klasse DateAdapter breidt XmlAdapter uit {privé statische laatste String CUSTOM_FORMAT_STRING = "jjjj-MM-dd HH: mm: ss"; @Override public String marshal (Datum v) {retourneer nieuwe SimpleDateFormat (CUSTOM_FORMAT_STRING) .format (v); } @Override public Date unmarshal (String v) gooit ParseException {retourneer nieuwe SimpleDateFormat (CUSTOM_FORMAT_STRING) .parse (v); }}

In deze adapter we hebben gebruiktSimpleDateFormat om onze datum op te maken. We moeten zo voorzichtig zijn de SimpleDateFormat is niet draadveilig. Om te voorkomen dat meerdere threads problemen ondervinden met een gedeeld SimpleDateFormat object, creëren we elke keer dat we het nodig hebben een nieuwe.

4.2. De XmlAdapter‘S Internals

Zoals we kunnen zien, is de XmlAdapter heeft twee typeparameters, in dit geval, Draad en Datum. De eerste is het type dat in de XML wordt gebruikt en wordt het waardetype genoemd. In dit geval weet JAXB hoe een XML-waarde moet worden geconverteerd naar een Draad. De tweede heet het gebonden type en heeft betrekking op de waarde in ons Java-object.

Het doel van een adapter is om te converteren tussen het waardetype en een gebonden type, op een manier die JAXB niet standaard kan doen.

Om een ​​gewoonte te bouwen XmlAdapter, we moeten twee methoden overschrijven: XmlAdapter.marshal () en XmlAdapter.unmarshal ().

Tijdens unmarshalling ontkoppelt het JAXB-bindende framework eerst de XML-representatie naar een Draad en roept vervolgens aan DateAdapter.unmarshal () om het waardetype aan te passen aan a Datum. Tijdens het rangschikken roept het bindende raamwerk van JAXB een beroep op DateAdapter.marshal () om een Datum naar Draad, die vervolgens wordt gemarshaald naar een XML-weergave.

4.3. Integreren via de JAXB-annotaties

De DatumAdapter werkt als een plug-in voor JAXB en we gaan het aan ons datumveld koppelen met behulp van de @XmlJavaTypeAdapter annotatie. De @XmlJavaTypeAdapter annotatie specificeert het gebruik van een XmlAdapter voor aangepaste unmarshalling:

@XmlRootElement (naam = "boek") openbare klasse BookDateAdapter {// hetzelfde als voorheen @XmlElement (naam = "gepubliceerd", vereist = waar) @XmlJavaTypeAdapter (DateAdapter.class) privé Publicatiedatum; // hetzelfde als voorheen }

We gebruiken ook de standaard JAXB-annotaties: @XmlRootElement en @XmlElement annotaties.

Laten we tot slot de nieuwe code uitvoeren:

[titel: Boek1; gepubliceerd: wo 28 november 02:31:32 EET 1979]

5. Niet-markeren van datums in Java 8

Java 8 introduceerde een nieuw Datum Tijd API. Hier gaan we ons concentreren op de LocalDateTime klasse die een van de meest gebruikte is.

5.1. Een .... bouwen LocalDateTime-gebaseerd XmlAdapter

Standaard, JAXB kan niet automatisch een xsd: dateTime waarde voor een LocalDateTime object ongeacht de datumnotatie. Om een ​​XML-schema-datumwaarde naar of van een LocalDateTime object, we moeten een ander definiëren XmlAdapter vergelijkbaar met de vorige:

openbare klasse LocalDateTimeAdapter breidt XmlAdapter uit {privé DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern ("jjjj-MM-dd HH: mm: ss"); @Override public String marshal (LocalDateTime dateTime) {return dateTime.format (dateFormat); } @Override public LocalDateTime unmarshal (String dateTime) {return LocalDateTime.parse (dateTime, dateFormat); }}

In dit geval, we hebben een DateTimeFormatter inplaats van een SimpleDateFormat. De eerste is geïntroduceerd in Java 8 en is compatibel met de nieuwe Datum Tijd API.

Merk op dat de conversiebewerkingen een DateTimeFormatter object omdat de DateTimeFormatter is draadveilig.

5.2. Integratie van de nieuwe adapter

Laten we nu de oude adapter vervangen door de nieuwe in onze Boek klasse en ook Datum met LocalDateTime:

@XmlRootElement (naam = "boek") openbare klasse BookLocalDateTimeAdapter {// hetzelfde als voorheen @XmlElement (naam = "gepubliceerd", vereist = waar) @XmlJavaTypeAdapter (LocalDateTimeAdapter.class) privé LocalDateTime gepubliceerd; // hetzelfde als voorheen }

Als we de bovenstaande code uitvoeren, krijgen we de uitvoer:

[titel: Boek1; gepubliceerd: 1979-11-28T02: 31: 32]

Merk op dat de LocalDateTime.toString () voegt de "T" scheidingsteken tussen datum en tijd.

6. Conclusie

In deze tutorial hebben we onderzocht het niet-markeren van datums met behulp van JAXB.

Eerst hebben we gekeken naar de toewijzing van XML-schema's naar Java-gegevenstypen en hebben we een voorbeeld gemaakt met de standaard datumnotatie XML-schema.

Vervolgens hebben we geleerd hoe we een aangepaste datumnotatie kunnen gebruiken op basis van een aangepaste XmlAdapter en zag hoe om te gaan met de draadveiligheid van SimpleDateFormat.

Ten slotte hebben we gebruikgemaakt van de superieure, thread-veilige, Java 8 Datum / tijd-API en niet-gemarshallerde datums met aangepaste indelingen.

Zoals altijd is de broncode die in de tutorial wordt gebruikt, beschikbaar op GitHub.