Automatizar generación de XML con JAXB
Hace poco en mi trabajo tenía que realizar ciertos artefactos que se empaquetan en un archivo jar, el cual incluye un XML, despues de hacer los primeros 2 o 3 note que estaba cayendo en la mala practica de copiar y pegar la estructura del XML de mi viejo artefacto y en ocasiones por rapidez no cambiaba el nombre, tipo de dato o argumento de alguna etiqueta y cuando desplegaba el artefacto pues fallaba, un compañero de trabajo me mencionó que definiera el xsd del archivo, y luego creará los objetos mapeados con xjc (imagino que significa xml java compiler, no estoy muy seguro de ello), y despues diseñara un standalone que preguntara por los valores de los atributos que variaran, y pues seguí las indicaciones realizando los siguientes pasos:
1.- Identifique los elementos que varian que fueron:
Valor del tag autor, email, creationDate, description e implementation.
Valor de los atributos type y length del tag Attribute.
Valor del atributo name del tag Plugin.
<Plugin name="MyPlugin" type="Authentication">
<autor>Unknown<autor>
<email>someone@domain</email>
<creationDate>2015-09-03</creationDate>
<version>10</version>
<description>MyPlugin</description>
<interface>oracle.security.am.plugin.authn.AbstractAuthenticationPlugIn</interface>
<implementation>com.example.MyPlugin</implementation>
<configuration>
<--Los elementos AttirbuteValuePair son opcionales dependiendo del tipo de artefacto>
<AttributeValuePair>
<Attribute type="string" length="30">prefix_user</Attribute>
<mandatory>true</mandatory>
<instanceOverride>true</instanceOverride>
<globalUIOverride>false</globalUIOverride>
<value><b>prefix_user</b></value>
</AttributeValuePair>
<AttributeValuePair>
<Attribute type="string" length="30">prefix_pass</Attribute>
<mandatory>true</mandatory>
<instanceOverride>true</instanceOverride>
<globalUIOverride>false</globalUIOverride>
<value>prefix_pass</value>
</AttributeValuePair>
</configuration>
</Plugin>
2.- Definí el schema de acuerdo a la estructura (Este paso es opcional algunas veces ya se tiene el esquema .xsd):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Plugin">
<xs:complexType>
<xs:sequence>
<xs:element name="author" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="email" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="creationDate" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="version" type="xs:string" default="10" minOccurs="1" maxOccurs="1"/>
<xs:element name="description" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="interface" type="xs:string" default="oracle.security.am.plugin.authn.AbstractAuthenticationPlugIn" minOccurs="1" maxOccurs="1"/>
<xs:element name="implementation" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="configuration" type="configuration" minOccurs="1" maxOccurs="1">
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="optional" default="Authentication"/>
</xs:complexType>
</xs:element>
<xs:complexType name="configuration" >
<xs:sequence>
<xs:element name="AttributeValuePair" type="AttributeValuePair" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AttributeValuePair">
<xs:sequence>
<xs:element ref="Attribute" minOccurs="1" maxOccurs="1"/>
<xs:element name="mandatory" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="instanceOverride" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="globalUIOverride" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="value" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Attribute">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="length" use="required" type="xs:string"/>
<xs:attribute name="type" use="required" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
3.- Generé los objetos del archivo .xsd con el comando xjc:
$ xjc -p domain.objects Plugin.xsd
En donde la opción p nos sirvió para definir el paquete y Plugin.xsd es nuestro archivo que define el esquema del XML, si todo salió bien y sin errores esta herramienta (xjc) nos genero las clases y anotaciones adecuadas de JAXB para el mapeo de los objetos que se encuentran en el paquete domain.objects:
Existe un paso intermedio aqui, si quieres generar valores por default, JAXB no es muy inteligente (link) para ello y se deben de hardcodear en mi caso modifique algunos valores de atributos y tags simplemente asignandoles el valor directamente.
4.- Generar el standalone para crear el XML con JAXB:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import domain.objects.AttributeValuePair;
import domain.objects.Attribute;
import domain.objects.Configuration;
import domain.objects.Plugin;
public class GeneratePluginXMLFile {
public static void main(String[] args) {
InputStreamReader lecturaCaracter = new InputStreamReader(System.in);
BufferedReader lecturaLinea = new BufferedReader(lecturaCaracter);
Plugin plugin = new Plugin();
try {
print("plugin name");
String pluginName = lecturaLinea.readLine();
plugin.setName(pluginName);
plugin.setDescription(pluginName);
print("autor");
plugin.setAuthor(lecturaLinea.readLine());
print("email");
plugin.setEmail(lecturaLinea.readLine());
print("package where is the implementation class");
plugin.setImplementation(lecturaLinea.readLine() + "." + pluginName);
System.out.println("Tipo de plugin: \n1 Lib Plugin \n2 Auth Plugin");
String tipo = lecturaLinea.readLine();
Configuration config = new Configuration();
if (tipo.equals("2")) {
System.out.println("Which prefix do you need for namespace´s variable");
String prefix = lecturaLinea.readLine();
System.out.println("How many attributes do you need ?");
String stringNum = lecturaLinea.readLine();
int attributes = Integer.parseInt(stringNum);
int n = 1;
do{
System.out.println("We need the data for attribute #" + n);
AttributeValuePair attrs = new AttributeValuePair();
Attribute attr = new Attribute();
print("type (i.e. xs:string)");
attr.setType(lecturaLinea.readLine());
print("length (i.e. 100)");
attr.setLength(lecturaLinea.readLine());
print("value (i.e. idUser)");
String name = lecturaLinea.readLine();
name = prefix + name;
attr.setValue(name);
attrs.setAttribute(attr);
attrs.setValue(name);
config.getAttributeValuePair().add(attrs);
n++;
}while(n<=attributes);
}
plugin.setConfiguration(config);
File file = new File("/file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Plugin.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// Le damos formato
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(plugin, file);
jaxbMarshaller.marshal(plugin, System.out);
} catch (Exception e) {
System.out.println(e.getMessage() + e.getStackTrace());
}
}
public static void print(String cadena) {
System.out.println("Introduce " + cadena + ": ");
}
}
Y si todo salio bien pues te preguntará por los valores de los tags y atributos que son variables y te generará el archivo y la salida a pantalla adecuados:
Introduce plugin name:
MyPlug
Introduce autor:
Hiroshige Cid
Introduce email:
algo@gmail.com
Introduce package where is the implementation class:
com.package
Tipo de plugin:
1 Lib Plugin
2 Auth Plugin
2
Which prefix do you need for namespace´s variable
generic_
How many attributes do you need ?
2
We need the data for attribute #1
Introduce type (i.e. string):
string
Introduce length (i.e. 100):
50
Introduce value (i.e. idUser):
iduser
We need the data for attribute #2
Introduce type (i.e. xs:string):
string
Introduce length (i.e. 100):
50
Introduce value (i.e. idUser):
password<Plugin name="MyPlug">
<author>Hiroshige Cid</author>
<email>algo@gmail.com</email>
<description>MyPlug</description>
<implementation>com.package.MyPlug</implementation>
<configuration>
<AttributeValuePair>
<Attribute type="string" length="50">generic_iduser</Attribute>
<value>generic_iduser</value>
</AttributeValuePair>
<AttributeValuePair>
<Attribute type="string" length="50">generic_password</Attribute>
<value>generic_password</value>
</AttributeValuePair>
</configuration>
</Plugin>
Si alguien tiene algo por mejorar o darme una idea mejor de como generar mi xml se los agradecería, de igual forma si le sirve a alguien más pues que bien.
Saludos.
- Cid's blog
- Inicie sesión o regístrese para enviar comentarios
Comentarios
JAXB & eclipse
También puedes generar las clases con eclipse: