How to avoid root element annotation while marshalling in JAXB? - java

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>

Related

Object to xml tag and format soap envelope in Spring Boot

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?

Return map from xml file Using Jaxb Library Java

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>

JAXB super class field not being deserialized

I am trying to deserialize xml string into object but ran across strange problem. Everything is being serialized as intended, however when deserializing field which originates from parent class always returns null.
MyNffgDescriptor is a class which contain VNFTypeReader as attribute. All fields are deserialized correctly, VNFTypeReader ones as well except the name which is passed from parent class (NamedEntityReaderImpl) and it returns null.
Parent class
package it.polito.dp2.NFV.sol3.client1.implementations;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import it.polito.dp2.NFV.NamedEntityReader;
#XmlAccessorType(XmlAccessType.NONE)
public class NamedEntityReaderImpl implements NamedEntityReader, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String entityName;
public NamedEntityReaderImpl() {
this.entityName = "";
}
public NamedEntityReaderImpl(String name) {
this.entityName = name;
}
#Override
public String getName() {
return this.entityName;
}
}
Child class
package it.polito.dp2.NFV.sol3.client1.implementations;
import java.io.Serializable;
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 it.polito.dp2.NFV.VNFTypeReader;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class VNFTypeReaderImpl extends NamedEntityReaderImpl implements Serializable,VNFTypeReader {
/**
*
*/
private static final long serialVersionUID = 1L;
#XmlElement
private int requiredMemory;
#XmlElement
private int requiredStorage;
#XmlElement
private it.polito.dp2.NFV.FunctionalType funcType;
public VNFTypeReaderImpl() {
super(null);
this.requiredMemory = 0;
this.requiredStorage = 0;
this.funcType = null;
}
public VNFTypeReaderImpl(VNFTypeReader reader) {
super(reader.getName());
this.requiredMemory = reader.getRequiredMemory();
this.requiredStorage = reader.getRequiredStorage();
this.funcType = reader.getFunctionalType();
}
#Override
public int getRequiredMemory() {
return this.requiredMemory;
}
#Override
public int getRequiredStorage() {
return this.requiredStorage;
}
#Override
public it.polito.dp2.NFV.FunctionalType getFunctionalType() {
return this.funcType;
}
#Override
#XmlElement(name="name", required=true)
public String getName() {
return super.getName();
}
}
This is the example of xml string I am trying to deserialize:
<?xml version="1.0" encoding="UTF-8"?>
<myNffgDescriptor>
<nodeList id="0">
<funcReader>
<requiredMemory>620</requiredMemory>
<requiredStorage>100</requiredStorage>
<funcType>WEB_SERVER</funcType>
<name>WEBSERVERt</name>
</funcReader>
<hostName>H3</hostName>
<linksList source="0" destination="10" />
<linksList source="0" destination="11" />
<linksList source="0" destination="8" />
</nodeList>
</myNffgDescriptor>
Place where unmarshalling occurs:
jaxbContext = JAXBContext.newInstance(MyNffgDescriptor.class);
unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(nffg);
MyNffgDescriptor nffgDesc = (MyNffgDescriptor) unmarshaller.unmarshal(reader);
Change XmlAccessType.NONE to XmlAccessType.FIELD on parent
class NamedEntityReaderImpl.
Also you could just add on class NamedEntityReaderImpl an annotation above the field:
#XmlElement(name= "name")
private String entityName;
Do either changes (or both) and it would work

storing multiple objects in XML file

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.

JAXB not generating XML as per the Annotations (JDK 1.7)

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.

Categories

Resources