una que interfaz interfaces implementacion example entre ejemplos diferencia clase abstracta java xsd jaxb xjc jaxb2-basics

que - public interface java



Generando una clase JAXB que implementa una interfaz (9)

Actualmente estoy usando JAXB para generar clases de Java para destrabar XML. Ahora me gustaría crear un nuevo esquema muy similar al primero y hacer que las clases que se generan implementen la misma interfaz.

Digamos, por ejemplo, que tengo dos archivos de esquema que definen XML con etiquetas similares:

adult.xsd

<?xml version="1.0" encoding="UTF-8"?> <xs:element name="Person"> <xs:complexType> <xs:sequence> <xs:element name="Name" type="xs:string" /> <xs:element name="Age" type="xs:integer" /> <xs:element name="Job" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:element>

kid.xsd

<?xml version="1.0" encoding="UTF-8"?> <xs:element name="Person"> <xs:complexType> <xs:sequence> <xs:element name="Name" type="xs:string" /> <xs:element name="Age" type="xs:integer" /> <xs:element name="School" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:element>

Usando JAXB y XJC me gustaría generar dos archivos de clase:

public class Adult implements Person { ... public String getName() { ... } public int getAge() { ... } public String getJob { ... } } public class Kid implements Person { ... public String getName() { ... } public int getAge() { ... } public String getSchool { ... } }

donde la interfaz de persona define los métodos getName() y getAge() .

He revisado parte de la documentation para las interfaces de mapeo, pero esto parece ser solo para la situación en la que ya tienes clases Java que deseas asignar a un DOM.

Además, he tratado de usar este complemento externo pero parece que no funciona. Aquí está mi archivo de enlace xjb:

<jxb:bindings version="1.0" xmlns:jxb="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" xmlns:ext="http://xml.w-wins.com/xjc-plugins/interfaces" jxb:extensionBindingPrefixes="xjc"> <jxb:bindings schemaLocation="xsd/adult.xsd" node="xs:schema/xs:complexType[@name=''Person'']"> <ext:interface>mypackage.Hello</ext:interface> </jxb:bindings> </jxb:bindings>

pero esto da el siguiente error:

$ java -cp "lib/activation.jar;lib/InterfacesXJCPlugin.jar;lib/jaxb1-impl.jar;lib/jaxb-api.jar;lib/jaxb-xjc.jar;lib/jsr173_1.0_api.jar" com.sun.tools.xjc.XJCFacade -p mypackage.myxml -extension -Xinterfaces xsd/adult.xsd -b binding.xjb parsing a schema... [ERROR] XPath evaluation of "xs:schema/xs:complexType[@name=''Person'']" results in empty target node line 8 of file:/C:/dev/jaxb/jaxb-ri/binding.xjb Failed to parse a schema.

¿Es posible generar una clase con JAXB que implemente una interfaz?

Actualizar

Intenté usar el complemento de inserción de interfaz, pero por alguna razón no puedo hacerlo funcionar. Así es como llamo a xjc, pero es como si el compilador de plugins no fuera recogido del classpath:

$ java -cp "lib/xjc-if-ins.jar;lib/jaxb-xjc.jar" com.sun.tools.xjc.XJCFacade -p mypackage -extension -Xifins myschema.xsd -b binding.xjb

Me sale el error:

unrecognized parameter -Xifins

¿Algunas ideas?


¿Qué sucede si extraes el tipo en un XSD común importado en adult.xsd y kid.xsd? ¿O tiene una interfaz existente que necesita que implemente?


Desafortunadamente, parece que el complemento de inyección de interfaz mencionado en algunas de las otras respuestas ya no es compatible. De hecho, tengo problemas para encontrar el archivo JAR para descargar.

Afortunadamente, los complementos básicos de JAXB2 proporcionan un mecanismo similar para agregar una interfaz a los talones de JAXB generados (consulte el complemento de herencia ).

La documentación del complemento de Herencia tiene un ejemplo que muestra cómo se vería el archivo de esquema XML. Sin embargo, dado que no puede modificar el esquema, puede usar un archivo de enlaces externo en su lugar:

