基于现有Java类,如何从XML生成填充完整的Registry对象?
问题描述
给定如下XML文件,以及已定义的6个Java类(Catalog、Cd、Album、Artist、Country、Registry),其中Catalog和Cd类已通过Jackson注解完成XML映射,需要生成填充完整字段的Registry对象。
输入XML文件
<?xml version="1.0" encoding="UTF-8"?> <CATALOG> <CD> <TITLE>Empire Burlesque</TITLE> <ARTIST>Bob Dylan</ARTIST> <COUNTRY>USA</COUNTRY> <COMPANY>Columbia</COMPANY> <PRICE>10.90</PRICE> <YEAR>1985</YEAR> </CD> <CD> <TITLE>Hide your heart</TITLE> <ARTIST>Bonnie Tyler</ARTIST> <COUNTRY>UK</COUNTRY> <COMPANY>CBS Records</COMPANY> <PRICE>9.90</PRICE> <YEAR>1988</YEAR> </CD> <CD> <TITLE>Greatest Hits</TITLE> <ARTIST>Dolly Parton</ARTIST> <COUNTRY>USA</COUNTRY> <COMPANY>RCA</COMPANY> <PRICE>9.90</PRICE> <YEAR>1982</YEAR> </CD> <CD> <TITLE>Still got the blues</TITLE> <ARTIST>Gary Moore</ARTIST> <COUNTRY>UK</COUNTRY> <COMPANY>Virgin records</COMPANY> <PRICE>10.20</PRICE> <YEAR>1990</YEAR> </CD> <CD> <TITLE>Eros</TITLE> <ARTIST>Eros Ramazzotti</ARTIST> <COUNTRY>EU</COUNTRY> <COMPANY>BMG</COMPANY> <PRICE>9.90</PRICE> <YEAR>1997</YEAR> </CD> <CD> <TITLE>One night only</TITLE> <ARTIST>Bee Gees</ARTIST> <COUNTRY>UK</COUNTRY> <COMPANY>Polydor</COMPANY> <PRICE>10.90</PRICE> <YEAR>1998</YEAR> </CD> </CATALOG>
已定义的Java类
目标结构类(需填充为Registry)
public class Registry { private List<Country> countries = new ArrayList<>(); } public class Country { private String name; // 对应XML中的<COUNTRY>节点内容 private List<Artist> artists = new ArrayList<>(); } public class Artist { private String name; // 对应XML中的<ARTIST>节点内容 private List<Album> albums = new ArrayList<>(); } public class Album { private String name; // 对应XML中的<TITLE>节点内容 private int year; // 对应XML中的<YEAR>节点内容 }
Jackson XML映射类
public class Catalog { @JacksonXmlProperty(localName = "CD") @JacksonXmlElementWrapper(useWrapping = false) private List cds; public List getCds() { return cds; } } public class Cd { @JsonProperty("TITLE") // 专辑名称 private String title; @JsonProperty("ARTIST") // 艺术家名称 private String artist; @JsonProperty("COUNTRY") // 国家名称 private String country; @JsonProperty("COMPANY") private String company; @JsonProperty("PRICE") private double price; @JsonProperty("YEAR") // 发行年份 private int year; }
解决方案
1. 引入Jackson XML依赖
确保项目中添加Jackson XML处理的依赖,以Maven为例:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.15.2</version> <!-- 使用最新稳定版本 --> </dependency>
2. 优化Jackson映射类
原Catalog类的cds字段为原始类型,建议改为泛型List<Cd>避免类型转换警告,并添加setter方法:
public class Catalog { @JacksonXmlProperty(localName = "CD") @JacksonXmlElementWrapper(useWrapping = false) private List<Cd> cds; public List<Cd> getCds() { return cds; } public void setCds(List<Cd> cds) { this.cds = cds; } }
为Cd类添加所有字段的getter/setter,确保Jackson能正确反序列化:
public class Cd { @JsonProperty("TITLE") private String title; @JsonProperty("ARTIST") private String artist; @JsonProperty("COUNTRY") private String country; @JsonProperty("COMPANY") private String company; @JsonProperty("PRICE") private double price; @JsonProperty("YEAR") private int year; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getArtist() { return artist; } public void setArtist(String artist) { this.artist = artist; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } }
3. 补充目标类的Getter/Setter
为Registry、Country、Artist、Album添加getter/setter,确保能正常访问和修改字段:
import java.util.ArrayList; import java.util.List; public class Registry { private List<Country> countries = new ArrayList<>(); public List<Country> getCountries() { return countries; } public void setCountries(List<Country> countries) { this.countries = countries; } } public class Country { private String name; private List<Artist> artists = new ArrayList<>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Artist> getArtists() { return artists; } public void setArtists(List<Artist> artists) { this.artists = artists; } } public class Artist { private String name; private List<Album> albums = new ArrayList<>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Album> getAlbums() { return albums; } public void setAlbums(List<Album> albums) { this.albums = albums; } } public class Album { private String name; private int year; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } }
4. 实现转换逻辑
通过Jackson将XML反序列化为Catalog,再遍历Cd列表,按国家→艺术家→专辑的层级分组,构建完整的Registry对象:
import com.fasterxml.jackson.dataformat.xml.XmlMapper; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class RegistryGenerator { public static void main(String[] args) throws IOException { // 1. 读取XML并反序列化为Catalog XmlMapper xmlMapper = new XmlMapper(); Catalog catalog = xmlMapper.readValue(new File("catalog.xml"), Catalog.class); // 2. 构建Registry层级结构 Registry registry = new Registry(); Map<String, Country> countryCache = new HashMap<>(); for (Cd cd : catalog.getCds()) { // 缓存国家,避免重复创建 Country country = countryCache.get(cd.getCountry()); if (country == null) { country = new Country(); country.setName(cd.getCountry()); countryCache.put(cd.getCountry(), country); registry.getCountries().add(country); } // 缓存艺术家,避免重复创建 Map<String, Artist> artistCache = new HashMap<>(); country.getArtists().forEach(artist -> artistCache.put(artist.getName(), artist)); Artist artist = artistCache.get(cd.getArtist()); if (artist == null) { artist = new Artist(); artist.setName(cd.getArtist()); country.getArtists().add(artist); } // 创建并添加专辑 Album album = new Album(); album.setName(cd.getTitle()); album.setYear(cd.getYear()); artist.getAlbums().add(album); } // 验证结果:打印Registry内容 printRegistry(registry); } // 辅助打印方法 private static void printRegistry(Registry registry) { for (Country country : registry.getCountries()) { System.out.println("国家: " + country.getName()); for (Artist artist : country.getArtists()) { System.out.println(" 艺术家: " + artist.getName()); for (Album album : artist.getAlbums()) { System.out.println(" 专辑: " + album.getName() + " (" + album.getYear() + ")"); } } } } }
运行说明
- 将XML文件保存为
catalog.xml放在项目根目录,或修改代码中的文件路径。 - 运行
RegistryGenerator类,即可生成填充完整的Registry对象,控制台会打印验证内容。
内容的提问来源于stack exchange,提问作者Nikita Zakharov
相关产品推荐
相关产品推荐

