英文:
Map inside POJO to XML with JAXB
问题
我有一个像这样的产品POJO:
@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
}
下一个类给我产品列表。
@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;
}
}
下一个类从数据库获取数据并将其作为产品列表返回:
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;
}
用于填充主列表的类(我的列表是从其他较小的列表构建的)。
@XmlRootElement(name = "offers")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class ListInitializer {
//从其他较小的列表创建主列表的代码
return mainList;
}
以及主要的 marshal 类:
public class MainMarshal {
private ListInitializer mainListInitializer = new ListInitializer();
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"));
}
}
我的代码的结果类似于这样:
<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>
</attrs>
</o>
</offers>
我需要的结果是这样的:
<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>
</attrs>
</o>
</offers>
有关如何实现这个结果的建议或指南吗?是否有改变标签名称(entry
,set
和 value
)的方法?
英文:
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
?
答案1
得分: 1
以下是翻译好的内容:
为此,您将需要使用XmlAdapter。
应创建以下bean:
public class Entry {
@XmlAttribute
public String name;
@XmlValue
public String value;
}
public class MapWrapper {
@XmlElement(name="a")
public List<Entry> entry = new ArrayList<>();
}
XML适配器:
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.name, 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.name = mapEntry.getKey();
entry.value = mapEntry.getValue();
return entry;
}).forEachOrdered(entry -> {
adaptedMap.entry.add(entry);
});
return adaptedMap;
}
}
在类Product中,您需要更改属性映射的注解:
@XmlElement(name="attrs")
@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, String> attributes;
这将产生以下输出:
<attrs>
<a name="key">value</a>
</attrs>
英文:
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论