Skip to content

Instantly share code, notes, and snippets.

@bryanjhv
Created May 18, 2018 07:33
Show Gist options
  • Save bryanjhv/7a1db648aaa9254d555c9cf2ecb07aba to your computer and use it in GitHub Desktop.
Save bryanjhv/7a1db648aaa9254d555c9cf2ecb07aba to your computer and use it in GitHub Desktop.

XSD TO JAVA

Simple proof of concept for converting XSD schemas into pure Java classes at runtime and by using reflection. It can be improved to, for example, build intelligent JAX-RS console or GUI clients without knowledge of the domain model, by querying application.wadl and looking for the schema. The classes are transpiled, compiled and appended to the path at runtime so they are always updated. Other things missing is fetching the schema from network instead of a file, not depending on JXC and Javax Tools, building a schema and creating an automatic CLI client for it, between other tree of possibilities.

<?xml version="1.0" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ciudad" type="ciudad"/>
<xs:element name="ciudadDTO" type="ciudadDTO"/>
<xs:element name="contacto" type="contacto"/>
<xs:element name="contactoDTO" type="contactoDTO"/>
<xs:element name="pais" type="pais"/>
<xs:element name="paisDTO" type="paisDTO"/>
<xs:element name="telefono" type="telefono"/>
<xs:element name="telefonoDTO" type="telefonoDTO"/>
<xs:complexType name="ciudadDTO">
<xs:sequence>
<xs:element name="contactos" type="contacto" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="idCiudad" type="xs:int"/>
<xs:element name="nombreCiudad" type="xs:string" minOccurs="0"/>
<xs:element ref="pais" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="contacto">
<xs:sequence>
<xs:element ref="ciudad" minOccurs="0"/>
<xs:element name="idContacto" type="xs:int"/>
<xs:element name="nombre" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ciudad">
<xs:sequence>
<xs:element name="idCiudad" type="xs:int"/>
<xs:element name="nombreCiudad" type="xs:string" minOccurs="0"/>
<xs:element ref="pais" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="pais">
<xs:sequence>
<xs:element name="idPais" type="xs:int"/>
<xs:element name="nombrePais" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="contactoDTO">
<xs:sequence>
<xs:element ref="ciudad" minOccurs="0"/>
<xs:element name="idContacto" type="xs:int"/>
<xs:element name="nombre" type="xs:string" minOccurs="0"/>
<xs:element name="telefonos" type="telefono" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="telefono">
<xs:sequence>
<xs:element ref="contacto" minOccurs="0"/>
<xs:element name="idTelefono" type="xs:int"/>
<xs:element name="numero" type="xs:string" minOccurs="0"/>
<xs:element name="operador" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="paisDTO">
<xs:sequence>
<xs:element name="ciudads" type="ciudad" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="idPais" type="xs:int"/>
<xs:element name="nombrePais" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="telefonoDTO">
<xs:sequence>
<xs:element ref="contacto" minOccurs="0"/>
<xs:element name="idTelefono" type="xs:int"/>
<xs:element name="numero" type="xs:string" minOccurs="0"/>
<xs:element name="operador" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import static java.nio.file.Files.createTempDirectory;
public class XsdToJava {
private static boolean exec(String cmd) throws Exception {
return Runtime.getRuntime().exec(cmd).waitFor() == 0;
}
public static void main(String[] args) throws Exception {
String dest = createTempDirectory("x2j").toString();
String path = XsdToJava.class.getResource("schema.xsd").getFile();
String cmd = String.join(" ", new String[]{
"/opt/payara41/glassfish/bin/xjc",
"-d " + dest,
"-p " + "x2j",
"-npa", "-no-header",
path,
});
int exitCode = Runtime.getRuntime().exec(cmd).waitFor();
if (exitCode == 0) {
System.out.println(dest);
// Enhance
addPath(dest);
// Compile
File dir = new File(dest, "x2j");
for (File file : dir.listFiles()) {
if (file.isFile()) {
compile(dest, file.getAbsolutePath());
}
}
// Lookup
try {
Class.forName("x2j.PaisDTO");
System.out.println("PaisDTO found!!!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private static void addPath(String path) throws Exception {
URLClassLoader loader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(loader, new File(path).toURL());
}
private static void compile(String dir, String path) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, path, "-cp", dir);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment