2012-09-20 14 views
11

Ich habe ein Problem mit der Art und Weise, wie JAXB die gebundenen Klassen für ein XML-Schema erzeugt (welches ich aus Gründen der Genauigkeit nicht modifizieren kann). ich eine XSD zuordnen möchten: Datum Typ einer Joda Zeit LOCALDATE Objekt und here, here und here lesen, habe ich die folgenden DateAdapter Klasse:JAXB, Custom Bindings, Adapter1.class und Joda-time

public class DateAdapter extends XmlAdapter<String,LocalDate> { 
    private static DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd"); 

    public LocalDate unmarshal(String v) throws Exception { 
     return fmt.parseLocalDate(v); 
    } 

    public String marshal(LocalDate v) throws Exception { 
     return v.toString("yyyyMMdd"); 
    } 
} 

Und ich fügte der folgenden meiner globalen Einbindemappe :

<jaxb:globalBindings> 
     <jaxb:javaType name="org.joda.time.LocalDate" xmlType="xs:date" 
      parseMethod="my.classes.adapters.DateAdapter.unmarshal" 
      printMethod="my.classes.adapters.DateAdapter.marshal" /> 
    </jaxb:globalBindings> 

Das Problem ist, dass, wenn ich versuche, mein Projekt zu maven kompilieren, ist es mit dem folgenden Fehler fehl:

[ERROR] \My\Path\MyProject\target\generated-sources\xjc\my\classes\generated\Adapter1.java:[20,59] non-static method unmarshal(java.lang.String) cannot be referenced from a static context 
[ERROR] \My\Path\MyProject\target\generated-sources\xjc\my\classes\generated\Adapter1.java:[24,59] non-static method marshal(org.joda.time.LocalDate) cannot be referenced from a static context 

... und hier wird es merkwürdig. JAXB erzeugt eine Klasse Adapter1, die Folgendes enthält:

public class Adapter1 
    extends XmlAdapter<String, LocalDate> 
{ 


    public LocalDate unmarshal(String value) { 
     return (my.classes.adapters.DateAdapter.unmarshal(value)); 
    } 

    public String marshal(LocalDate value) { 
     return (my.classes.adapters.DateAdapter.marshal(value)); 
    } 

} 

...., die die Quelle des Zusammenstellungsfehler ist.

Nun meine Fragen sind:

  • ist, dass mein Adapter XMLAdapter überschreibt, kann ich nicht die Methoden statisch machen .... wie kann ich das vermeiden?
  • Kann ich die Generierung von Adapter1.class insgesamt vermeiden? Vielleicht mit der Annotation auf Packet-Level XmlJavaTypeAdapters, und wenn ja, wie mache ich das genau? (JAXB erzeugt bereits ein eigenes Paket-info.java ....)

Hoffe, ich machte meine Situation klar.
Danke

Antwort

7

Sie brauchen nicht XmlAdapter zu verlängern.

Erstellen Sie einfach statische Methoden auf einem POJO und es wird funktionieren.

Beispiel:

public class DateAdapter { 
    private static DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd"); 

    public static LocalDate unmarshal(String v) throws Exception { 
     return fmt.parseLocalDate(v); 
    } 

    public static String marshal(LocalDate v) throws Exception { 
     return v.toString("yyyyMMdd"); 
    } 
} 
3

Wenn Sie XmlAdapter aus einem XML-Schema generieren, müssen Sie die Logik für die Konvertierung in statische Methoden nicht in eine XmlAdapter setzen. Dies ist so ein XmlAdapter, das nutzt, dass Logik generiert werden kann. Ich erkenne, dass dies ein seltsamer Mechanismus ist.

vollständiges Beispiel

3

Sie XmlAdapter erweitern, die verwendet wird, wenn Sie für jaxb Ihr Java-Modell in Annotations wollen, ist, dass durch die Anmerkung @XmlJavaTypeAdapter(Adapter1.class). Für Ihren Fall brauchen Sie nur eine Klasse mit statischen Methoden, die nicht XmlAdapter erweitert. Sie brauchen die Analyse-Methode (nehmen Sie eine Zeichenfolge und Datum zurück) und Druckmethode (nehmen Sie ein Datum und geben Sie eine Zeichenfolge zurück) und das ist es.

3

ich diese Lösung gefunden als nützlich http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html

Sie einen Adapter durch die Definition eines Blog/jodatime/package-info.java in Ihren Quellen

package blog.jodatime; 

import javax.xml.bind.annotation.adapters.XmlAdapter; 
import org.joda.time.DateTime; 

public class DateTimeAdapter 
    extends XmlAdapter<String, DateTime>{ 

    public DateTime unmarshal(String v) throws Exception { 
     //return new DateTime(v); - old solution that didn't properly handled the timezone 
     return DateTime.parse(v); 
    } 

    public String marshal(DateTime v) throws Exception { 
     return v.toString(); 
    } 

} 

Dann registriert es mit Anmerkungen erstellen

