SimpleDataFormat.format() spuckt falsches Jahr aus (statt 1999 = 3899)

Hag2bard

Bekanntes Mitglied
Hallo,

ich bin gerade dabei etwas über JAXB (XML Binding) zu lernen und habe bisher folgendes Beispiel aufgebaut:

Duke.java

In dieser Klasse habe ich an dem Feld publishingDate eine Annotation gesetzt, welche mir mit Hilfe eines DateAdapters das Datum in ein lesbares Format umwandelt.
Java:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Date;

@XmlRootElement                         //Markiert Java Klasse als Root Element
@XmlAccessorType(XmlAccessType.FIELD)   //Stellt AccessorType auf Felder der Klasse (XML-Datenbindung)
public class Duke {
    @XmlElement(name = "Sprache")
    private String language;                //Feld für Serialisierung
    @XmlElement(name = "Erscheinungsdatum")
    @XmlJavaTypeAdapter(DateAdapter_yyyyMMdd.class)
    private Date publishingDate;             //Feld für Serialisierung
    @XmlElement(name = "Objektorientiert")
    private ObjectOriented objectOriented;  //Feld für Serialisierung

    public Duke() {                         //Standard-Konstruktor
    }

    public Duke(String language, Date publishingDate, ObjectOriented objectOriented) {     //Konstruktor
        this.language = language;
        this.publishingDate = publishingDate;
        this.objectOriented = objectOriented;
    }

    @Override
    public String toString() {          //Überschriebene toString Methode für die Testmethode des Parsens
        return "Duke{" + "Sprache=" + language + ", Erscheinungsjahr=" + publishingDate + ", Objektorientiert=" + objectOriented + '}';
    }


    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public Date getPublishingDate() {
        return publishingDate;
    }

    public void setPublishingDate(Date publishingDate) {
        this.publishingDate = publishingDate;
    }

    public ObjectOriented isObjectOriented() {
        return objectOriented;
    }

    public void setObjectOriented(ObjectOriented objectOriented) {
        this.objectOriented = objectOriented;
    }
}


DateAdapter_yyyyMMdd.java
Hier setze ich in der Marshal-Methode nochmal Testweise das Jahr auf 1990.
Java:
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateAdapter_yyyyMMdd extends XmlAdapter<String, Date> {
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd");

    public DateAdapter_yyyyMMdd() {
    }

    @Override
    public String marshal(Date date) {
        date.setYear(1990);
        return this.dateFormat.format(date);
    }

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


}


Und meine TestKlasse DukeTest.java
Java:
import org.junit.Before;
import org.junit.Test;

import javax.xml.bind.*;
import java.io.File;
import java.util.Calendar;
import java.util.Date;

public class DukeTest {
    private JAXBContext context;

    /**
     * Die mit @Before annotierte Methode init() initialisiert ein JAXBContext anhand der übergebenen Instance der Duke-Klasse.
     *
     * @throws JAXBException
     */
    @Before
    public void init() throws JAXBException {
        this.context = JAXBContext.newInstance(Duke.class);
    }

    /**
     * Die Serialization Methode erstellt ein neues Marshaller-Objekt aus dem JAXBContext der Duke Klasse.
     * Anschließend wird die marshall()-Methode aufgerufen, welche als Parameter ein Duke-Objekt sowie ein File Objekt übergeben bekommt.
     *
     * @throws JAXBException
     */
    @Test
    public void serialization() throws JAXBException {
        Marshaller marshaller = this.context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);                    //Formatierter Output der xml Datei
        marshaller.marshal(new Duke("C++", new Date(1990, Calendar.DECEMBER, 31), ObjectOriented.Ja), new File("duke.xml"));
    }

    /**
     * Die Parsing Methode erstellt ein neues Unmarshaller-Objekt aus dem JAXBContext der Duke Klasse.
     * Anschließend wird ein Java-Object deklariert, welches durch die unmarshal()-Methode initialisiert wird.
     * Zum Schluss wird mit einem einfachen sysout das Java Objekt ausgegeben. (toString()-Methode)
     *
     * @throws JAXBException
     */
    @Test
    public void parsing() throws JAXBException {
        Unmarshaller unmarshaller = this.context.createUnmarshaller();
        Object unmarshalled = unmarshaller.unmarshal(new File("duke.xml"));
        System.out.println("unmarshalled = " + unmarshalled);
        Duke duke = (Duke) unmarshalled;
        System.out.println("Programmiersprache: " + duke.getLanguage());
        System.out.println("ist Objektorientiert: " + duke.isObjectOriented());
        System.out.println("Erscheinungsjahr: " + duke.getPublishingDate().getYear());
    }
}


