Reputation: 11
I am working on a project where I need to automatically generate code for a POJO-like object from an XML Schema (XSD) file. To achieve this, I have created a class that takes the file path of the XSD as input and generates the corresponding code as a string.
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.xml.sax.InputSource;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.CodeWriter;
import com.sun.tools.xjc.api.ClassNameAllocator;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
import com.sun.codemodel.writer.SingleStreamCodeWriter;
public class SemanticPOJOCreator {
public static String fromXSD(String xsdFilePath, String outClassName) throws IOException {
SchemaCompiler sc = XJC.createSchemaCompiler();
sc.forcePackageName("");
sc.setClassNameAllocator(new ClassNameAllocator() {
public String assignClassName(String packageName, String className) {
return outClassName;
}
});
File schemaFile = new File(xsdFilePath);
try (FileInputStream fis = new FileInputStream(schemaFile)) {
InputSource is = new InputSource(fis);
URI uri = schemaFile.toURI();
is.setSystemId(uri.toASCIIString());
sc.parseSchema(is);
S2JJAXBModel model = sc.bind(); // Here
JCodeModel jCodeModel = model.generateCode(null, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CodeWriter codeWriter = new SingleStreamCodeWriter(baos);
jCodeModel.build(codeWriter);
String generatedCode = baos.toString();
generatedCode = Arrays.stream(generatedCode.split("\n"))
.map(line -> {
if (line.startsWith("public class")) {
return line.replace("public class", "class");
} else {
return line;
}
})
.filter(line -> !line.startsWith("import") && !line.contains("-----"))
.collect(Collectors.joining("\n"));
generatedCode = generatedCode.replaceAll("ObjectFactory", "ObjectFactory_" + outClassName);
return generatedCode;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
The class works correctly with most XSD files. However, it triggers an error when the file contains an <xs:import> element. Below is an example of the XSD file causing the issue:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:a3st ="http://gres.uninova.pt/a3st"
xmlns:sawsdl="http://www.w3.org/ns/sawsdl"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<xs:import namespace="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
schemaLocation="../common/UBL-CommonAggregateComponents-2.1.xsd"/>
<xs:import namespace="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
schemaLocation="../common/UBL-CommonBasicComponents-2.1.xsd"/>
<xs:import namespace="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
schemaLocation="../common/UBL-CommonExtensionComponents-2.1.xsd"/>
<xs:complexType name="InvoiceType">
<xs:sequence>
<xs:element ref="cac:AllowanceCharge" sawsdl:modelReference ="/TemperatureSensor{2}/hasDecValue">
</xs:element>
<xs:element ref="cac:TaxTotal">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
The error encountered is consistentently Exception in thread "main" java.lang.IllegalArgumentException: the root package cannot be annotated
and occurs at S2JJAXBModel model = sc.bind();
.
If the sc.forcePackageName("");
line is omitted, a different error occurs:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.sun.tools.xjc.api.S2JJAXBModel.generateCode(com.sun.tools.xjc.Plugin[], com.sun.tools.xjc.api.ErrorListener)" because "model" is null
Is the issue I'm encountering a limitation of the libraries or packages I am using, or could it be due to incorrect usage or configuration on my part?
Upvotes: 1
Views: 41