How can I get jaxb to bind to my Vector? I cannot seem to get it to bind a Vector that contains generics as it complains that it cannot recognize my class "shape" or any of its subtypes.. "[javax.xml.bind.JAXBException: class shape.shape nor any of its super class is known to this context.]"?
import java.util.Vector;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "XVector")
public class XVector<shape> {
private Vector<shape> q;
public XVector() {}
#XmlElement(name = "q")
public Vector<shape> getVector() {
return q;
}
public void setVector(Vector<shape> q) {
this.q = q;
}
}
I get the following errors:
javax.xml.bind.MarshalException
- with linked exception:
[javax.xml.bind.JAXBException: class shape.Rectangle nor any of its super class is known to this context.]
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:317)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:243)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
public void saveFile(File filename) {
try {
FileOutputStream fout = new FileOutputStream(filename);
objs.setVector(objVec);
JAXBContext context = JAXBContext.newInstance(XVector.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(objs, fout);
fout.close();
} catch (JAXBException e) {
e.printStackTrace ();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this, ex.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
You should include all required classes in the JAXBContext
JAXBContext context = JAXBContext.newInstance(XVector.class, shape.class);
(note: the convention dictates that Shape should be capitalized)
Related
I want to read the data from multiple XML files based on the XSD document and the structure of one XML file will not be the same as to another but will follow the xsd schema. Also, the xmls are nested xmls.Can someone help me with it so that I can use the already created utility and add the attributes to it? I need a XML parser which parses each xml file(They are different) based on the xsd schema and returns me a list of the map so that the data can be matched with the DB data.
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Test {
public static void main(String[] args) {
Customer customer = new Customer();
try {
File file = new File("SalesPoslog20200225104558676.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(customer, file);
jaxbMarshaller.marshal(customer, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Customer {
int organizationID;
int retailStoreID;
int workstationID;
int tillID;
int sequenceNumber;
public int organizationID() {
return organizationID;
}
#XmlElement
public void RetailStoreID(int retailStoreID) {
this.retailStoreID = retailStoreID;
}
public int workstationID() {
return workstationID;
}
#XmlAttribute
public void RetailStoreId(int RetailStoreId) {
this.retailStoreID = retailStoreID;
}
}
I have a xml which is having japanese characters. The Xml is getting marshalled correctly but which jaxbUnmarshalling all the characters are getting converted into '?'
Please find the Code Below :-
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Customer {
String name;
int age;
int id;
public String getName() {
return name;
}
#XmlElement
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
#XmlElement
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
#XmlAttribute
public void setId(int id) {
this.id = id;
}
}
JAXBExample
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JAXBExample {
public static void main(String[] args) {
Customer customer = new Customer();
customer.setId(100);
customer.setName("株式会社三菱東京UFJ銀行");
customer.setAge(29);
try {
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(customer, file);
jaxbMarshaller.marshal(customer, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Conversion.java
public class Conversion {
public static void main(String[] args) {
try {
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Customer customer = (Customer) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer.getName());
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
OutPUT :-
XML :-
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer id="100">
<age>29</age>
<name>株式会社三菱東京UFJ銀行</name>
</customer>
After running the Conversion.java class i am getting the below output:-
Customer Name ????????UFJ??
Please help i have searched the net but could not find any solution.
Try constructing a Reader yourself with the correct encoding and feed that Reader to Unmarshaller#unmarshal() instead of your File:
File file = new File("C:\\file.xml");
try (Reader reader = new InputStreamReader(new FileInputStream(file), "utf-8")) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Customer customer = (Customer) jaxbUnmarshaller.unmarshal(reader);
System.out.println(customer.getName());
} catch (JAXBException e) {
e.printStackTrace();
}
}
Also, if your platform encoding is something like latin1, then System.out uses it and corrupts the data being output (replacing it with question marks). Please run your program like this:
java -Dfile.encoding=utf-8 JAXBExample
By the way, this may be sufficient by itself, without the Reader-related twist, to solve the problem, as unmarshal() method should respect encoding specified in the XML file.
I try to unmarshall one xml to ArrayList or to Class but the object which i make is not populated by JAXB
#Override
public Ships load(String xmlFilePath) {
//Ships ship = new Ships();
ArrayList<Ship> shps = new ArrayList<>();
try {
File file = new File(xmlFilePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Ship.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
shps = (ArrayList<Ship>) jaxbUnmarshaller.unmarshal(file);
} catch (JAXBException e) {
e.printStackTrace();
}
return shps;}
}
Maybe you already read this solution somewhere else, but the most common solution is to make a wrapper class (or even better, a generic, reusable wrapper class). In the code below there's a working example of this concept, I hope the code is self explanatory.
package com.quick;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD) // just to avoid the get and set methods
class Wrapper<T> {
#XmlAnyElement
List<T> list;
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD) // just to avoid the get and set methods
class Ship {
String id = "N" + System.nanoTime();
}
public class Main {
public static void main(String[] args) throws JAXBException {
// context, marshaller and unmarshaller
JAXBContext context = JAXBContext.newInstance(Ship.class, Wrapper.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Unmarshaller unmarshaller = context.createUnmarshaller();
// original list
List<Ship> originalList = new ArrayList<>();
originalList.add(new Ship());
originalList.add(new Ship());
originalList.add(new Ship());
// wrapper object
Wrapper<Ship> originalWraper = new Wrapper<>();
originalWraper.list = originalList;
// marshal the original wrapper and save the bytes in byteArray1
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
marshaller.marshal(originalWraper, os1);
byte[] byteArray1 = os1.toByteArray();
// unmarshall the bytes
ByteArrayInputStream is = new ByteArrayInputStream(byteArray1);
Wrapper<Ship> unmarshaledWrapper = (Wrapper<Ship>) unmarshaller.unmarshal(is);
// THIS LIST SHOULD CONTAIN A COPY OF originalList
List<Ship> unmarshaledList = unmarshaledWrapper.list;
// marshal the unmarshaledWrapper (...) and sabe the bytes in byteArray2
ByteArrayOutputStream os2 = new ByteArrayOutputStream();
marshaller.marshal(unmarshaledWrapper, os2);
byte[] byteArray2 = os2.toByteArray();
// print the bytes, they should be the same
System.out.println(new String(byteArray1));
System.out.println(new String(byteArray2));
}
}
The general idea is to make a class that works as a wrapper for your list (or array) that can be marshaled or marshaled according to your needs.
I am new born for Jaxb and trying to do read/write operation in xml.
I am done with the write operation but having trouble with the read one.
I have the following xml-
<docOperations>
<SkuSlabs id="1">
<docId>677-WORK</docId>
<itemIds>11</itemIds>
<itemName>new item addedaaaaaa</itemName>
</SkuSlabs>
<SkuSlabs id="2">
<docId>699-WORK</docId>
<itemIds>21</itemIds>
<itemName>extra</itemName>
</SkuSlabs>
</docOperations>
Now i want to unmarshal the SkuSlabs object based on the condition supplied 'where id = 1', but don't know how to achieve that.
Please help.
Here you are (as you want add same access modifiers to attributes):
package pl.skuslab;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "SkuSlabs")
#XmlAccessorType(XmlAccessType.FIELD)
public class SkusLab {
#XmlAttribute
int id;
String docId;
int itemIds;
String itemName;
public SkusLab(int id, String docId, int itemIds, String itemName) {
super();
this.id = id;
this.docId = docId;
this.itemIds = itemIds;
this.itemName = itemName;
}
public SkusLab() {
super();
}
#Override
public String toString() {
return "SkusLab [id=" + id + ", docId=" + docId + ", itemIds=" + itemIds + ", itemName=" + itemName + "]";
}
}
Class DocOperation:
package pl.skuslab;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class DocOperation {
#XmlElement(name = "SkuSlabs")
List<SkusLab> docOperations = new ArrayList<SkusLab>();
}
Class with the main function. Firstly I generate XML like you wrote in question, then I unmarshall xml to obejcts. First obejct is printed.
package pl.skuslab;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class SkusLabJaxb {
private static JAXBContext jc;
static {
try {
jc = JAXBContext.newInstance(DocOperation.class);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
private static Marshaller getMarshaller() {
try {
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
return marshaller;
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
private static Unmarshaller getUnmarshaller() {
try {
Unmarshaller unmarshaller = jc.createUnmarshaller();
return unmarshaller;
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String xml = "";
try {
DocOperation doper = new DocOperation();
doper.docOperations.add(new SkusLab(1, "677-WORK", 11, "new item addedaaaaaa"));
doper.docOperations.add(new SkusLab(2, "699-WORK", 21, "extra"));
StringWriter sw = new StringWriter();
getMarshaller().marshal(doper, sw);
xml = sw.toString();
System.out.println(xml);
} catch (JAXBException e) {
e.printStackTrace();
}
try {
DocOperation docOperation = (DocOperation) getUnmarshaller().unmarshal(
new StringReader(xml));
System.out.println(docOperation.docOperations.get(0).toString());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
I have an object value, which is of some type, either #XmlRootElement-annotated, or not. I want to marshal it into XML:
String value1 = "test";
assertEquals("<foo>test</foo>", toXml("foo", value1));
// ...
#XmlRootElement
class Bar {
public String bar = "test";
}
assertEquals("<foo><bar>test</bar></foo>", toXml("foo", new Bar()));
Can I do it with JAXB existing facilities, or I should create some custom analyzer?
You could leverage JAXBIntrospector to do the following:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
public class Demo {
public static void main(String[] args) throws Exception {
Object value = "Hello World";
//Object value = new Bar();
JAXBContext jc = JAXBContext.newInstance(String.class, Bar.class);
JAXBIntrospector introspector = jc.createJAXBIntrospector();
Marshaller marshaller = jc.createMarshaller();
if(null == introspector.getElementName(value)) {
JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), Object.class, value);
marshaller.marshal(jaxbElement, System.out);
} else {
marshaller.marshal(value, System.out);
}
}
#XmlRootElement
public static class Bar {
}
}
With the above code when the JAXBElement is marshalled it will be qualified with an xsi:type attribute corresponding to the appropriate schema type:
<ROOT
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">Hello World</ROOT>
To eliminate the qualification you can simply change the line that creates the JAXBElement to:
JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), value.getClass(), value);
This will result in the following XML:
<ROOT>Hello World</ROOT>
Here is how to marshal value1, which is a String. You can pass yourObject.getClass() to the JAXBElement constructor, and value1:
try {
JAXBContext jc = JAXBContext.newInstance();
Marshaller m = jc.createMarshaller();
String value1 = "test";
JAXBElement jx = new JAXBElement(new QName("foo"), value1.getClass(), value1);
m.marshal(jx, System.out);
} catch (JAXBException ex) {
ex.printStackTrace();
}
This works without using #XmlRootElement. The result of the code above was:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo>test</foo>
On the other part, this will not work with a Bar object: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. However, you can get the value from inside Bar, and create the JAXBElement with that, not the object itself.
If it's not annotated with #XmlRootElement, then JAXB does not have sufficient information to marshal it. You would need to wrap it in a JAXBElement first.
Could you do some reflective lovin' to find out how to wrap the object in the appropriate JAXBElement?
I didnt find any good generic way of doing it. Here is my generic solution.
import javax.xml.bind.*;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
public class XMLConverter {
/**
* Serialize object to XML string
* #param object object
* #param <T> type
* #return
*/
public static <T> String marshal(T object) {
try {
StringWriter stringWriter = new StringWriter();
JAXBContext jc = JAXBContext.newInstance(object.getClass());
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
QName qName = new QName(object.getClass().getCanonicalName(), object.getClass().getSimpleName());
JAXBElement<T> root = new JAXBElement(qName, object.getClass(), object);
m.marshal(root, stringWriter);
return stringWriter.toString();
} catch (Exception e) {
// log the exception
}
return null;
}
/**
* Deserialize XML string back to object
* #param content XML content
* #param clasz class
* #param <T> type
* #return
*/
public static <T> T unMarshal(final String content, final Class<T> clasz) {
try {
JAXBContext jc = JAXBContext.newInstance(clasz);
Unmarshaller u = jc.createUnmarshaller();
return u.unmarshal(new StreamSource(new StringReader(content)), clasz).getValue();
} catch (Exception e) {
// log the exception
}
return null;
}
}