<?xml version="1.0"?> <jxb:bindings version="1.0" xmlns:jxb="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" xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance" jxb:extensionBindingPrefixes="xjc"> <jxb:bindings schemaLocation="xsd/adult.xsd"> <jxb:bindings node="//xs:complexType[@name=''Person'']"> <inheritance:implements>mypackage.Hello</inheritance:implements> </jxb:bindings> </jxb:bindings> </jxb:bindings>

La documentación de los Complementos básicos de JAXB2 incluye instrucciones para usar el complemento con Ant y Maven. También puede usarlo directamente desde la línea de comando, pero el comando es un poco desordenado (debido a la cantidad de jarras que debe agregar a la ruta de clases):

java -jar jaxb-xjc.jar -classpath jaxb2-basics-0.5.3.jar,jaxb2-basics-runtime-0.5.3.jar, jaxb2-basics-tools-0.5.3.jar,commons-beanutils-0.5.3.jar, commons-lang.jar,commons-logging.jar -p mypackage.myxml -extension -Xinheritance xsd/adult.xsd -b binding.xjb

Los complementos básicos de JAXB2 proporcionan una serie de otras utilidades que también puede resultarle útiles (como la autogeneración de los métodos equals, hashCode y toString).


En mi caso, la llamada de línea de comando a través de java -jar funciona:

java -jar $somepath/jaxb-xjc.jar -classpath $somepath/xjc-if-ins.jar my.xsd -d $destdir -b $bindingconfig -p $desiredpackage -extension -Xifins

Sin embargo, al ejecutar xjc ant-task, el error permanece. El mensaje de error es irritante ya que la verdadera razón en mi caso es un número de versión malo en un archivo de clase que la hormiga intenta cargar (ver stacktrace a continuación). Este mensaje de error correcto solo aparece cuando agrega lo siguiente a ANT_OPTS: -Dcom.sun.tools.xjc.Options.findServices=true

[xjc] java.lang.UnsupportedClassVersionError: Bad version number in .class file [xjc] at java.lang.ClassLoader.defineClass1(Native Method) [xjc] at java.lang.ClassLoader.defineClass(ClassLoader.java:620) [xjc] at org.apache.tools.ant.AntClassLoader.defineClassFromData(AntClassLoader.java:1134) [xjc] at org.apache.tools.ant.AntClassLoader.getClassFromStream(AntClassLoader.java:1320) [xjc] at org.apache.tools.ant.AntClassLoader.findClassInComponents(AntClassLoader.java:1376) [xjc] at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1336) [xjc] at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1074) [xjc] at java.lang.ClassLoader.loadClass(ClassLoader.java:299) [xjc] at java.lang.ClassLoader.loadClass(ClassLoader.java:251) [xjc] at com.sun.tools.xjc.Options.findServices(Options.java:936) [xjc] at com.sun.tools.xjc.Options.getAllPlugins(Options.java:336) [xjc] at com.sun.tools.xjc.Options.parseArgument(Options.java:632) [xjc] at com.sun.tools.xjc.Options.parseArguments(Options.java:742) [xjc] at com.sun.tools.xjc.XJC2Task._doXJC(XJC2Task.java:444) [xjc] at com.sun.tools.xjc.XJC2Task.doXJC(XJC2Task.java:434) [xjc] at com.sun.tools.xjc.XJC2Task.execute(XJC2Task.java:369) [xjc] at com.sun.istack.tools.ProtectedTask.execute(ProtectedTask.java:55) [xjc] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291) [xjc] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [xjc] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [xjc] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [xjc] at java.lang.reflect.Method.invoke(Method.java:585) [xjc] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106) [xjc] at org.apache.tools.ant.Task.perform(Task.java:348) [xjc] at org.apache.tools.ant.Target.execute(Target.java:390) [xjc] at org.apache.tools.ant.Target.performTasks(Target.java:411) [xjc] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1360) [xjc] at org.apache.tools.ant.Project.executeTarget(Project.java:1329) [xjc] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41) [xjc] at org.apache.tools.ant.Project.executeTargets(Project.java:1212) [xjc] at org.apache.tools.ant.Main.runBuild(Main.java:801) [xjc] at org.apache.tools.ant.Main.startAnt(Main.java:218) [xjc] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280) [xjc] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109) [xjc] [xjc] failure in the XJC task. Use the Ant -verbose switch for more details


