簡體   English   中英

使用 JAXB 將 POJO 內部映射到 XML

[英]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 {
           
       //code to create main list from other smaller list

        return mainList;
    }
}

和主要元帥類:

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"));
    }

}

我的代碼的結果是這樣的:

<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>

結果我需要這個:

<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>

任何建議或指南如何實現這一結果? 有什么方法可以更改標簽名稱: entrysetvalue

為此,您需要使用 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.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;
    }

}

在 Product 類中,您需要更改屬性映射的注釋:

@XmlElement(name="attrs")
@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, String> attributes;

這將給出以下輸出:

<attrs>
    <a name="key">value</a>
</attrs>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM