Java.util.Date ve XMLGregorianCalendar arasında basit dönüşüm


110

Her iki yönde java.util.Date ve javax.xml.datatype.XMLGregorianCalendar arasında dönüştürme yapmak için basit bir yöntem arıyorum.

İşte şimdi kullandığım kod :

import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * Utility class for converting between XMLGregorianCalendar and java.util.Date
 */
public class XMLGregorianCalendarConverter {  

    /**
     * Needed to create XMLGregorianCalendar instances
     */
    private static DatatypeFactory df = null;
    static {
        try {
            df = DatatypeFactory.newInstance();
        } catch (DatatypeConfigurationException dce) {
            throw new IllegalStateException(
                "Exception while obtaining DatatypeFactory instance", dce);
        }
    }  

    /**
     * Converts a java.util.Date into an instance of XMLGregorianCalendar
     *
     * @param date Instance of java.util.Date or a null reference
     * @return XMLGregorianCalendar instance whose value is based upon the
     *  value in the date parameter. If the date parameter is null then
     *  this method will simply return null.
     */
    public static XMLGregorianCalendar asXMLGregorianCalendar(java.util.Date date) {
        if (date == null) {
            return null;
        } else {
            GregorianCalendar gc = new GregorianCalendar();
            gc.setTimeInMillis(date.getTime());
            return df.newXMLGregorianCalendar(gc);
        }
    }

    /**
     * Converts an XMLGregorianCalendar to an instance of java.util.Date
     *
     * @param xgc Instance of XMLGregorianCalendar or a null reference
     * @return java.util.Date instance whose value is based upon the
     *  value in the xgc parameter. If the xgc parameter is null then
     *  this method will simply return null.
     */
    public static java.util.Date asDate(XMLGregorianCalendar xgc) {
        if (xgc == null) {
            return null;
        } else {
            return xgc.toGregorianCalendar().getTime();
        }
    }
}

Gözden kaçırdığım bazı API çağrıları gibi daha basit bir şey var mı?

Standart bir XML tarih / saati ile bir Java tarih nesnesi arasında dönüşüm yapmak oldukça rutin bir görev gibi görünüyor ve bu kodu yazmam gerektiğine şaşırdım.

Baska öneri?

NOTLAR: JAXB sınıflarım bir şemadan otomatik olarak oluşturuldu. Projemdeki derleme süreci, oluşturulan sınıflarda manuel değişiklikler yapmama izin vermiyor. Xs: dateTime öğeleri, JAXB sınıflarında XMLGregorianCalendar olarak XJC tarafından üretiliyor. Şema periyodik olarak genişletilir ve değiştirilir, bu nedenle şema XSD dosyasında sınırlı değişiklikler yapmama izin verilir.

ÇÖZÜM ÜZERİNDE GÜNCELLEME: Blaise tarafından önerilen çözüm, XMLGregorianCalendar'ı karışımdan çıkarmama ve bunun yerine java.util.Calendar nesneleriyle ilgilenmeme izin verdi. Şema dosyamın üstüne bir JAXB bağlama cümlesi ekleyerek, XJC, JAXB sınıflarımdaki xs: dateTime için daha uygun eşlemeler oluşturabilir. XSD dosyamdaki değişiklikleri gösteren bazı parçacıklar.

XSD dosyasındaki kök öğe:

<xs:schema xmlns:mydata="http://my.example.com/mydata" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" targetNamespace="http://my.example.com/mydata" elementFormDefault="unqualified" attributeFormDefault="unqualified" version="0.2" xml:lang="en" jaxb:version="2.0">

XSD'de kök öğeden hemen sonra eklenen JAXB bağlama ek açıklama bloğu:

<xs:annotation>
    <xs:appinfo>
        <jaxb:globalBindings>
            <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime" parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
        </jaxb:globalBindings>
    </xs:appinfo>
</xs:annotation>

