In our application, User is sending an XML like below:
<Decl>
<MessageHeader>
<A>Info</A>
<B>Info2</B>
</MessageHeader>
</Decl>
and using JABX unmarshller we are populating the java object.
But the problem is customer is asking to generate the error when he/she
send the message like below:
<Decl>
<MessageHeader>
<A>Info</A>
<B>Info2</B>
</MessageHeader>
<MessageHeader>
<A>Info3</A>
<B>Info4</B>
</MessageHeader>
</Decl>
JAXB is successfully unmarshling the xml and populating the object with second MessageHeader Object. Please note MessageHeader is not List type.
Is there any way to stop JAXB to behave like this and it should throw ParsingException. We cannot use schema validation of xml before parsing due to some reason. But is there any way that we can instruct JAXB parser to check target type is list or not and throw the error.
Thanks a lot in advance.
JAXB is a technology for generating Java classes for an XML Schema model. Therefore, any validation that JAXB performs is going to use XML Schema validation.
Is there any way to stop JAXB to behave like this and it should throw ParsingException
No. Not unless you enable schema validation in your JAXB unmarshaller.
We cannot use schema validation of xml before parsing due to some reason.
You should either supply the reason, or not mention it. It's a very strange rule, given that JAXB is an XML Schema technology and Java has native support for XSD validation.
Please note MessageHeader is not List type.
A List type is for simple types. MessageHeader is based on a complex type.
I recommend that you ignore the rule that says 'no schema validation'. Set maxOccurs=1 on MessageHeader and enable schema validation on the JAXB unmarshaller.
As already pointed out, the way to go is to use schema validation. Generate a schema and set maxOccurs="1" on MessageHeader. You can set the schema with:
unmarshaller.setSchema(schema);
If for some strange reason you absolutely cannot use schema validation you could do an ugly hack to throw an exception when a duplicated MessageHeader is processed with an implementation of Unmarshaller.Listener
unmarshaller.setListener(new Unmarshaller.Listener() {
boolean messageHeaderAlreadyPresent = false;
#Override
public void beforeUnmarshal(Object target, Object parent) {
// When <Decl> is encountered, set to false
if (target instanceof Decl) {
messageHeaderAlreadyPresent = false;
} else if (target instanceof MessageHeader) {
if (messageHeaderAlreadyPresent) {
throw new RuntimeException("duplicate MessageHeader");
}
messageHeaderAlreadyPresent = true;
}
}
});
Although this should work, I insist that you should reconsider schema validation.
Also note that the unmarshaller silently ignores some events, for example when encounters en element that is not mapped. That's not your case, because there is no mapping problem in your use case, but, for example if you received the message:
<Decl>
<MessageHeader>
<A>Info1</A>
<C>Info3</C>
</MessageHeader>
</Decl>
with element <C> instead of <B>, you would end up with values A = Info1 and B = null, as JAXB would silently ignore the element <C>.
You can capture these events and throw an exception setting a ValidationEventHandler to return false
unmarshaller.setEventHandler(new ValidationEventHandler() {
#Override
public boolean handleEvent(ValidationEvent event) {
// log event ....
return false;
}
});
Related
I have a webapp (Play framework 2.x, Java) that receives JSON payloads as input.
I have input payloads in different shapes like:
{
files: [{id: 1,name: null}}
requiredAttribute: null,
}
I want to output errors in this form, similar to the input:
{
files: [{name: "name can't be null"}}
requiredAttribute: "requiredAttribute can't be null",
}
I'd like to know how I can output errors in this form with Java without too much pain.
I know I'll loose the ability to output multiple errors per field and I'm fine with that.
I'm ok using any external library as long as it's easy to declare the constraints on the fields, so using something like Java validation and validation constraints annotations would be nice. But I wasn't able to find any support for this kind of stuff so far. Any idea how it could be done with Play or Java validation or Jackson?
Using bean validation, you can achieve this by calling validate() yourself and processing a collection of Set<ConstraintViolation<T>>.
You first need to get a Validator object. There may be ways to do this better, but one way is to use the factory (used this in the past, it worked with a Hibernate validator dependency on the class path):
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Then use the validator to retrieve a set of constraint violations (Assuming a generic type T for a bean class with the relevant constraint annotations):
Set<ConstraintViolation<T>> constraintViolations = validator.validate(myBean);
Map<String, String> fieldErrors = new HashMap<>();
for (ConstraintViolation<T> violation : constraintViolations) {
String message = violation.getMessage();
String field = violation.getPropertyPath().toString();
fieldErrors.put(field, message);
}
Note that for nested bean classes, you'll get a dot-separated "path" for field names.
I have an application that receives a JSON and upon receiving it should validate it. The validation is consisted out of several steps.
If the received object is a properly formatted JSON
If all the required fields are present
If all the fields constraints are satisfied (ie. string sizes)
If the conditional dependencies are satisfied (if some field has value A, then another field should have value B)
Based on the described requirements, if any of the constraints is violated, I should generate my own, specifically formatted, validation report object.
I have considered several ways how to do this, but I am not really happy with any, and hoping to get an advice from you guys, how this could be done. What I have considered:
Idea #1: Jackson + JSR303 bean validation
#CustomConstraintIfAThenB // this should emulate the conditional dependency
public class Message {
#JsonProperty(value = "a", required = true)
#Size(min = 3, max = 8)
private String a;
#JsonProperty(value = "b", required = true)
#Size(min = 5, max = 9)
private String b;
// ...
}
The problem I found with this approach is when generating my report, because first I need to use the Jackson's ObjectMapper to try to create my POJO. If this throws JsonProcessingException I should parse it, and create my report. If doesn't throw, only then I can validate with my bean validator (ie. Hibernate).
MyReport report = null;
Message m = null;
// first Jackson validation
try {
m = objectMapper.treeToValue(json, Message.class);
} catch (JsonProcessingException e) {
report = myExceptionParser.parse(e);
}
// second bean (field) validation
Set<ConstraintViolation<Message>> violations = validator.validate(m);
if (violations.size() > 0) {
report = myViolationsParser.parse(violations);
}
Big problem with this is the actual parsing through the JsonProcessingException to create my custom report. And additionally parse through the violations. I should write two parsers, one of which (the one that parses the exception) would probably be extremely clumsey.
Idea #2: Validation against JSON schema
I could write a JSON schema and then validate an incoming JSON against that schema. The up side for this is that I would have a unique, consistent report generated by the JSON Schema Validator I am using, and I should only write one parser for it. For example if I were to use fge-validator:
JsonSchema schema = JsonSchemaFactory.byDefault().getJsonSchema(mySchema);
ProcessingReport report = mySchema.validate(json);
// only have one parser to parse the report to my custom report
MyReport = myReportParser.parse(report);
The problem is with this that JSON Schema v4 gets very clumsy when dealing with conditional dependencies, as there are no IF-THEN-ELSE keywords. And I couldn't find a library that would support JSON Schema v7. Also, modifying a large JSON Schema can get tricky and very prone to errors. In that context also, class annotations would be better.
Is there any 3rd way to do the JSON validation and create a custom report out of it, that is moderately elegant and not clumsy as writing two parsers (one of which parses the exception)?
Please also note that my JSON files can easily have 200+ fields, so writing a custom deserializer field-by-field is probably not an option.
I would like to get some advises on this, as I can't really find a reasonable way to do this.
I am getting a XML response and it keeps on changing very frequently (nodes keep on increasing or reducing). After each updation in response xml my code breaks as my mapped Java class does not have all fileds.
Is there any way to avoid my code breaking if any changes occurs in response XML.
Any help will be appreciated.
Thanks.
Use JAXB.unmarshal() to simply create Java objects from XML.
By default it is very liberal.
Quoting from the javadoc:
In addition, the unmarshal methods have the following characteristic:
Schema validation is not performed on the input XML. The processing will try to continue even if there are errors in the XML, as much as possible. Only as the last resort, this method fails with DataBindingException.
So what JAXB.unmarshal() does is it tries to "transfer" as much data from XML to Java as possible, and it doesn't care if there is no Java field for an XML element or attribute, and it also doesn't care if there is a Java field for which there is no XML element or attribute.
Example
Let's try to unmarshal the following XML to an instance of java.awt.Point:
<p hi="Yo">
<y>123</y>
<peach>weor</peach>
</p>
The Java code:
String s = "<p hi=\"Yo\"><y>123</y><peach>weor</peach></p>";
Point p = JAXB.unmarshal(new StringReader(s), Point.class);
System.out.println(p); // Prints "java.awt.Point[x=0,y=123]"
We told JAXB.unmarshal() to parse a java.awt.Point instance. The input XML contains an element <y> which can be matched with Point.y so an int was parsed and set to Point.y. No XML data was found for Point.x so it was not touched. There were no match for the attribute hi and the XML element <peach>, so they were simply not used for anything.
We got absolutely no Exception here, and the most that was possible was parsed and transferred from XML to Java.
To cope with unknown fields, you can add a List<Object> property annotated #XmlAnyElement(lax=true)
#XmlAnyElement(lax = true)
private List<Object> anything;
Any elements in the input that do not correspond to explicit properties of the class will be swept up into this list. If the element is known to the JAXBContext you'll get the unmarshalled form (the #XmlRootElement annotated class or a JAXBElement<Foo>), if the element is not known to the context you'll get an org.w3c.dom.Element.
Full details in Blaise's blog.
For nodes that get removed you should be fine as long as you use types that can be null (Integer rather than int, Boolean rather than boolean, etc).
I have the following requirement:
I have a validation system. One of the things that I need to do is perform validations on XML files, meaning validating that tag X equals a given value. I have more than one possible scenario, and in each scenario there is a different set of tags that need to be validated.
I don't want to repeat same code when testing same tags in different scenarios.
I'm trying to figure out a design that will solve this issue.
Any ideas?
Thanks.
I'd define pairs of XPath expressions and expected results for the scenarios.
The validator then would take a scenario (object), compile and apply the associated expressions to the xml document. This would select an element and the validator would check, if the element's content matches the expected value.
Erm, delegate to a shared method? Like:
void validateAppleScenario(Xml xml) {
validateFruit(xml);
// validate apples specific tags
}
void validateBanana(Xml xml) {
validateFruit(xml);
// validate banana specific tags
}
void validateFruit(Xml xml) {
// validate tags common to all fruit
}
Or if you prefer validators to be seperate objects, you can use subtyping:
interface Validator {
void validate(Xml xml);
}
class FruitValidator implements Validator {
void validate(Xml xml) {
// validate tags common to all fruit
}
}
class AppleValidator extends FruitValidator {
void validate(Xml xml) {
super.validate(xml);
// validate tags specific to apples
}
}
One approach would be to parse the XML into an object and then validate it in accordance with Bean Validation spec (JSR 303). Hibernate Validator is the reference implementation.* You can annotate your properties with validation constraints, and then specify validation groups so that certain fields get validated in certain scenarios.
There is more info here and here.
*Hibernate Validator is different from Hibernate ORM. They're only related in that Hibernate ORM uses Validator for its constraint checking.
The Problem I'm facing is how to marshall a large list of objects into a single XML File, so large I can not marshall the complete list in one step. I have a method that returns these objects in chunks, but then I marshall these using JAXB, the marshaller returns with an exception that these objects are no root elements. This is ok for the normal case there you want to marshall the complete document in one step, but it also happens if I set the JAXB_FRAGMENT Property to true.
This is the desired XML output:
<rootElem>
<startDescription></startDescription>
<repeatingElem></repeatingElem>
<repeatingElem></repeatingElem>...
</rootElem>
So I assume I need some kind of listener that dynamically loads the next chunk of repeatingElements to feed it to the marshaller before he would write the closing tag of the rootElement. But how to do that? Up until now I only used JAXB to marshall small files and the JAXB documentation does not give much hints for that use case.
I'm aware that this is an old question but I came across it while searching for duplicates of another similar question.
As #skaffman suggests, you want to Marshal with JAXB_FRAGMENT enabled and your objects wrapped in JAXBElement. You then repeatedly marshal each individual instance of the repeated element. Basically it sounds like you want something roughly like this:
public class StreamingMarshal<T>
{
private XMLStreamWriter xmlOut;
private Marshaller marshaller;
private final Class<T> type;
public StreamingMarshal(Class<T> type) throws JAXBException
{
this.type = type;
JAXBContext context = JAXBContext.newInstance(type);
this.marshaller = context.createMarshaller();
this.marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
}
public void open(String filename) throws XMLStreamException, IOException
{
xmlOut = XMLOutputFactory.newFactory().createXMLStreamWriter(new FileOutputStream(filename));
xmlOut.writeStartDocument();
xmlOut.writeStartElement("rootElement");
}
public void write(T t) throws JAXBException
{
JAXBElement<T> element = new JAXBElement<T>(QName.valueOf(type.getSimpleName()), type, t);
marshaller.marshal(element, xmlOut);
}
public void close() throws XMLStreamException
{
xmlOut.writeEndDocument();
xmlOut.close();
}
}
As you've discovered, if a class does not have the #XmlRootElement annotation, then you can't pass an instance of that class to the marshaller. However, there is an easy way around this - wrap the object in a JAXBElement, and pass that to the marshaller instead.
Now JAXBElement is a rather clumsy beast, but what it does is contains the element name and namespace of the object that you want to marshal, information which would normally be contained in the #XmlRootElement annotation. As long as you have the name and namespace, you can construct a JAXBElement to wrap your POJO, and marshal that.
If your POJOs were generated by XJC, then it will also have generated an ObjectFactory class which contains factory methods for building JAXBElement wrappers for you, making things a bit easier.
You'll still have to use the JAXB_FRAGMENT property for the repeating inner elements, otherwise JAXB will generate stuff like the XML prolog each time, which you don't want.
I don't know much of JAXB, so I can't help. But if you don't mind, I have a suggestion.
Writing XML is a lot easier than reading it, so an solution for your problem might be to use a more "low level" approach. Just write your own marshaller using one of the available open source libraries for XML. I think you can easily do what you want using dom4j.