2012-09-20 19 views
11

Ho un problema con il modo in cui JAXB genera le classi associate per uno schema XML (che, per motivi di precisione, non posso modificare). Voglio mappare un xsd: tipo di data a un oggetto LocalDate Joda-time e, leggendo here, here e here, ho creato il seguente DateAdapter classe:JAXB, associazioni personalizzate, Adapter1.class e 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"); 
    } 
} 

E ho aggiunto il seguente al mio file vincolante globale :

<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> 

il problema è che, quando cerco di Maven compilare il mio progetto, non riesce con il seguente errore:

[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 

... e questo è dove le cose diventano strane. JAXB genera un'adapter1 classe che contiene il seguente:

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)); 
    } 

} 

.... che è la fonte della errore di compilazione.

Ora, le mie domande sono:

  • è che il mio adattatore è prevalente XMLAdapter, non posso fare i metodi statici .... come posso evitare questo?
  • Posso evitare la generazione di Adapter1.class del tutto ?? Forse usando l'annotazione a livello di pacchetto XmlJavaTypeAdapters, e se sì, come faccio a farlo esattamente ?? (JAXB genera già un pacchetto-info.java a sé stante ....)

Spero di aver chiarito la mia situazione.
Grazie

risposta

7

Non è necessario estendere XmlAdapter.

Basta creare metodi statici su un POJO e funzionerà.

Esempio:

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

Quando si genera XmlAdapters da uno schema XML è necessario inserire la logica per la conversione in metodi statici non in un XmlAdapter. Questo è così un XmlAdapter che sfrutta quella logica può essere generata. Riconosco che questo è un meccanismo strano.

Complete Esempio

3

si sta estendendo XmlAdapter che viene utilizzato quando si vuole annotazione il vostro modello di Java per JAXB, che è attraverso l'annotazione @XmlJavaTypeAdapter(Adapter1.class). Per il tuo caso hai solo bisogno di una classe con metodi statici che non si estenda XmlAdapter. Sarà necessario il metodo di analisi (prendere una stringa e la data di ritorno) e il metodo di stampa (prendere una data e restituire una stringa) e questo è tutto.

3

ho trovato questa soluzione come utile http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html

Si creerà un adattatore

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(); 
    } 

} 

quindi registrarlo con annotazioni definendo un blog/jodatime/package-info.java nelle vostre fonti

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

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

import org.joda.time.*; 

Quindi ci si deve aspettare che la serializzazione di DateTime sia eseguita senza altre modifiche, non dimenticare di annota la tua classe con @XmlRootElement.

+1

Che cosa succede se sto generando i miei 'classi JAXB' con' xjc'? La mia annotazione verrebbe sovrascritta. –

17

Ero in un primo contesto WSDL: nessun java, basta generare un client CXF da un WSDL fornito.

Sono stato bloccato con il brutto Adapter1.java per molto tempo, ma ho trovato la soluzione there.

Si utilizzerà un XMLAdapter personalizzato come già spiegato.

La chiave di questo problema è stata aggiunta la xjc estensione al file vincolante globale:

<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 estensione permette l'utilizzo di xjc:javaType che accetta adattatore parametro. Non è più necessario il metodo statico!

Nota: sembra funzionare solo con jaxb 2.1+.

1

Un esempio completo. Questo è il tuo 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> 

più la classe Java:

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); 
    } 

} 

più la definizione pom.xml:

<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

Non è necessario estendere XmlAdapter e con Joda -Time v2, non è nemmeno necessario implementare metodi statici, poiché sono già forniti.

<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" 
/> 

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

Problemi correlati