Reputation: 37
I have POJO of product like this:
@XmlRootElement(name = "o")
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
@XmlAttribute
private Integer avail;
@XmlAttribute
private Long id;
@XmlAttribute
private BigDecimal price;
@XmlAttribute
private String url;
@XmlAttribute
private Integer stock;
private String category;
private String title;
private String description;
@XmlElementWrapper(name = "attrs")
@XmlElement(name = "a")
private Map<String, String> attributes;
//getters, setters, toString
}
Next class gives me list of products.
@XmlRootElement(name = "offers")
@XmlAccessorType(XmlAccessType.FIELD)
public class Products {
@XmlElement(name = "o")
private List<Product> products = null;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
Next class gets data from database and return it as a product list:
private Connection conn = null;
private ResultSet rs = null;
private PreparedStatement selectProducts = null;
private Query query = new Query();
private Map<String, String> attr = new HashMap<String , String>();
private List<Product> mainList = new ArrayList<>();
private DescCreator descCreator = new DescCreator(); //taking care of product html description
public List<Product> listFiller() {
try {
conn = DriverManager.getConnection(connectionData);
selectProducts = conn.prepareCall(query.getMainQuery());
rs = selectProducts.executeQuery();
while(rs.next()){
Product product = new Product();
product.setId(rs.getLong("products_id"));
product.setPrice(rs.getBigDecimal("products_price_tax"));
product.setUrl("https://www.link.com/" + rs.getString("products_id") + ".html");
product.setAvail(rs.getInt("products_availability_id"));
product.setStock(rs.getInt("products_quantity"));
product.setCategory(rs.getString("categories_name"));
product.setTitle(rs.getString("products_name"));
product.setDescription(descCreator.descript(rs.getString("products_description")));
attr.put(rs.getString("products_extra_fields_name"), rs.getString("products_extra_fields_value"));
product.setAttributes(attr);
mainList.add(product);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return mainList;
}
Class to populate main list (my list was built from other smaller lists).
@XmlRootElement(name = "offers")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class listInitializer {
//code to create main list from other smaller list
return mainList;
}
}
And main marshal class:
public class MainMarshal{
private MainListInitializer mainListInitializer = new MainListInitializer();
private Products products = new Products();
public void marshalMain() throws JAXBException, IOException {
products.setProducts(mainListInitializer.generateMainXml());
JAXBContext jaxbContext = JAXBContext.newInstance(Products.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(products, new File("filepath"));
}
}
Result of my code is something like this:
<offers>
<o avail="1" id="1234" price="1234.00" url="some url" stock="1234">
<category>PC</category>
<title>Some product title</title>
<desc>Some product description</desc>
<attrs>
<entry>
<key>Map key</key>
<value>Map value</value>
</entry>
<entry>
<key>Map key</key>
<value>Map value</value>
</entry>
<entry>
<key>Map key</key>
<value>Map value</value>
</entry>
</atrts>
</o>
</offers>
And i need this as a result:
<offers>
<o avail="1" id="1234" price="1234.00" url="some url" stock="1234">
<category>PC</category>
<title>Some product title</title>
<desc>Some product description</desc>
<attrs>
<a name="Map key">Map value</a>
<a name="Map key">Map value</a>
<a name="Map key">Map value</a>
<a name="Map key">Map value</a>
</atrts>
</o>
</offers>
Any suggetions or guides how to achiev this result? Is there any way to change tag names: entry
, set
and value
?
Upvotes: 2
Views: 906
Reputation: 4462
For this purpose you'll need to use XmlAdapter.
Following beans should be created:
public class Entry {
@XmlAttribute
public String name;
@XmlValue
public String value;
}
public class MapWrapper {
@XmlElement(name="a")
public List<Entry> entry = new ArrayList<>();
}
XML Adapter:
import java.util.Map;
import java.util.TreeMap;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class MapAdapter extends XmlAdapter<MapWrapper, Map<String, String>> {
@Override
public Map<String, String> unmarshal(MapWrapper adaptedMap) throws Exception {
Map<String, String> map = new TreeMap<>();
adaptedMap.entry.forEach(entry -> {
map.put(entry.key, entry.value);
});
return map;
}
@Override
public MapWrapper marshal(Map<String, String> map) throws Exception {
MapWrapper adaptedMap = new MapWrapper();
map.entrySet().stream().map(mapEntry -> {
Entry entry = new Entry();
entry.key = mapEntry.getKey();
entry.value = mapEntry.getValue();
return entry;
}).forEachOrdered(entry -> {
adaptedMap.entry.add(entry);
});
return adaptedMap;
}
}
In class Product you'll need to change annotations for attributes map:
@XmlElement(name="attrs")
@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, String> attributes;
That will give following output:
<attrs>
<a name="key">value</a>
</attrs>
Upvotes: 1