XML xs: dateTime alanı da saat dilimini sakladığından, Takvim nesneleri yerel ayarlar ve saat dilimleriyle çalışmak için oldukça iyi bir API'ye sahip olduğundan, yine de Date yerine Calendar ile çalışmak benim için daha iyi olabilir. Her durumda, XMLGregorianCalendar yerine Takvim nesneleriyle uğraşmaktan çok daha mutluyum. Artık yukarıda listelediğim dönüştürme yöntemlerine gerek yok. Java.util.Date'e kadar gelemedim ama yeterince yaklaştım!


Ben bilmiyorum. Ama seninki oldukça iyi görünüyor - sadece bir utilpakete koyun ve kullanın.
Bozho

Biraz kenara, ama neden öncelikle XMLGregorianCalendar nesneleriyle uğraşmak zorundasın? Biraz rahatsız edicidirler. Jaxb'den geliyorlarsa, java.util.Date'e doğrudan bağlanmak için @XMLTypeAdapter kullanmak mümkündür. Elbette, bir şemadan otomatik olarak oluşturuyorsanız, nesneleri değiştirmek, yeniden oluşturduğunuzda da rahatsız edici olabilir.
Affe

@Affe Bir şemadan otomatik olarak oluşturuluyorum, bu nedenle oluşturulan JAXB sınıflarında herhangi bir manuel değişiklik yapamıyorum
Jim Tough


1
@Jacob - öyle değil. Nasıl yapılacağını çoktan anladı , kullanıma hazır bir fayda sınıfı olup olmadığını merak ediyor.
Bozho

Yanıtlar:


46

XJC'ye XMLGregorianCalendar yerine java.util.Date alanları oluşturmasını söylemek için neden harici bir bağlama dosyası kullanmıyorsunuz?

Ayrıca xs: date ile java.util.Date'i nasıl eşlerim? Blog


Bunu araştıracağım. Teşekkürler.
Jim Tough

Sorun değil. JAXB, java.util.Date türünü işleyebilir, sadece bunu modelinizde oluşturmanız gerekir. Bu aldatıcı olabilir.
bdoughan

Bu benim için çalıştı. Yaptığım şeyle ilgili ayrıntılar için yukarıdaki sorumla ilgili düzenlemelere bakın.
Jim Tough

Xs: schema'nın hemen altına jaxb bağlamaları ekledim ve şu hatayı alıyorum: com.sun.istack.SAXParseException2: derleyici bu globalBindings özelleştirmesini kabul edemedi. Yanlış bir yere bağlanmış veya diğer bağlarla tutarsız. com.sun.tools.xjc.ErrorReceiver.error (ErrorReceiver.java:86) at ..
pri

@pritam - Yardımcı olabilecek başka bir örnek: blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html . Gördüğünüz konu için yeni bir soruya bakmaya değer olabilir.
bdoughan

81

XMLGregorianCalendar'dan java.util.Date'e kadar şunları yapabilirsiniz:

java.util.Date dt = xmlGregorianCalendarInstance.toGregorianCalendar().getTime();  

Teşekkürler ... XMLGregorianCalendar'ı milisaniye cinsinden zamana dönüştürmenin bir yolunu arıyordum.
Andez

6

Java.util.Date'den XMLGregorianCalendar'a kadar şunları yapabilirsiniz:

import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import java.util.GregorianCalendar;
......
GregorianCalendar gcalendar = new GregorianCalendar();
gcalendar.setTime(yourDate);
XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcalendar);

@ F-puras'ın ilk yorumundan sonra düzenlenen kod, çünkü bir hata yapıyorum.


1
Yazdığınız şekilde çalışmıyor: GregorianCalendar.setTime () hiçbir şey döndürmeyecek.
f_puras

5

Bu arada bazı şeyler değişmiş gibi göründüğünden, çalışmasını sağlamak için bazı değişiklikler yapmak zorunda kaldım:

  • xjc bağdaştırıcımın XmlAdapter'ı genişletmediğinden şikayet eder
  • bazı tuhaf ve gereksiz ithalatlar alındı ​​(org.w3._2001.xmlschema)
  • ayrıştırma yöntemleri XmlAdapter genişletirken statik olmamalıdır, tabii ki