@XmlJavaTypeAdapters({ @XmlJavaTypeAdapter(type = DateTime.class, value = JodaDateTimeJaxbAdapter.class) }) 
package blog.jodatime; 

import javax.xml.bind.annotation.adapters.*; 

import org.joda.time.*; 

Dann sollten Sie erwarten, dass die Serialisierung von DateTime ohne weitere Änderungen durchgeführt wird, vergessen Sie nicht zu Kommentieren Sie Ihre Klasse mit @XmlRootElement.

+1

Was ist, wenn ich mit 'xjc' meine' JAXB' Klassen bin zu erzeugen? Meine Anmerkung würde überschrieben werden. –

17

Ich war in einem ersten WSDL-Kontext: überhaupt kein Java, einfach einen CXF-Client aus einer bereitgestellten WSDL generieren.

Ich war für eine lange Zeit mit dem hässlichen Adapter1.java fest, aber ich fand die Lösung there.

Sie verwenden einen benutzerdefinierten XMLAdapter wie bereits erläutert.

Der Schlüssel dieses Problems wurde Hinzufügen der xjc Erweiterung der globalen Einbindemappe:

<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.1"> 
    <jaxb:globalBindings> 
     <xjc:javaType adapter="com.xxx.tools.xjc.DateAdapter" 
     name="java.util.Date" xmlType="xs:dateTime" /> 
    </jaxb:globalBindings> 
</jaxb:bindings> 

xjc Erweiterung der Nutzung von xjc:javaType ermöglichen, die Adapter Parameter akzeptieren. Keine statische Methode mehr erforderlich!

Hinweis Dies scheint nur mit Jaxb 2.1 + zu arbeiten.

1

Ein vollständiges Beispiel. Das ist Ihre bindings.xml:

<jaxws:bindings wsdlLocation="YourWsdl" 
     xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" 
     xmlns:xs="http://www.w3.org/2001/XMLSchema" 
     xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
     xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
     jxb:extensionBindingPrefixes="xjc"> 
    <jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='YourTargetNameSpace']"> 
     <jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
      <xjc:javaType adapter="com.xxx.your.package.DateAdapter" name="java.util.Date" xmlType="xs:dateTime" /> 
     </jxb:globalBindings> 
    </jaxws:bindings> 
</jaxws:bindings> 

plus der Java-Klasse:

package com.yourpackage; 

import java.util.Calendar; 
import java.util.Date; 
import java.util.GregorianCalendar; 

import javax.xml.bind.DatatypeConverter; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class DateAdapter extends XmlAdapter<String, Date> 
{ 

    @Override 
    public Date unmarshal(final String date) { 
     return DatatypeConverter.parseDate(date).getTime(); 
    } 

    @Override 
    public String marshal(final Date date) 
    { 
     Calendar calendar = new GregorianCalendar(); 
     calendar.setTime(date); 
     return DatatypeConverter.printDate(calendar); 
    } 

} 

plus die pom.xml Definition:

<plugin> 
    <groupId>org.apache.cxf</groupId> 
    <artifactId>cxf-codegen-plugin</artifactId> 
    <version>${cxf.version}</version> 
    <dependencies> 
     <dependency> 
      <groupId>org.jvnet.jaxb2_commons</groupId> 
      <artifactId>jaxb2-basics</artifactId> 
      <version>0.6.4</version> 
     </dependency> 
    </dependencies> 
    <executions> 
     <execution> 
      <id>generate-sources</id> 
      <phase>generate-sources</phase> 
      <configuration> 
       <sourceRoot>${project.build.directory}/generated/cxf</sourceRoot> 
       <defaultOptions> 
        <autoNameResolution>true</autoNameResolution> 
       </defaultOptions> 
       <wsdlOptions> 
        <wsdlOption> 
         <wsdl>${basedir}/src/main/resources/your.wsdl</wsdl> 
         <extraargs> 
          <extraarg>-verbose</extraarg> 
          <extraargs>-xjc-npa</extraargs> 
          <extraarg>-xjc-Xsetters</extraarg> 
         </extraargs> 
         <bindingFiles> 
         <bindingFile>${basedir}/src/main/resources/binding.xml</bindingFile> 
         </bindingFiles> 
        </wsdlOption> 
       </wsdlOptions> 
      </configuration> 
      <goals> 
       <goal>wsdl2java</goal> 
      </goals> 
     </execution> 
    </executions> 
</plugin> 
0

Sie brauchen nicht XmlAdapter und mit Joda zu erweitern -Time v2, Sie müssen nicht einmal statische Methoden implementieren, wie sie bereits zur Verfügung gestellt werden.

<jaxb:javaType xmlns="http://java.sun.com/xml/ns/jaxb" 
    name="org.joda.time.LocalDate" 
    xmlType="xs:date" 
    parseMethod="org.joda.time.LocalDate.parse" 
    printMethod="java.lang.String.valueOf" 
/> 

Siehe JAXB datatype converters for xs:date xs:time and xs:dateTime