I have a simple java program to write an object to a xml file, my problem is that no matter how I do it, I can just store 1 object in the xml file.
my code goes as follows
import javax.xml.bind.annotation.XmlAttribute ;
import javax.xml.bind.annotation.XmlElement ;
import javax.xml.bind.annotation.XmlRootElement ;
#XmlRootElement
public class Product {
String Name;
int Price;
#XmlElement
public void setName(String Name) {
this.Name = Name;
}
#XmlElement
public void setPrice(int price) {
this.price = price;
}
}
import xml.Product;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class XML {
public static void main(String[] args) {
Product product=new Product();
product.setName("Hamburger");
product.setPrice(10);
try{
//File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Product.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(product, file);
jaxbMarshaller.marshal(product, System.out);
}catch(JAXBException e){
e.printStackTrace();
}
}
}
but even if I instance 2 products, I get just one object in my XML file(which is written correctly)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Product>
<Name>Hamburger</Name>
<price>10</price>
</Product>
You can fix this by using a List of Product for example
Here is Product.java refactored:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "product")
#XmlAccessorType (XmlAccessType.FIELD)
public class Product {
private String Name;
private int price;
public String getName() {
return Name;
}
public int getPrice() {
return price;
}
public void setName(String Name) {
this.Name = Name;
}
public void setPrice(int price) {
this.price = price;
}
}
Now create a Products entity that will have a field of type List
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(name = "products")
#XmlAccessorType (XmlAccessType.FIELD)
public class Products {
#XmlElement(name = "product")
private List<Product> products = null;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
And finally a demo:
import java.io.File;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class ProductsDump {
static Products products = new Products();
static
{
products.setProducts(new ArrayList<>());
Product prod1 = new Product();
prod1.setName("Hamburger");
prod1.setPrice(10);
Product prod2 = new Product();
prod2.setName("Bretzel");
prod2.setPrice(5);
products.getProducts().add(prod1);
products.getProducts().add(prod2);
}
private static void marshalingExample() throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(Products.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//Marshal the products list in console
jaxbMarshaller.marshal(products, System.out);
//Marshal the products list in file
jaxbMarshaller.marshal(products, new File("c:/products.xml"));
}
public static void main(String[] args) throws Exception {
marshalingExample();
}
}
Hmm, this is kind of like asking if it's plugged in, but your example only has thing. You need a list of some sort. Add the products to the list and then serialize the list.
Also take a look at XStream, you can get it to do the xml bits for you and you won't have to deal with the javax stuff. It'll serialize to and from XML for you.
Related
I am new in Spring Boot application i face an issue with xml format to soap envelope like below detail:
I need to convert object from java class to xml and format xml tag to soap envelop like below:
Bookstore.java
package com.example.wsdltojavaclass.xmlrequest;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
public class Bookstore {
#XmlElementWrapper(name = "bookList")
#XmlElement(name = "book")
private List < Book > bookList;
private String name;
private String location;
// public void setBookList(List < Book > bookList) {
// this.bookList = bookList;
// }
//
// public List < Book > getBooksList() {
// return bookList;
// }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
My Controller:
#GetMapping("/xml")
public void newroute() throws JAXBException, FileNotFoundException, JAXBException {
List<Book> bookList = new ArrayList<Book>();
Bookstore bookstore = new Bookstore();
bookstore.setName("Amazon Bookstore");
bookstore.setLocation("Newyorkt");
convertObjectToXML(bookstore);
}
private static void convertObjectToXML(Bookstore bookstore) throws JAXBException, FileNotFoundException {
JAXBContext context = JAXBContext.newInstance(Bookstore.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(bookstore, System.out);
m.marshal(bookstore, new File(BOOKSTORE_XML));
}
And here is my result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2: xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/">
<name>Amazon Bookstore</name>
<location>Newyorkt</location>
</ns2:>
My expected result i need to change remove <?xml version="1.0" encoding="UTF-8" standalone="yes"?> and change format to
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://www.dataaccess.com/webservicesserver/">
<soap:Header/>
<soap:Body>
<web:name>Amazon Bookstore</web:name>
<web:location>Newyorkt</web:location>
</soap:Body>
</soap:Envelope>
So how to change from ns2 to soap envelope?
I am trying to return a map directly from an XML file. I've tried it by creating a custom Adapter but the problem is this adapter is not receiving Input Parameter with values from XML.
For Referencing, here are the screenshots of the problem.
Here is the XML which I am trying to parse
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<GroupRoot>
<Root>
<Group>
<UUID>ahsdlfkjadslkfjalkdsjflakjdslf</UUID>
<Name>Root Group 1</Name>
<Entry>
<UUID>1212135454==</UUID>
<String>
<Key>Notes</Key>
<Value>Notes from Manager</Value>
</String>
<String>
<Key>Item1</Key>
<Value>Item1Value</Value>
</String>
<String>
<Key>Item2</Key>
<Value>Item2Value</Value>
</String>
<String>
<Key>Item3</Key>
<Value>Item3Value</Value>
</String>
<String>
<Key>Item4</Key>
<Value>Item4Value</Value>
</String>
</Entry>
<Entry>
<UUID>45645466546546464==</UUID>
<String>
<Key>Notes</Key>
<Value>Notes from Manager</Value>
</String>
<String>
<Key>Item1</Key>
<Value>Item1Value1</Value>
</String>
<String>
<Key>Item2</Key>
<Value>Item2Value1</Value>
</String>
<String>
<Key>Item3</Key>
<Value>Item3Value1</Value>
</String>
<String>
<Key>Item4</Key>
<Value>Item4Value1</Value>
</String>
</Entry>
</Group>
</Root>
</GroupRoot>
& Here is my Pojo's.
package com.parser.xml.model;
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.FIELD)
#XmlRootElement(name = "GroupRoot")
public class KeePassFile {
#XmlElement(name = "Root")
public Root root;
}
package com.parser.xml.model;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
public class Root {
#XmlElement(name = "Group")
public List<Group> groups;
}
package com.parser.xml.model;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
public class Group {
#XmlElement(name = "Name")
public String name;
#XmlElement(name = "Group", nillable = false )
public List<Group> subGroups;
#XmlElement(name = "Entry",nillable = false)
public List<Entry> entries;
}
package com.parser.xml.model;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class Entry {
#XmlElement(name = "UUID")
public String UUID;
#XmlElement(name = "String")
#XmlJavaTypeAdapter(StringMapperAdapter.class)
public Map<String, String> MappedItems;
}
class MapperString {
#XmlElement(name = "Key")
public String key;
#XmlElement(name = "Value")
public String value;
public MapperString() {
}
public MapperString(String key, String value) {
this.key = key;
this.value = value;
}
}
class StringMapperAdapter extends XmlAdapter<MapperString[], Map<String, String>> {
#Override
public Map<String, String> unmarshal(MapperString[] v) throws Exception {
HashMap<String, String> map = new HashMap<String, String>();
for (MapperString element : v) {
map.put(element.key, element.value);
}
return map;
}
#Override
public MapperString[] marshal(Map<String, String> v) throws Exception {
// TODO Auto-generated method stub
return null;
}
}
Main Method
package com.parser.xml;
import java.io.File;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.springframework.core.io.ClassPathResource;
import com.parser.xml.model.KeePassFile;
public class RunAppMain {
private static final String FILE_PATH = "TestXML.xml";
public static void main(String[] Args) throws IOException, JAXBException
{
File resource = new ClassPathResource(FILE_PATH).getFile();
JAXBContext context = JAXBContext.newInstance(KeePassFile.class);
Unmarshaller un = context.createUnmarshaller();
KeePassFile entry = (KeePassFile) un.unmarshal(resource);
System.out.println("Testing");
}
}
I don't know if it's possible to use an XmlAdapter on an xs:sequence. I did manage to set the XmlAdapter one level up on the Entry element:
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class Test {
public static void main(String[] args) throws Exception {
Root root = (Root) JAXBContext.newInstance(Root.class).createUnmarshaller().unmarshal(new File("test.xml"));
System.out.println("" + root.entryList.get(0).map);
System.out.println("" + root.entryList.get(1).map);
}
}
#XmlRootElement(name = "Root")
class Root {
#XmlElement(name = "Entry")
public List<Entry> entryList = new ArrayList<>();
}
#XmlJavaTypeAdapter(EntryAdapter.class)
class Entry {
public String uuid;
public Map<String, String> map = new TreeMap<>();
}
class EntryMappableByJaxb {
#XmlElement
public String UUID;
#XmlElement(name = "String")
public List<KeyValue> stringList = new ArrayList<>();
}
class KeyValue {
#XmlElement
public String Key;
#XmlElement
public String Value;
}
class EntryAdapter extends XmlAdapter<EntryMappableByJaxb, Entry> {
#Override
public Entry unmarshal(EntryMappableByJaxb entryMappableByJaxb) throws Exception {
Entry entry = new Entry();
entry.uuid = entryMappableByJaxb.UUID;
entryMappableByJaxb.stringList.forEach(i -> entry.map.put(i.Key, i.Value));
return entry;
}
#Override
public EntryMappableByJaxb marshal(Entry v) throws Exception {
return null;
}
}
Test XML used:
<Root>
<Entry>
<UUID>uuid 1</UUID>
<String>
<Key>1.1</Key>
<Value>value 1.1</Value>
</String>
<String>
<Key>1.2</Key>
<Value>value 1.2</Value>
</String>
</Entry>
<Entry>
<UUID>uuid 2</UUID>
<String>
<Key>2.1</Key>
<Value>value 2.1</Value>
</String>
<String>
<Key>2.2</Key>
<Value>value 2.2</Value>
</String>
</Entry>
</Root>
I think the best way is to copy my code so you can understand it.
Here are my POJO classes:
import javax.xml.bind.annotation.XmlAttribute;
public class Product {
private String name;
public Product() {
}
public Product(String name) {
this.name = name;
}
#XmlAttribute(name = "productName")
public String getProduct() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="ShoppingCart")
public class Cart {
private List<Product> productList = new ArrayList<>();
private long CartIdentifier;
public Cart() {
}
public Cart(long id) {
this.CartIdentifier=id;
}
#XmlAttribute(name="CartIdentifier")
public long getId() {
return CartIdentifier;
}
public void setType(long id) {
this.CartIdentifier=id;
}
public Cart(List<Product> list) {
this.productList = list;
}
public void addElement(Product element) {
this.productList.add(element);
}
#XmlElement(name = "CurrentProducts")
public List<Product> getCart() {
return this.productList;
}
public void setCart(List<Product> cart) {
this.productList = cart;
}
}
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "CashRegister")
public class Register {
#XmlElement(name = "ShoppingCart")
private ArrayList<Cart> listCart;
long CartIdentifier;
public Register() {
}
public Register(long id) {
this.CartIdentifier=id;
}
public long getId() {
return CartIdentifier;
}
public void addElementforBonus(Cart element) {
listCart.add(element);
}
public void setType(long id) {
this. CartIdentifier=id;
}
public void setList(ArrayList<Cart> list) {
this.listCart = list;
}
public ArrayList<Cart> getCartList() {
return listCart;
}
}
So those are my POJO classes and in main they create perfect XML, but when it comes to converting from XML to normal output something goes wrong. Can someone tell me where am I making mistake and why is my output than alway 0 and null?
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Main {
public static void main(String[] args) throws JAXBException, IOException {
ArrayList<Cart> list = new ArrayList<Cart>();
Register store = new Register(1);
store.setType(1);
store.setList(list);
Product first = new Product("Burger");
Product second = new Product("Banana");
Cart cart1 = new Cart(1);
cart1.setType(1);
cart1.addElement(first);
cart1.addElement(second);
store.getCartList().add(cart1);
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance(Register.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// Write to System.out
m.marshal(store, System.out);
m.marshal(store, new File("mrs.xml"));
System.out.println("Output from our XML File: ");
Unmarshaller um = context.createUnmarshaller();
Register reg = (Register) um.unmarshal(new FileReader("mrs.xml"));
ArrayList<Cart> list1 = reg.getCartList();
for(Cart x:reg.getCartList()) {
System.out.println(x.getId());
}
for (Cart cart : list1) {
System.out.println("Cart: " + cart.getId());
for(Product product : cart.getCart()) {
System.out.println("Product: " + product.getProduct());
}
}
}
}
So here is my output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CashRegister>
<ShoppingCart CartIdentifier="1">
<CurrentProducts productName="Burger"/>
<CurrentProducts productName="Banana"/>
</ShoppingCart>
</CashRegister>
Output from our XML File:
0
Cart: 0
Product: null
Product: null
There is one cart with two products but not with 0 and null.
No, my question isn't duplicate. I don't want to have that as Element or show the name of that element in my xml. My xml looks perfect but i can't unmarshal it
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CashRegister>
<ShoppingCart CartIdentifier="1">
<CurrentProducts productName="Burger"/>
<CurrentProducts productName="Banana"/>
</ShoppingCart>
</CashRegister>
Output from our XML File:
Exception in thread "main" java.lang.ClassCastException: bonusxml.Register cannot be cast to bonusxml.Register1
at bonusxml.Main.main(Main.java:45)
If you are hell bent on preserving your XML structure, you will have to pay a price for that. Below, are classes that can get you de-serializing the XML you have created. But, you will end up using two different set of classes for serializing and de-serializing.
Cart.java
#XmlRootElement(name="ShoppingCart")
public class Cart1 {
#XmlElement(name = "CurrentProducts")
private List<Product1> productList = new ArrayList<>();
#XmlAttribute(name="CartIdentifier")
private long CartIdentifier;
public Cart1() {}
public Cart1(long id) {
this.CartIdentifier=id;
}
// setters & getters
}
Product.java
public class Product1 {
#XmlAttribute(name = "productName")
private String name;
public Product1() {
}
public Product1(String name) {
this.name = name;
}
// setters & getters
}
Register.java
#XmlRootElement(name = "CashRegister")
public class Register1 {
#XmlElement(name = "ShoppingCart")
private ArrayList<Cart1> listCart;
long CartIdentifier;
public Register1() {
}
public Register1(long id) {
this.CartIdentifier=id;
}
//setters & getters
}
I want to store my object data to XML. Below code spinets will show the example of model class.
Class Model
{
#XmlElement
private int id;
#XmlElement
Private string name;
}
I will have multiple model objects which will be stored in some list as below
#XmlRootElement
Class ModelWrapper
{
#XmlElement
#XmlJavaTypeAdapter(value = ListAdapter.class, type = List.class)
List<model> list;
public setlist(List<model>list)
{
//setting list
}
public List<model> getlist()
{
return list
}
}
Now if I marshall this using JAXB, something like this will be produced:
<Modelwrapper>
<List>
......
......
</List>
</Modelwrapper>
I want to avoid one of the root may be list or Modelwrapper.
Is there any way to do it?
In this way your xml will be
<ModelWrapper>
<model>
......
</model>
<model>
......
</model>
</ModelWrapper>
ModelWrapper.java
#XmlRootElement
public class ModelWrapper {
#XmlElement(name = "model")
protected List<Model> list;
Test
ModelWrapper.java
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;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ModelWrapper", propOrder = {
"list"
})
public class ModelWrapper {
#XmlElement(name = "model")
private List<Model> list;
public List<Model> getList() {
return list;
}
public void setList(List<Model> list) {
this.list = list;
}
}
Model.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Model", propOrder = {
"id","name"
})
public class Model {
#XmlElement
private int id;
#XmlElement
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Main.java
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(ModelWrapper.class);
ModelWrapper mw = new ModelWrapper();
List<Model> list = new ArrayList<Model>();
Model m = new Model();
m.setId(1);
m.setName("model1");
list.add(m);
m = new Model();
m.setId(1);
m.setName("model2");
list.add(m);
mw.setList(list);
Marshaller mar = jc.createMarshaller();
mar.marshal(mw, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<modelWrapper>
<model>
<id>1</id>
<name>model1</name>
</model>
<model>
<id>1</id>
<name>model2</name>
</model>
</modelWrapper>
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
public class JavaToXMLDemo {
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Employee.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Employee object = new Employee();
object.setCode("CA");
object.setName("Cath");
object.setSalary(300);
object.setProperties(new PropertiesMap());
m.marshal(object, System.out);
}
}
#XmlRootElement(name="Employee")
#XmlAccessorType(XmlAccessType.FIELD)
class Employee {
private String code;
#XmlElement(name = "Name")
private String name;
private int salary;
#XmlElement(name = "Properties")
protected PropertiesMap params;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public PropertiesMap getProperties() {
return params;
}
public void setProperties(PropertiesMap value) {
this.params = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int population) {
this.salary = population;
}
}
#XmlRootElement(name="Properties")
class PropertiesMap<K,V> extends HashMap<K,V>
{
}
The above code generates the below XML with JDK 1.6
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee>
<code>CA</code>
<Name>Cath</Name>
<salary>300</salary>
<Properties/>
</Employee>
and this on JDK 1.7
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee>
<code>CA</code>
<Name>Cath</Name>
<salary>300</salary>
<params/>
</Employee>
Why does the Marshaller behave differently?
You should use #XmlElementWrapper instead of #XmlElement for your Properties map.
See http://blog.bdoughan.com/2013/03/jaxb-and-javautilmap.html use case #2.