How to export java JAXB Schema class to an xsd file? - java

I'm running into a problem with some XML validation and am trying to debug my problem. I am generating my XSDs on the fly with JAXBContext.generateSchema(), and then creating a unified schema with SchemaFactory.newSchema(schemas). However, my validation is failing. I'd like to see if the unified schema that newSchema is creating is as I expect, however I cannot seem to find a way to export the resulting Schema class to a string or a text file.
Is there any way to export a javax.xml.validation.Schema class into a readable String and/or XSD file? I looked through the API and cannot seem to find anything.
Thanks,
Eric

Instead of combining your schemas after creating them from JAXBContext.generateSchema(), why not just generate them all at once from your JAXBContext.
JAXBContext jc = JAXBContext.newInstance( new Class[] { Class1.class,
Class2.class,
Class3.class
}
);
jc.generateSchema(new SchemaOutputResolver() {
#Override
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
File file = new File(suggestedFileName);
return new StreamResult(file);
}
});

Related

Validating XML against multiple XSD(stored as resources). Spring Boot

I've spend a lot of time to validate XML against multiple XSD in Spring. Even when I give all XSD schemas to SchemaFactory it does not work because main schema can't see import schema declared in main XSD file. Even when I give this schemas as files it does not work, because Spring's resource files can't be resolved to absolute path.
<xs:import namespace="http://test.com/types" schemaLocation="types.xsd"/>
1. First we need this dependency which can parse xsd schemas:
implementation("org.apache.ws.xmlschema:xmlschema-core:2.2.4")
2. We create 2 beans. One for storing our XSD's (it will automatically find other files if there this schemaLocation="..."), another for our Validator:
#Bean
fun schema(): XsdSchemaCollection {
return CommonsXsdSchemaCollection(
ClassPathResource("xsd/main.xsd")
).also { it.setInline(true) }
}
#Bean
fun myValidator(schema: XsdSchemaCollection): XmlValidator {
return schema.createValidator()
}
3. And we can use it:
#Autowired
private val myValidator: XmlValidator
fun validate(data: String): Array<SAXParseException> {
return myValidator.validate(StreamSource(data.byteInputStream()))
}
Array<SAXParseException> will contain list of validation exceptions if any of course

Generate sample XML from JAXB using Eclipse