Es posible lograr esto para este caso simple sin usar un complemento de terceros utilizando JAXB RI Vendor Extensions xjc: personalización de superInterface. Cabe señalar que este enfoque hará que todas las clases generadas implementen la interfaz.

Ejemplo de archivo de enlaces:

<jxb:bindings version="1.0" xmlns:jxb="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" jxb:extensionBindingPrefixes="xjc"> <jxb:bindings schemaLocation="adult.xsd" node="/xs:schema"> <jxb:globalBindings> <xjc:superInterface name="com.example.model.Person"/> </jxb:globalBindings> </jxb:bindings> </jxb:bindings>

Entonces solo necesita ejecutar xjc especificando el archivo de enlace y configurando el indicador de extensión. ¡Mucho más rápido / más simple que traer JAXB2Basics!

Inicialmente, era escéptico de que esto funcionaría como lo indica la documentación:

La personalización le permite especificar el nombre completo de la interfaz Java que se utilizará como la interfaz raíz de todas las interfaces generadas. Esta personalización no tiene ningún efecto a menos que genere interfaces específicamente con el interruptor globalBindings generateValueClass = "false".

Pero cuando lo probé con un enlace similar al anterior (sin especificar generateValueClass = "false", y generando clases, no interfaces), me dio el resultado que necesitaba: todas las clases generadas implementaron la interfaz común.


La documentación para el complemento de inserción de interfaz sugiere el siguiente

[Para llamar a xjc con el complemento de inserción de interfaz desde la línea de comando, puede escribir:

java -cp $JAXB_HOME/share/lib/xjc-if-ins.jar -extension -Xifins schema

]

Supongo que está llamando al método principal de la clase incorrecta: com.sun.tools.xjc.XJCFacade. Probablemente deberías volver a intentar con la sintaxis exacta.

Aquí hay un enlace en otro foro que analiza un problema similar. http://forums.java.net/jive/message.jspa?messageID=220686

  • Lo habría publicado como un comentario, pero no tengo suficientes puntos para comentar.

La respuesta que funcionó para mí fue el ejemplo de Jim Hurne sobre el uso del complemento JAXB2 Basics. Pero la documentación que él vinculó parece que ya no está disponible, así que como referencia, así es como configuré el plugin maven:

<plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifactId> <version>0.8.2</version> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <extension>true</extension> <args> <arg>-Xinheritance</arg> </args> <bindingDirectory>src/main/resources/xjb</bindingDirectory> <bindingIncludes> <include>**.xml</include> <!-- This Should reference the binding files you use to configure the inheritance --> </bindingIncludes> <schemaDirectory>src/main/resources/xsd</schemaDirectory> <generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory> <generatePackage>mypackage</generatePackage> <plugins> <plugin> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-basics</artifactId> <version>0.5.3</version> </plugin> </plugins> </configuration> </plugin>


Para quienes deseen ayuda en la creación de archivos de enlace de datos JAXB para esquemas más complejos, la última herramienta XML de código abierto, CAM Editor v2.2 ahora es compatible con esto.

Puede acceder a los recursos y descargar el sitio para la guía paso a paso y para ver la sección de descargas en la parte superior de la página para la herramienta.

http://www.cameditor.org/#JAXB_Bindings

Disfrutar.


Puede ser exagerado para su situación, pero lo he hecho usando AspectJ (ya estábamos usando aspectos en ese proyecto, por lo que ya teníamos la dependencia y la exposición).

Usted declararía un aspecto en la línea de:

public aspect MyAspect { declare parents: com.foo.generated.Adult implements com.foo.Person; declare parents: com.foo.generated.Kid implements com.foo.Person; }

Lo cual agregará la interfaz com.foo.Person a las clases com.foo.generated.Adult y com.foo.generated.Adult

Podría ser excesivo para su propósito, pero funcionó para nosotros.