İşte çalışan bir örnek, umarım bu yardımcı olur (JodaTime kullanıyorum ama bu durumda SimpleDate yeterli olacaktır):

import java.util.Date;
import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.joda.time.DateTime;

public class DateAdapter extends XmlAdapter<Object, Object> {
    @Override
    public Object marshal(Object dt) throws Exception {
        return new DateTime((Date) dt).toString("YYYY-MM-dd");
    }

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

Xsd'de yukarıda verilen mükemmel referansları takip ettim, bu yüzden bu xml açıklamasını ekledim:

<xsd:appinfo>
    <jaxb:schemaBindings>
        <jaxb:package name="at.mycomp.xml" />
    </jaxb:schemaBindings>
    <jaxb:globalBindings>
        <jaxb:javaType name="java.util.Date" xmlType="xsd:date"
              parseMethod="at.mycomp.xml.DateAdapter.unmarshal"
          printMethod="at.mycomp.xml.DateAdapter.marshal" />
    </jaxb:globalBindings>
</xsd:appinfo>

1
Bu soruyu sorduğumdan beri Joda Time hayranı oldum. Java SE tarih ve saat sınıflarından çok daha iyi. Saat dilimlerini işlemek için harika!
Jim Tough

1

Benim de bu tür bir baş ağrım vardı. POJO'mda zaman alanlarını ilkel uzun olarak temsil ederek ondan kurtuldum. Şimdi WS istemci kodumun oluşturulması her şeyi doğru bir şekilde hallediyor ve artık XML'den Java'ya saçmalığı yok. Ve tabii ki Java tarafında millis ile uğraşmak basit ve zahmetsizdir. KISS prensibi harika!


1

Varsayılan eşlemeyi java.util.Date olarak değiştirmek için bu özelleştirmeyi kullanabilirsiniz.

<xsd:annotation>
<xsd:appinfo>
    <jaxb:globalBindings>
        <jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"
                 parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime"
                 printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime"/>
    </jaxb:globalBindings>
</xsd:appinfo>


0

Sıralama Sırasında Takvimi ve Tarihi Özelleştirme

Adım 1: Özel özellikler için jaxb bağlama xml'yi hazırlayın, Bu durumda tarih ve takvim için hazırladım

<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings generateElementProperty="false">
<jaxb:serializable uid="1" />
<jaxb:javaType name="java.util.Date" xmlType="xs:date"
    parseMethod="org.apache.cxf.tools.common.DataTypeAdapter.parseDate"
    printMethod="com.stech.jaxb.util.CalendarTypeConverter.printDate" />
<jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
    parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
    printMethod="com.stech.jaxb.util.CalendarTypeConverter.printCalendar" />


Setp 2: Apache'ye veya aşağıda belirtildiği gibi xsd seçeneğinde ilgili eklentilere özel jaxb bağlama dosyası ekleyin

<xsdOption>
  <xsd>${project.basedir}/src/main/resources/tutorial/xsd/yourxsdfile.xsd</xsd>
  <packagename>com.tutorial.xml.packagename</packagename>
  <bindingFile>${project.basedir}/src/main/resources/xsd/jaxbbindings.xml</bindingFile>
</xsdOption>

Setp 3: CalendarConverter sınıfının kodunu yazın

package com.stech.jaxb.util;

import java.text.SimpleDateFormat;

/**
 * To convert the calendar to JaxB customer format.
 * 
 */

public final class CalendarTypeConverter {

    /**
     * Calendar to custom format print to XML.
     * 
     * @param val
     * @return
     */
    public static String printCalendar(java.util.Calendar val) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");
        return simpleDateFormat.format(val.getTime());
    }

    /**
     * Date to custom format print to XML.
     * 
     * @param val
     * @return
     */
    public static String printDate(java.util.Date val) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(val);
    }
}

Setp 4: Çıkış

  <xmlHeader>
   <creationTime>2014-09-25T07:23:05</creationTime> Calendar class formatted

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.