Multiple marshallers/unmarshallers with Spring OXM - java

I have a legacy web service project that receives two different XML schemas, but with the same attribute name (including the root element). I'm using Spring, OXM and JAXB2 for marshalling/unmarshalling.
I've solved a previous issue with another question, so I use SAX parser to determine which unmarshaller to use. When a XML is parsed, I check a value and then I can use an unmarshaller or other unmarshaller.
My problem comes when I try to define marshallers/unmarhsallers with Spring OXM. If I set the classpath with two packages, it fails beacause unmarshaller finds two classes with the same XMLRootElement. If I set a list of class-to-be-bound it fails too beacause unmarshaller always unmarshall to the last item in the class list (same XMLRootElement, unmarshaller doesn't know which class to unmarshall).
But It works correctly If I use JaxbContext:
JAXBContext jc = JAXBContext.newInstance(MyClass1.class);
myClass1Object = (MyClass1) jc.createUnmarshaller().unmarshal(new StreamSource(new StringReader(xml)));
And
JAXBContext jc = JAXBContext.newInstance(MyClass2.class);
myClass2Object = (MyClass2) jc.createUnmarshaller().unmarshal(new StreamSource(new StringReader(xml)));
How can I transform this to a more Spring (OXM) approach?

First of all I tried to declare the JAXBContext instance in the application context file, but finally I went for changing the namespace of one XML schema. Now I'm using Spring OXM to marshall/unmarshall my two XML schemas without any problem.

Related

JAXB validation - difference between jaxb 1.0 vs jaxb 2.0

In Jaxb 1.0 the xml validation is turned on by calling 'setValidating' on unmarshaller object:
JAXBContext jaxbContext = JAXBContext.newInstance(packageName);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setValidating(true);
In Jaxb 2.0 the validation is enhanced and setting up a schema is required:
Schema schema = schemaFactory.newSchema(file);
unmarshaller.setSchema(schema);
Looks like to use JAXB 2.0 validation the schema xsd file is a neccessary, requisite resource that must be provided in the application context.
While in JAXB 1.0 to turn on validation the schema file is not required (at least explicitly)
Question 1:
Does JAXB 1.0 really stores validation capabilities in its implementation (which comes from xjc) and xsd file is not required in the app/package/classpath runtime context?
Question 2:
In JAXB 2.0 is it possible to 'unsetSchema' for the unmarshaller - just give up validation (for performance purposes ... when I see that incoming xml payload is the same like the one I already validated earlier)?
Answer to question #2:
To turn off unmarshaller validation it is enough to reset schema to null:
unmarshaller.setSchema(null);
Question #1 remains open:
Does JAXB 2.0 need a schema file to be provided at runtime to perform validation during marshalling/unmarshalling ? ... or maybe we can force xjc complier with some options (like -nv) to generate implementation that has validation capabilities like JAXB 1.0 used to have. (just not to disclose xsd schema)

Validating an xml against xsd that was used to generate Beans

I generate some beans from a couple of xsd via ant-build.
When unmarshalling an xml, I would like to validate that one. As far as I know, there is now way to do this with the beans themself, one has to do something like this:
JAXBContext context = JAXBContext.newInstance(Bean.class);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("whatever.xsd"));
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setSchema(schema);
unmarshaller.setEventHandler(validationHandler);
return (Bean) unmarshaller.unmarshal(givenXmlString);
My problem is that new File("whatever.xsd"). I don't want to hardcode an URL to the xsd, that might change later (i.e. by refactoring the project) and will break at runtime, because one forgot (or didn't know) to change that url.
Idea:
The only idea I have for that is to copy the xsd to the same folder as the generated beans and to use the packagename of one bean to generate the url at runtime.
Any better ideas?
Instead of sf.newSchema(File) you can use sf.newSchema(Source[]) with one of the javax.xml.transform.Source implementations, e.g. javax.xml.transform.stream.StreamSource.

Prevent parsing XML files containing DTD using Jaxb2Marshaller

I saw many solutions using XMLInputFactory, SAXParser and DocumentBuilderFactory. Our project is spring web service and the only thing we do is:
#Bean
public Jaxb2Marshaller unmarshaller() {
Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
unmarshaller.setContextPath("foo");
unmarshaller.setProcessExternalEntities(false);
return unmarshaller;
}
And then we pass this marshaller and unmarshaller to MarshallingPayloadMethodProcessor. So my question is if there is some property for Jaxb2Marshaller that will prevent DTD. Something like: unmarshaller.setProperty(foo.SUPPORT_DTD, false);
We have .xsd schema but in case of xml bomb the entity needs to be exanded for purpose of validation, so it seems like this is not the solution.
As far as I can see from the code, this must be the default behaviour.
In the JAXB RI there is a context property com.sun.xml.bind.disableXmlSecurity which is reasonably set to false by default. JAXB RI the uses this property when it creates the parser. So, at the end it configures the FEATURE_SECURE_PROCESSING feature of the parser:
SAXParserFactory factory = SAXParserFactory.newInstance();
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "SAXParserFactory instance: {0}", factory);
}
factory.setNamespaceAware(true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !isXMLSecurityDisabled(disableSecureProcessing));
return factory;
You can also use the system property javax.xml.accessExternalDTD.
See also this answer:
How to disable DTD fetching using JAXB2.0
If you want to make it ever more secure, you may write and configure your own entity resolver.

MOXy/JAXB annotations are being ignored on weblogic 12c

For some reason weblogic 12c (Eclipse link 2.4.2) seems to be ignoring all my annotations.
For example, classes being marshalled have the following annotation tag but the default accessor type is still being used.
#XmlAccessorType(XmlAccessType.FIELD)
Fields with the following annotation are also not being ignored:
#XmlTransient
I'm not sure what I am doing wrong. I have the jaxb.properties file in the correct package along with my marshaller looking similar to the following:
final JAXBContext jaxbContext = JAXBContext.newInstance(MappingProfiles.class);
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(mappingProfiles, baos);
This scenario definitely works (As MOXy lead I would have been fired if it didn't). Is there a chance you are including the JAXB API classes in what you are deploying to WebLogic?

Suppress prolog from XML during marshalling

I am using Mule XML module jaxb-object-to-xml-transformer to convert my object to XML. Then this XML is embedded into another XML using templates.
But the issue here is the object to XML transformer is giving an XML output with prolog:
<?xml version="1.0" encoding="UTF-8"?>
I need an XML without this. So that it can be embedded into another template without issues.
<flow name="main.flow">
....
....
<mule-xml:jaxb-object-to-xml-transformer name="obj2xml" jaxbContext-ref="myJaxbContext" returnClass="java.lang.String" />
<custom-transformer ..... >
....
....
</flow>
In plain JAXB there is a way to do this. But in Mule XML module I couldn't find any property to do this. Please advise if there is any property to achieve this behaviour.
The documentation indicates that you can intercept JAXB transforms (see: http://www.mulesoft.org/documentation/display/current/JAXB+Bindings). The following example is taken from that documentation.
#Transformer(sourceTypes = {String.class, InputStream.class})
public Person toPerson(Document doc, JAXBContext context) throws JAXBException
{
return (Person) context.createUnmarshaller().unmarshal(doc);
}
Assuming there is a corresponding thing you can do for marshalling you would be able to set the necessary JAXB property.
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);

Categories