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.
Created
May 18, 2018 07:33
-
-
Save bryanjhv/7a1db648aaa9254d555c9cf2ecb07aba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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