Dabei kommt aber in der XML folgendes bei raus:

Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<duke>
    <Sprache>C++</Sprache>
    <Erscheinungsdatum>3899_12_31</Erscheinungsdatum>
    <Objektorientiert>Ja</Objektorientiert>
</duke>

Kann mir jemand erklären, wieso das der Fall ist?
Bitte kein Hinweis bezüglich dessen, dass ich deprecated-Sachen benutze, darum geht es mir zumindest im Moment noch nicht.

Danke im Voraus
 
Zuletzt bearbeitet:
Also muss ich das in meiner unmarshal Methode mit berücksichtigen, so wie ich es in der Marshal Methode berücksichtigt habe?
Java:
    @Override
    public String marshal(Date date) {
        date.setYear(date.getYear()-1900);
        return this.dateFormat.format(date);
    }

Ich verstehe den Sinn nicht, wieso das +1900 gerechnet wird.
 
Neun, wenn du das alte Date API nutzen willst, dann musst du es entsprechend der Dokumentation nutzen. Und das Jahr wird immer mit -1900 angegeben. Wenn du also das Jahr 1990 haben willst, dann musst du Date ein 90 übergeben.

Bezüglich deprecated Methoden wolltest du aber nichts hören … also wenn du mir Sch…. spielen willst, dann wunder Dich nicht, wenn du entsprechend stinkst.
 
Neun, wenn du das alte Date API nutzen willst, dann musst du es entsprechend der Dokumentation nutzen. Und das Jahr wird immer mit -1900 angegeben. Wenn du also das Jahr 1990 haben willst, dann musst du Date ein 90 übergeben.

Bezüglich deprecated Methoden wolltest du aber nichts hören … also wenn du mir Sch…. spielen willst, dann wunder Dich nicht, wenn du entsprechend stinkst.
Guter Spruch 😀, leider bin ich darauf angewiesen mit der Sch... von anderen zu spielen. Ich muss anhand eines existierenden Beispiels JAXB erläutern und habe gerade dank dir entdeckt, dass dieser Fallstrick in dem Code nicht berücksichtigt wird 😀
 
Guter Spruch 😀, leider bin ich darauf angewiesen mit der Sch... von anderen zu spielen. Ich muss anhand eines existierenden Beispiels JAXB erläutern und habe gerade dank dir entdeckt, dass dieser Fallstrick in dem Code nicht berücksichtigt wird 😀
Sehr gerne. Das Problem ist halt, dass die alte date/time API viele Probleme oder Fallstricke hatte. Teilweise wurden dann Teile deprecated gemacht (so wie bei setDate und den verwendeten Konstruktoren) um da erst einmal die gröbsten Schnitzer (so nenne ich die einfach einmal) zu deaktivieren. Aber durch die neue API wurde das Problem dann letztendlich gelöst. Und ab Java 8 steht die zur Verfügung und man sollte versuchen, darauf zu wechseln, wenn irgendwie möglich. Siehe dazu z.B. einmal https://www.baeldung.com/java-8-date-time-intro.

Aber wenn man da noch gezwungen sein sollte, die alte API zu nutzen, dann ist das leider nur ein Ausblick, wo man evtl. irgendwann mal hin kommen könnte. Oder um bei den Visuellen Vergleichen zu bleiben: Wenn die Firma nun einmal "Wasser, Gas, Sch...." macht (frei nach Werner), dann gehört das halt mit zum Job 🙂
 
Ich weiß, der Post ist schon etwas älter uind das hier trägt zu keiner Lösung bei, wollte nur noch anmerken, dass der OP nicht der einzige ist, der damit Probleme hat:
cleo.jpg
 

Zurück
Oben