Let's say I've created JAXB class in eclipse. (Using #XmlRootElement, #XmlAttribute, etc)
Is there a plugin which generate me example XML preview from my JAXB annotated class ?
There are XML Editors, which can create Sample XMLs from the XSD, for example we use Altova XMLSpy.
There is a plugin called " org.jvnet.jaxbw.eclipse_1.0.0" which you need to keep in eclipse lib folder.
Below is the link for guide.
http://www.xyzws.com/scdjws/studyguide/jaxb_samples2.0.html
You can use JAXB marshaller for doing this. Just a 3 three lines of code.
File file = new File("D:\\generatedFile.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Myclass.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(obj, file);
generatedFile.xml will contains the XML equivalent of your annonated java bean(Myclass)

how to use jaxb to create java objects

I am trying to create java objects from xml file. I am using jaxb(unmarshalling) to create java objects.I am getting errors javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/2001/XMLSchema", local:"schema"). Expected elements are
I did some google and found out that, we need xsd file to do that... so I converted it to xsd using apache inst2xsd tool. I am using following java code:
import java.io.FileNotFoundException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="report")
public class Report
{
public static void main(String [] args) throws FileNotFoundException
{
try
{
JAXBContext jc = JAXBContext.newInstance(new Class[] {com.bcbsks.testjb.Report.class});
Unmarshaller um = jc.createUnmarshaller();
Report myJAXBObject = (Report)um.unmarshal(new java.io.FileInputStream("report.xsd"));
}
catch( UnmarshalException ue )
{
ue.printStackTrace();
}
catch( JAXBException je )
{
je.printStackTrace();
}
}
}
But I am getting fol;owing error:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/2001/XMLSchema", local:"schema"). Expected elements are (none)
Can you please tell me whats wrong I am doing?
Any help is greatly appreciated.
I think you are missing a few steps. You didn't post what report.xsd is, nor a sample xml, so I'm going to take a few guesses.
For starters, you are trying to unmarshal the xsd and not xml, which is itself the root of the problem. That being said, your Report.java class does not look properly generated so it is unlikely that your unmarshalling would work even if you tried against your xml file.
If you have a properly created XSD file, the first thing you should do is create the JaxB POJOs using xjc. xjc comes installed with java, and you use it to create annotated java classes from the xsd. It will also create 2 additional files - ObjectFactory.java and package-info.java which are used by JAXB. (You can specify the output path using the -d param (see --help for the full list of switches)
xjc -d c:\dev\myproject\src\main\java report.xsd
Once you have those files generated, you have to create your JAXBContext based on that package/file.
JAXBContext jc = JAXBContext.newInstance(something.generated.Report.class);
Unmarshaller um = jc.createUnmarshaller();
Report myJAXBObject = (Report)um.unmarshal(new java.io.FileInputStream("report.xsd"), Report.class).getValue();
The unmarshaller generates a JAXBElement, from which you can extract the actual report class.
Hope this helps.
There are no properties on the bean you are trying to unmarshal. But more importantly, you are trying to deserialize your object from the XSD itself. The error message is a good indicator here:
unexpected element (uri:"http://www.w3.org/2001/XMLSchema", local:"schema")
JAXB is spitting out this error message because it is attempting to map the XSD's metadata to properties of your bean. Which of course, your bean doesn't actually have any. The next part of the error message indicates as much:
Expected elements are (none)
You need to define your Java Bean properly (put some properties on it!), and actually get an XML file that represents the serialized version of your bean.

Mapping JavaObject to Javabeans in declarative way

Edit1
I am not sure if the title is best for the problem so if any have some more orinted title please suggest
i am trying my hands on camel where i have to fetch some csv file from a file system and needs to convert it to xml format and place it on some other system
i am using camel for this and here is my sample POC code
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import com.poc.convertor.CSVConverterBean;
public class TestPOC {
public static void main(String args[]) throws Exception {
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:data/csv?noop=true").unmarshal().csv().bean(new CSVConverterBean(),"processCSVInvoice").to("file:data/csvoutput?fileName=test.xml").marshal("jaxb");
}
});
context.start();
Thread.sleep(1000);
context.stop();
}
}
In this approach camel csv unmarshaller will covert the csv file in to java list List<List<String>>
i have written a java converter CSVConverterBean which will iterate the list and set the values in the respective java objects being generated by jaxb 2.x , final object is being marshaled in to xml and file is being saved.
Everything is being working properly with only one issue , if in future there arises any request to change mapping we need to do the modification in CSVConverterBean and than this java file needs to be recompiled and need to be redistributed which we want to avoid.
my question is, Is there any way by which we can map the values from the java List being given by Camel to the respective java classes being generated by the JaxB so that the need to recompile java code can be avooided.
You can provide a "from-to" kind of configuration file to map the columns of your CSV data with your Bean properties, and code an algorithm to read that file and process the convertion.
You could do with a .properties file:
# mapping.properties
column0=propertyOne
column1=propertyTwo
For each column in your CSV, you get the value from the property file and find which property you should set the value on.
int columnIndex = 0;
for(String column : csvColumns) {
String property = findProperty(columnIndex);
reflectionUtil.setValue(object, property, column);
columnIndex++;
}
This may give you some hint.
Whenever your data changes, you will only need to change the property file, not the class.
Use Bruno's idea, but read the property names from the header row in the csv file.
I have solved this problem using dom4j.camel gave me back csv as list> and firstly i read the headers and than made these headers and the XML tags and the values as there respected values on run time.

XML unmarshalling with Castor and Grails

I have a grails project that contains a few domain objects. I am using a java project in this code which can parse a document for me. The controller that calls that Java project is using JAXB to generate XML from the object returned by the Java project.
I want to use this XML document (which is generated after some text parsing, using JAXB) to populate my Domain classes in my grails project. How does this work in grails? Can I use something like Castor, and create a mapping using the names of my groovy classes? The idea is I want to generate new entries in the database and save it for the user based on whatever text was parsed out of the document they uploaded.
How does this even work in grails anyway? Can I create a new Domain object from another object's controller with something like
Project p = new Project();
and then do a p.save()?
Download the Castor Core and Castor XML jars from here and put them in the lib directory (there's probably a better way to manage this dependency using Grails' dependency management, but this one's a quick and dirty).
With Castor introspection mode you don't need to worry about creating mapping files if your XML matches up nicely with your domains. Here's an example:
grails-app/domain/MyDomain.groovy
class MyDomain {
String foo
String bar
}
grails-app/controllers/MyController.groovy
import org.exolab.castor.xml.Unmarshaller
import java.io.ByteArrayInputStream
class MyController {
def myAction = {
def xml = '''
<myDomain>
<foo>My Foo String</foo>
<bar>My Bar String</bar>
</myDomain>
'''
def reader = new ByteArrayInputStream(xml.bytes).newReader()
def domain = (MyDomain)Unmarshaller.unmarshal(MyDomain.class, reader)
domain.save()
def count = MyDomain.countByFoo('My Foo String')
render "Found $count results"
}
}
Navigate to localhost:8080/appname/my/myAction and it should display "Found N results", N > 0.

Categories

Resources