2012-09-20 20 views
11

Tengo un problema con la forma en que JAXB genera las clases enlazadas para un esquema XML (que, en aras de la precisión, no puedo modificar). que desea asignar un xsd: tipo de fecha a un objeto LocalDate Joda-tiempo y, leyendo here, here y here, creé la siguiente DateAdapter clase:JAXB, enlaces personalizados, Adapter1.class y 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"); 
    } 
} 

Y añadí lo siguiente a mi archivo de enlace mundial :

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

el problema es que, cuando intento compilar mi proyecto maven, se produce un error con el siguiente error:

[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 

... y aquí es donde las cosas se ponen raras. JAXB genera una adapter1 clase que contiene lo siguiente:

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

} 

.... que es la fuente del error de compilación.

Ahora, mis preguntas son:

  • es que mi adaptador es reemplazar XmlAdapter, no puedo hacer que los métodos estáticos .... ¿cómo puedo evitar esto?
  • ¿Puedo evitar la generación de Adapter1.class por completo? Tal vez usando la anotación de nivel de paquete XmlJavaTypeAdapters, y si es así, ¿cómo lo hago exactamente? (JAXB genera ya un paquete-info.java propio ...)

Espero que haya aclarado mi situación.
Gracias

Respuesta

7

No es necesario extender XmlAdapter.

Solo crea métodos estáticos en un POJO y funcionará.

Ejemplo:

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

al generar XmlAdapters de un esquema XML que necesita para poner la lógica para la conversión de los métodos estáticos no en un XmlAdapter. Esto es tan XmlAdapter que aprovecha esa lógica se puede generar. Reconozco que este es un mecanismo extraño.

completa Ejemplo

3

le conceden un XmlAdapter que se utiliza cuando se desea anotación de su modelo de Java para jaxb, que es a través de la anotación @XmlJavaTypeAdapter(Adapter1.class). Para su caso, solo necesita una clase con métodos estáticos que no se extienda XmlAdapter. Necesitará el método de análisis (tome una cadena y una fecha de regreso) e imprima el método (tome una fecha y devuelva una cadena) y eso es todo.

3

me encontré con esta solución tan útil http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html

Va a crear un adaptador

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

} 

A continuación, registrarlo con anotaciones mediante la definición de un blog/JodaTime/package-info.java en sus fuentes

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

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

import org.joda.time.*; 

Luego debe esperar que la serialización de DateTime se realice sin ningún otro cambio, simplemente no se olvide de anota tu clase con @XmlRootElement.

+1

¿Qué pasa si estoy generando mis clases '' JAXB' con xjc'? Mi anotación se sobrescribe. –

17

Estaba en un primer contexto WSDL: no hay java en absoluto, solo genera un cliente CXF a partir de un WSDL provisto.

Estuve atascado con el feo Adapter1.java durante mucho tiempo, pero encontré la solución there.

Utilizará un XMLAdapter personalizado como ya se explicó.

La clave de este problema fue la adición de la extensión xjc en el fichero de unión mundial:

<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 extensión permite el uso de xjc:javaType que aceptan adaptador parámetro. ¡No se requiere más método estático!

Nota esto parece funcionar solo con jaxb 2.1+.

1

Un ejemplo completo. Esta es su 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> 

más la clase de 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); 
    } 

} 

más la definición 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

No es necesario extender XmlAdapter y con Joda -Tiempo v2, ni siquiera necesita implementar métodos estáticos, ya que ya están provistos.

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

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