How to add suffix to XmlRootElement - java

I've tried this:
package-info.java
#XmlSchema(xmlns=
{
#XmlNs(prefix="Person", namespaceURI="sample.url.something"),
#XmlNs(prefix="xsi", namespaceURI="http://www.w3.org/2001/XMLSchema-instance")
})
Java
#XmlRootElement(name = "Person:sampleData")
public class Person {
private static String path = "files/test.xml";
#XmlElement()
public String Name;
#XmlElement()
public int Age;
public Person(){}
public Person(String name, int age){
this.Name = name;
this.Age = age;
}
public static String PersonToXMLString(Person person) throws JAXBException
{
JAXBContext jc = JAXBContext.newInstance(Person.class);
StringWriter sw = new StringWriter();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "somelocation.xsd");
marshaller.marshal(person, sw);
return sw.toString();
}
public static Person XMLStringToPerson() throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Person Person = (Person) unmarshaller.unmarshal(new File(path));
return Person;
}
public static void WriteXMLStringFile(String xml) throws IOException
{
File file = new File(path);
try (FileOutputStream fop = new FileOutputStream(file)) {
if (!file.exists()) {
file.createNewFile();
}
byte[] contentInBytes = xml.getBytes();
fop.write(contentInBytes);
fop.flush();
fop.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String ReadXmlStringFromFile() throws IOException
{
BufferedReader br = new BufferedReader(new FileReader(new File(path)));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line.trim());
}
return sb.toString();
}
public static void main(String[] args) throws JAXBException, IOException
{
Person user = new Person("User",23);
String xml = user.PersonToXMLString(user);
System.out.println(xml);
user.WriteXMLStringFile(xml);
xml = user.ReadXmlStringFromFile();
//used to unmarshall xml to Person object
Person person = user.XMLStringToPerson();
System.out.println(person.Name);
}
}
XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Person:sampleData xmlns:Person="sample.url.something" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>User</Name>
<Age>23</Age>
</Person:sampleData>
If i do something like this i get exception on unmarshalling:
Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"sample.url.something", local:"sampleData").
Expected elements are <{}Person:sampleData>`
FYI: I can not modify the XML.
Any help gratefully received!

You can do the following:
package-info.java
Your #XmlSchema annotation should look something like the following on your package-info class. Since elementFormDefault is specified as UNQUALIFIED the namespace will only be applied to global elements (in JAXB those corresponding to the #XmlRootElement). Note a JAXB impl is not required to use the prefix included in the #XmlSchema when marshalling XML.
#XmlSchema(
elementFormDefault=XmlNsForm.UNQUALIFIED,
namespace="sample.url.something",
xmlns={
#XmlNs(prefix="Person", namespaceURI="sample.url.something")
}
)
package com.example;
import javax.xml.bind.annotation.*;
Person
The #XmlRootElement annotation should not include the prefix.
package com.example;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="sampleData")
public class Person {
For More Information
You can read more about controlling namespace prefixes in JAXB on my blog:
http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html

Related

JAXB marshalling with nested tags

I am creating XML files using JAXB based on the XSD template generated classes.
But the XML output is not expected one.
public class ProcessXMLService {
public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance("com.ford.xml.poc");
StringBuilder xmlSB = new StringBuilder();
try {
FileWriter out = new FileWriter("C:\\gopal\\sales.xml");
int count=0;
while(count<2){
StringWriter xmlStr = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output",Boolean.FALSE);
marshaller.marshal(getMSGBody("DONE"), xmlStr);
xmlSB.append(xmlStr.toString()+"\n");
count++;
}
out.write(xmlSB.toString());
out.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
static JAXBElement<MessageBodyType> getMSGBody(String serviceName){
ObjectFactory factory = new ObjectFactory();
RequestInfoType reqInfoType = factory.createRequestInfoType();
reqInfoType.setRequesterName("ETL Sales");
reqInfoType.setRequestId("123");
//JAXBElement<RequestInfoType> reqInfoJaxB = factory.createRequestInfo(reqInfoType);
SalesDataType saleDataType = factory.createSalesDataType();
saleDataType.setGlobalSourceRecordId("c0a460e0-60aa-4bd5-9155-5645b4afe1de");// Update GSRID
//JAXBElement<SalesDataType> saleDataJaxB = factory.createSaleData(saleDataType);
MessageBodyType msgBdType = factory.createMessageBodyType();
msgBdType.setRequestInfo(reqInfoType);
msgBdType.getSaleData().add(saleDataType);
JAXBElement<MessageBodyType> msgBd = factory.createMessageBody(msgBdType);
return msgBd;
}
}
Getting the below XML output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:MessageBody
xmlns:ns2="urn:ford/identifier/v1.0"
xmlns:ns4="urn:ford/Consumer/Sales/v1.0"
xmlns:ns3="urn:ford/crfcommon/v1.0">
<ns3:RequestInfo>
<RequestId>123</RequestId>
<RequesterName>ETL Sales</RequesterName>
</ns3:RequestInfo>
<SaleData>
<ns2:GlobalSourceRecordId>c0a460e0-60aa-4bd5-9155-5645b4afe1de</ns2:GlobalSourceRecordId>
</SaleData>
</ns4:MessageBody>
But expected XML output is :
<?xml version="1.0" encoding="UTF-8"?>
<tns:MessageBody
xmlns:tns="urn:ford/Consumer/Sales/v1.0">
<com:RequestInfo
xmlns:com="urn:ford/crfcommon/v1.0">
<com:RequestId>123</com:RequestId>
<com:RequesterName>ETL Sales</com:RequesterName>
</com:RequestInfo>
<tns:SaleData>
<ns1:GlobalSourceRecordId
xmlns:ns1="urn:ford/identifier/v1.0">c0a460e0-60aa-4bd5-9155-5645b4afe1de
</ns1:GlobalSourceRecordId>
</tns:SaleData>ns4:MessageBody>

escape characters (e.g. quotes) using JAXB Marshaller

I need use a XmlAdapter because I want do not have empty XLM object:
<TACHES>
<TACHE>
<NB_HEURE>7.75</NB_HEURE>
<NOTES>foo</NOTES>
<CODE_TACHE>1234</CODE_TACHE>
</TACHE>
<TACHE> <- I Want delete this part
<NB_HEURE/> <- I Want delete this part
<NOTES/> <- I Want delete this part
<CODE_TACHE/> <- I Want delete this part
</TACHE> <- I Want delete this part
</TACHES>
My POJO is:
#XmlRootElement(name = "TACHES")
public class Tasks {
private List<Task> tasks;
#XmlJavaTypeAdapter(TaskAdapter.class)
#XmlElement(name = "TACHE")
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
}
My XmlAdapter is:
public class TaskAdapter extends XmlAdapter<String, Task> {
#Override
public Task unmarshal(String v) throws Exception {
return null;
}
#Override
public String marshal(Task t) throws Exception {
JAXBContext context = JAXBContext.newInstance(Task.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_FRAGMENT, true);
m.setProperty("jaxb.encoding", "Unicode");
StringWriter sw = new StringWriter();
if ("".equals(t.getNotes()) && "".equals(t.getHourCount()) && "".equals(t.getTaskCode())) {
return null;
}
m.marshal(t, sw);
String s = sw.toString();
s = s.substring(s.indexOf("<TACHE>") + 7, s.indexOf("</TACHE>"));
System.out.println(s);
return s;
}
}
System.out.println of XmlAdapter print:
<NB_HEURE>7.75</NB_HEURE>
<NOTES>foo</NOTES>
<CODE_TACHE>1234</CODE_TACHE>
but, when I marshal global POJO, I have:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
...
<TACHES>
<TACHE>
<NB_HEURE>7.75</NB_HEURE>
<NOTES>foo</NOTES>
<CODE_TACHE>1234</CODE_TACHE>
</TACHE>
</TACHES>
...
My is:
JAXBContext context = JAXBContext.newInstance(MoReports.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
m.marshal(moReports, sw);
xmlString = sw.toString();
Step 1
I do not use 'TaskAdapter extends XmlAdapter'
Step 2
I set JAXB_FORMATTED_OUTPUT at FALSE
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
Step 3
and I add this code post marshal
xmlString = removeAllEmptyXmlTags(xmlString);
public String removeAllEmptyXmlTags(String xml) {
final String regex1 = "<([a-zA-Z0-9-\\_]*)[^>]*/>";
final String regex2 = "<([a-zA-Z0-9-\\_]*)[^>]*>\\s*</\\1>";
final Pattern pattern1 = Pattern.compile(regex1);
final Pattern pattern2 = Pattern.compile(regex2);
String xmlString = xml;
Matcher matcher1;
Matcher matcher2;
do {
xmlString = xmlString.replaceAll(regex1, "").replaceAll(regex2, "");
matcher1 = pattern1.matcher(xmlString);
matcher2 = pattern2.matcher(xmlString);
} while (matcher1.find() || matcher2.find());
return xmlString;
}
Step 4
and I add this code post marshal
xmlString = xmlIndent(xmlString, false);
public String xmlIndent(String xml, Boolean ommitXmlDeclaration) {
Writer outxml = new StringWriter();
try {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xml)));
OutputFormat format = new OutputFormat(doc);
format.setIndenting(true);
format.setIndent(2);
format.setOmitXMLDeclaration(ommitXmlDeclaration);
format.setLineWidth(Integer.MAX_VALUE);
XMLSerializer serializer = new XMLSerializer(outxml, format);
serializer.serialize(doc);
} catch (ParserConfigurationException | SAXException | IOException e) {
return xml;
}
return outxml.toString();
}
Result is OK:
<TACHES>
<TACHE>
<NB_HEURE>7.75</NB_HEURE>
<NOTES>foo</NOTES>
<CODE_TACHE>1234</CODE_TACHE>
</TACHE>
</TACHES>

Would like unknown attributes to error when Jaxb unmarshalling

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.

Unmarshal JSON String to some "Object" using MOXy

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;
}

Generate a XSD from a JAXB-annotated class without using File

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();
}
}

Categories

Resources