I am working on an API that will return an JSON response from an XML source. I have used RestTemplate and JAXB to get the XML string from the source and then used StringReader and Unmarshaller to create the Java object. The object looks like this;
#XmlRootElement(name="ItemSearchResponse", namespace="http://webservices.amazon.com/AWSECommerceService/2011-08-01") //
#XmlAccessorType(XmlAccessType.FIELD)
public class SampleXML {
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType
public static class OperationRequest {
#XmlTransient
private String RequestId;
#XmlElement(name="RequestId")
public void setRequestId(String id) {
this.RequestId = id;
}
public String getRequestId() {
return RequestId;
}
...
This is the code that should return the JSON string to the browser;
#RequestMapping("/samplexml2")
public SampleXML CreateXMLFile2 () throws EncoderException, FileNotFoundException, SAXException {
try {
String requestUrl = null;
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new ResponseErrorHandler());
String decodedUrl = "http://localhost:8080/sample.xml";
String response = restTemplate.getForObject(decodedUrl, String.class);
//Prepare JAXB objects
JAXBContext jaxbContext = JAXBContext.newInstance(SampleXML.class);
Unmarshaller u = jaxbContext.createUnmarshaller();
//Create an XMLReader to use with our filter
XMLReader reader = XMLReaderFactory.createXMLReader();
//Create the filter (to add namespace) and set the xmlReader as its parent.
NamespaceFilter inFilter = new NamespaceFilter("http://webservices.amazon.com/AWSECommerceService/2011-08-01", true);
inFilter.setParent(reader);
//Prepare the input, in this case a java.io.File (output)
InputSource is = new InputSource(new StringReader(response));
//Create a SAXSource specifying the filter
SAXSource source = new SAXSource(inFilter, is);
//Do unmarshalling
SampleXML myJaxbObject = (SampleXML) u.unmarshal(source);
//Convert to myJaxbObject to JSON string here;
return myJaxbObject;
} catch (JAXBException e) {
e.printStackTrace();
return null;
}
}
I want to write the conversation at this line; //Convert to myJaxbObject to JSON string here;
I have read many articles that point to this library; https://github.com/FasterXML/jackson-module-jaxb-annotations But I have not been able to use it successfully.
I would like an example that uses Jackson or MOXy dependencies
Have you tried simply changing your RequestMapping to #RequestMapping(value = "/samplexml2", produces = MediaType.APPLICATION_JSON_VALUE)?
Related
I want to convert XMLStreamReader object to StreamSource object so that I can apply XSD validation. Can any one help me to convert this.
public XMLStreamReader getStreamReader(InputStream inputStream) {
try {
XMLInputFactory xif = XMLInputFactory.newInstance();
return new XmlStreamReaderDelegate(xif.createXMLStreamReader(inputStream, "UTF-8"));
} catch (XMLStreamException e) {
//logger.info(XmlValidatorSettings.class,e.getMessage(),e.getMessage());
throw new UnmarshallingException(e);
}
}
I need to call this method to validate the XML against XSD.
public List<SAXParseException> validateSrcXmlAgainstSchema(Source xmlFile, String schemaFilePath) throws SAXException, IOException {
List<SAXParseException> exceptions = new LinkedList<SAXParseException>();
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new File(schemaFilePath));
// logger.debug("Schema Initialised for Schema located in : " + schemaFilePath);
XmlValidationExceptionHandler validationErrorHandler = new XmlValidationExceptionHandler();
Validator validator = schema.newValidator();
validator.setErrorHandler(validationErrorHandler);
// logger.debug("START - validate xml against schema ");
validator.validate(xmlFile);
// logger.debug("END - validate xml against schema ");
exceptions = validationErrorHandler.getExceptionList();
return exceptions;
}
XmlStreamReaderDelegate class used to avoid XML case-sensitive issue.
public class XmlStreamReaderDelegate extends StreamReaderDelegate {
public XmlStreamReaderDelegate(XMLStreamReader xsr) {
super(xsr);
}
#Override
public String getAttributeLocalName(int index) {
return super.getAttributeLocalName(index).toLowerCase().intern();
}
#Override
public String getLocalName() {
return super.getLocalName().toLowerCase().intern();
}
}
I'm using Jaxb to unmarshal XML into a java object. I need to know when new attributes/elements are in the XML and fail. However by default the unmarshaller is ignoring new elements/attributes.
Is there a configuration I can set to fail when new attributes/elements exist in the XML that are not specified in the POJO?
My POJO:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "ROOT")
public class Model {
private A a;
public A getA() {
return a;
}
#XmlElement(name = "A")
public void setA(A a) {
this.a = a;
}
static class A {
String country;
public String getCountry() {
return country;
}
#XmlAttribute(name = "Country")
public void setCountry(String country) {
this.country = country;
}
}
}
Code to unmarshal:
JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
String sample = "<ROOT>" +
"<A Country=\"0\" NewAttribute=\"0\"></A>" +
"<NEWELEMENT> </NEWELEMENT>" +
"</ROOT>";
InputStream stream = new ByteArrayInputStream(sample.getBytes(StandardCharsets.UTF_8));
Object unmarshal = jaxbUnmarshaller.unmarshal(stream);
You need to call Unmarshaller.setEventHandler() to make invalid XML content fail.
You can block unexpected content by enabling XML Schema validation on the Unmarshaller. If you don't already have an XML Schema for your POJO, you can generate one at runtime from the JAXBContext, build a Schema object and then set it on the Unmarshaller. By default the Unmarshaller will throw an exception if the XML document isn't valid with respect to the schema.
Here's an example of how to do that:
JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);
// Generate XML Schema from the JAXBContext
final List<ByteArrayOutputStream> schemaDocs = new ArrayList<ByteArrayOutputStream>();
jaxbContext.generateSchema(new SchemaOutputResolver() {
#Override
public Result createOutput(String namespaceUri, String suggestedFileName)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
StreamResult sr = new StreamResult(baos);
schemaDocs.add(baos);
sr.setSystemId(suggestedFileName);
return sr;
}
});
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
int size = schemaDocs.size();
Source[] schemaSources = new Source[size];
for (int i = 0; i < size; ++i) {
schemaSources[i] = new StreamSource(
new ByteArrayInputStream(schemaDocs.get(i).toByteArray()));
}
Schema s = sf.newSchema(schemaSources);
// Set the JAXP Schema object on your Unmarshaller.
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jaxbUnmarshaller.setSchema(s);
String sample = "<ROOT>" +
"<A Country=\"0\" NewAttribute=\"0\"></A>" +
"<NEWELEMENT> </NEWELEMENT>" +
"</ROOT>";
InputStream stream = new ByteArrayInputStream(sample.getBytes("UTF-8"));
Object unmarshal = jaxbUnmarshaller.unmarshal(stream);
Combine this with the ValidationEventHandler (set through Unmarshaller.setEventHandler()) suggested in the previous answer if you wish to be notified about multiple errors or filter out validation errors that you want to tolerate.
I'm trying to write a method to pretty print JSON Strings, using MOXy. So what I want is to have a method like this
public String formatJson(String input) { ... }
I think the way to go is to parse the String to a generic Object (Something like a SAX-Document, or the kind), and then marshal this Object back to JSON using some formatting properties (which is not the problem :-) ).
The Problem is, when reading the JSON-String-Input, I don't have a Class to unmarshal to (as I want the method to be as generic as possible).
[edited] GSON and Jackson examples removed, as only MOXy is the question.
I tried this:
public static String toFormattedJson(final String jsonString) {
String formatted;
try {
JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] { JAXBElement.class }, null);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setProperty(MEDIA_TYPE, MediaType.APPLICATION_JSON);
unmarshaller.setProperty(JSON_INCLUDE_ROOT, true);
StringReader reader = new StringReader(jsonString);
Object element = unmarshaller.unmarshal(reader); // Exception is thrown here
formatted = toFormattedJson(element);
} catch (final JAXBException e) {
formatted = jsonString;
}
return formatted;
}
but I get an this Exception
javax.xml.bind.UnmarshalException
- with linked exception:
[java.lang.ClassCastException: org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler cannot be cast to org.eclipse.persistence.internal.oxm.record.UnmarshalRecord]
So how can I read an arbitrary JSON String in to a Java Object, if I don't have any Class for that specific String?
Update:
This is the method used to format an Object into a JSON String:
private static String toFormattedJson(Object obj) {
String result;
try (StringWriter writer = new StringWriter()) {
final JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] { obj.getClass() }, null);
final Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
marshaller.setProperty(MarshallerProperties.JSON_REDUCE_ANY_ARRAYS, false);
marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
marshaller.setProperty(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, false);
marshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, true);
marshaller.marshal(obj, writer);
writer.flush();
result = writer.toString();
} catch (JAXBException | IOException e) {
result = obj.toString();
}
return result;
}
And using now the code from below (Martin Vojtek), when I try to format
String jsonString = "{\"p\" : [ 1, 2, 3]}";
I get:
{
"p" : "1"
}
You can specify String as the unmarshal target:
public static void main(String[] args) {
System.out.println(toFormattedJson("[{\"test\":true}, \"ok\", [\"inner\",1]]"));
}
public static String toFormattedJson(final String jsonString) {
String formatted;
try {
JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] { JAXBElement.class }, null);
System.out.println("jaxbContext="+jaxbContext);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
unmarshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, true);
StringReader reader = new StringReader(jsonString);
Object element = unmarshaller.unmarshal(new StreamSource(reader), String.class);
formatted = toFormattedJsonElement(element);
} catch (final JAXBException e) {
e.printStackTrace();
formatted = jsonString;
}
return formatted;
}
private static String toFormattedJsonElement(Object element) {
return "formatted: " + element;
}
I am newbie in JAVA programming and trying to convert XML to JAVA using the below snipet.
Input File:
<?xml version="1.0" encoding="UTF-8"?>
-<ns0:MT_ECCJDBC xmlns:ns0="urn:xml:json">
-<REQUEST>
<ID>46565665</ID>
</REQUEST>
</ns0:MT_ECCJDBC>
The output :
{
"#xmlns:ns0": "urn:xml:json",
"REQUEST": ["46565665"]
}
The expected output in JSON is
{
"REQUEST":
{
" ID " : ["46565665"]
}
}
Below is my java code :
public class ConversionXMLtoJSON {
public static void main(String[] args) throws Exception {
{
InputStream is = ConversionXMLtoJSON.class.getResourceAsStream("instance.xml");
String xml = IOUtils.toString(is);
XMLSerializer xmlSerializer = new XMLSerializer();
JSON json = xmlSerializer.read( xml );
System.out.println( json.toString(2) );
}
}
}
Please suggest me to add in the code
To remove the tag "#xmlns:ns0": "urn:xml:json",
To add the ID element in the JAVA code.
Regards
You can map the XML into Java objects and then use JSON generator to generate the JSON. I like to use jackson-mapper-asl, jackson-core-asl and jackson-dataformat-xml.
To bind the XML to Java:
public class XmlRequest {
#JacksonXmlElementWrapper(localName="REQUEST")
private REQUEST request;
public static class REQUEST {
#JacksonXmlProperty(localName="ID")
protected int ID;
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
}
public REQUEST getRequest() {
return request;
}
public void setRequest(REQUEST request) {
this.request = request;
}
}
To Generate the JSON:
XmlMapper mapper = new XmlMapper();
XmlRequest request = (XmlRequest) mapper.readValue(App.class.getResourceAsStream("/NewFile.xml"), XmlRequest.class);
StringWriter sw = new StringWriter();
JsonGenerator jsongen = new JsonFactory().createJsonGenerator(System.out);
jsongen.writeStartObject();
jsongen.writeFieldName("REQUEST");
jsongen.writeStartObject();
jsongen.writeFieldName("ID");
jsongen.writeStartArray();
jsongen.writeNumber(request.getRequest().getID());
jsongen.writeEndArray();
jsongen.writeEndObject();
jsongen.writeEndObject();
jsongen.close();
I am trying to generate XSD from Java Annotated classes by following code mentioned in this post Is it possible to generate a XSD from a JAXB-annotated class
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
SchemaOutputResolver sor = new MySchemaOutputResolver();
jaxbContext.generateSchema(sor);
public class MySchemaOutputResolver extends SchemaOutputResolver {
public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException {
File file = new File(suggestedFileName);
StreamResult result = new StreamResult(file);
result.setSystemId(file.toURI().toURL().toString());
return result;
}
}
This technique is using File system, My requirement is to get the XML as String without using file system.
Is there any possibility the Implementation of SchemaOutputResolver may not write file to disk and return or set some instance variable with the String value.
You can write the StreamResult on a StringWriter and get the string from that.
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
MySchemaOutputResolver sor = new MySchemaOutputResolver();
jaxbContext.generateSchema(sor);
String schema = sor.getSchema();
public class MySchemaOutputResolver extends SchemaOutputResolver {
private StringWriter stringWriter = new StringWriter();
public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException {
StreamResult result = new StreamResult(stringWriter);
result.setSystemId(suggestedFileName);
return result;
}
public String getSchema() {
return stringWriter.toString();
}
}