diff --git a/CHANGELOG.md b/CHANGELOG.md
index 471f7ab77..d35a456f4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,11 +8,13 @@
### 🐣新特性
* 【core 】 增加Convert.toSet方法(issue#I3XFG2@Gitee)
* 【core 】 CsvWriter增加writeBeans方法(pr#345@Gitee)
+* 【core 】 新增JAXBUtil(pr#346@Gitee)
### 🐞Bug修复
* 【json 】 修复XML转义字符的问题(issue#I3XH09@Gitee)
* 【core 】 修复FormatCache中循环引用异常(pr#1673@Github)
* 【core 】 修复IdcardUtil.getIdcardInfo.getProvinceCode获取为汉字的问题(issue#I3XP4Q@Gitee)
+* 【core 】 修复CollUtil.subtract使用非标准Set等空指针问题(issue#I3XN1Z@Gitee)
-------------------------------------------------------------------------------------------------------------
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/JAXBUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/JAXBUtil.java
new file mode 100644
index 000000000..19101cd0e
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/util/JAXBUtil.java
@@ -0,0 +1,106 @@
+package cn.hutool.core.util;
+
+import cn.hutool.core.exceptions.UtilException;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+
+/**
+ * JAXB(Java Architecture for XML Binding),根据XML Schema产生Java对象,即实现xml和Bean互转。
+ *
+ * 相关介绍:
+ *
+ * - https://www.cnblogs.com/yanghaolie/p/11110991.html
+ * - https://my.oschina.net/u/4266515/blog/3330113
+ *
+ *
+ * @author dazer
+ * @since 5.7.3
+ */
+public class JAXBUtil {
+
+ /**
+ * JavaBean转换成xml
+ *
+ * @param bean Bean对象
+ * @return 输出的XML字符串
+ */
+ public static String beanToXml(Object bean) {
+ return beanToXml(bean, CharsetUtil.CHARSET_UTF_8, true);
+ }
+
+ /**
+ * JavaBean转换成xml
+ *
+ * @param bean Bean对象
+ * @param charset 编码 eg: utf-8
+ * @param format 是否格式化输出eg: true
+ * @return 输出的XML字符串
+ */
+ public static String beanToXml(Object bean, Charset charset, boolean format) {
+ StringWriter writer;
+ try {
+ JAXBContext context = JAXBContext.newInstance(bean.getClass());
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, format);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, charset.name());
+ writer = new StringWriter();
+ marshaller.marshal(bean, writer);
+ } catch (Exception e) {
+ throw new UtilException("convertToXml 错误:" + e.getMessage(), e);
+ }
+ return writer.toString();
+ }
+
+ /**
+ * xml转换成JavaBean
+ *
+ * @param xml XML字符串
+ * @param c Bean类型
+ * @return bean
+ */
+ public static T xmlToBean(String xml, Class c) {
+ return xmlToBean(StrUtil.getReader(xml), c);
+ }
+
+ /**
+ * XML文件转Bean
+ *
+ * @param file 文件
+ * @param charset 编码
+ * @param c Bean类
+ * @param Bean类型
+ * @return Bean
+ */
+ public static T xmlToBean(File file, Charset charset, Class c) {
+ return xmlToBean(FileUtil.getReader(file, charset), c);
+ }
+
+ /**
+ * 从{@link Reader}中读取XML字符串,并转换为Bean
+ *
+ * @param reader {@link Reader}
+ * @param c Bean类
+ * @param Bean类型
+ * @return Bean
+ */
+ @SuppressWarnings("unchecked")
+ public static T xmlToBean(Reader reader, Class c) {
+ try {
+ JAXBContext context = JAXBContext.newInstance(c);
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+ return (T) unmarshaller.unmarshal(reader);
+ } catch (Exception e) {
+ throw new RuntimeException("convertToJava2 错误:" + e.getMessage(), e);
+ } finally {
+ IoUtil.close(reader);
+ }
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/XmlBeanUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/XmlBeanUtil.java
deleted file mode 100644
index 3f7c384d0..000000000
--- a/hutool-core/src/main/java/cn/hutool/core/util/XmlBeanUtil.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package cn.hutool.core.util;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.Unmarshaller;
-import java.io.*;
-import java.nio.charset.StandardCharsets;
-
-/**
- * xml和Bean互转工具类,不依赖第三方库;需要使用到:javax.xml 包
- * @author dazer
- * 相关介绍:
- *
- */
-public class XmlBeanUtil {
- /**
- * JavaBean转换成xml
- *
- * @param obj
- * @param encoding eg: utf-8
- * @param format eg: true
- * @return
- */
- public static String convertToXml(Object obj, String encoding, boolean format) {
- String result = null;
- StringWriter writer = null;
- try {
- JAXBContext context = JAXBContext.newInstance(obj.getClass());
- Marshaller marshaller = context.createMarshaller();
- marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, format);
- marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
- writer = new StringWriter();
- marshaller.marshal(obj, writer);
- result = writer.toString();
- } catch (Exception e) {
- throw new RuntimeException("convertToXml 错误:" + e.getMessage(), e);
- } finally {
- if (writer != null){
- try {
- writer.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- return result;
- }
-
- public static String convertToXml(Object obj) {
- return convertToXml(obj, StandardCharsets.UTF_8.toString(), true);
- }
-
- /**
- * xml转换成JavaBean
- *
- * @param xml
- * @param c
- * @return
- */
- @SuppressWarnings("unchecked")
- public static T convertToJava(String xml, Class c) {
- if (xml == null || "".equals(xml))
- return null;
- T t = null;
- StringReader reader = null;
- try {
- JAXBContext context = JAXBContext.newInstance(c);
- Unmarshaller unmarshaller = context.createUnmarshaller();
- reader = new StringReader(xml);
- t = (T) unmarshaller.unmarshal(reader);
- } catch (Exception e) {
- throw new RuntimeException("convertToJava1 错误:" + e.getMessage(), e);
- } finally {
- if (reader != null)
- reader.close();
- }
- return t;
- }
-
- @SuppressWarnings("unchecked")
- public static T convertToJava(File filePath, Class c) throws IOException {
- if (!filePath.exists())
- return null;
- T t = null;
- FileReader reader = null;
- try {
- JAXBContext context = JAXBContext.newInstance(c);
- Unmarshaller unmarshaller = context.createUnmarshaller();
- reader = new FileReader(filePath);
- t = (T) unmarshaller.unmarshal(reader);
- } catch (Exception e) {
- throw new RuntimeException("convertToJava2 错误:" + e.getMessage(), e);
- } finally {
- if (reader != null)
- reader.close();
- }
- return t;
- }
-}
diff --git a/hutool-core/src/test/java/cn/hutool/core/util/XmlBeanUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/JAXBUtilTest.java
similarity index 64%
rename from hutool-core/src/test/java/cn/hutool/core/util/XmlBeanUtilTest.java
rename to hutool-core/src/test/java/cn/hutool/core/util/JAXBUtilTest.java
index 8fdb8cdcb..8d9ce8989 100644
--- a/hutool-core/src/test/java/cn/hutool/core/util/XmlBeanUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/util/JAXBUtilTest.java
@@ -6,15 +6,25 @@ import org.junit.Test;
import javax.xml.bind.annotation.*;
/**
- * {@link XmlBeanUtil} 工具类
+ * {@link JAXBUtil} 工具类
+ * 测试 xml 和 bean 互转工具类
*
* @author dazer
- * 测试 xml 和 bean 互转工具类
*/
-public class XmlBeanUtilTest {
+public class JAXBUtilTest {
+
+ private String xmlStr = "\n" +
+ "\n" +
+ " 西安市第一中学\n" +
+ " 西安市雁塔区长安堡一号\n" +
+ " \n" +
+ " 101\n" +
+ " 101教室\n" +
+ " \n" +
+ "\n";
@Test
- public void convertToXmlTest() {
+ public void beanToXmlTest() {
SchoolVo schoolVo = new SchoolVo();
schoolVo.setSchoolName("西安市第一中学");
schoolVo.setSchoolAddress("西安市雁塔区长安堡一号");
@@ -24,22 +34,23 @@ public class XmlBeanUtilTest {
roomVo.setRoomNo("101");
schoolVo.setRoom(roomVo);
- String xmlStr = "\n" +
- "\n" +
- " 西安市第一中学\n" +
- " 西安市雁塔区长安堡一号\n" +
- " \n" +
- " 101\n" +
- " 101教室\n" +
- " \n" +
- "\n";
- Assert.assertEquals(XmlBeanUtil.convertToXml(schoolVo), xmlStr);
+ Assert.assertEquals(xmlStr, JAXBUtil.beanToXml(schoolVo));
}
+ @Test
+ public void xmlToBeanTest() {
+ final SchoolVo schoolVo = JAXBUtil.xmlToBean(xmlStr, SchoolVo.class);
+ Assert.assertNotNull(schoolVo);
+ Assert.assertEquals("西安市第一中学", schoolVo.getSchoolName());
+ Assert.assertEquals("西安市雁塔区长安堡一号", schoolVo.getSchoolAddress());
+
+ Assert.assertEquals("101教室", schoolVo.getRoom().getRoomName());
+ Assert.assertEquals("101", schoolVo.getRoom().getRoomNo());
+ }
@XmlRootElement(name = "school")
@XmlAccessorType(XmlAccessType.FIELD)
- private static final class SchoolVo {
+ public static class SchoolVo {
@XmlElement(name = "school_name", required = true)
private String schoolName;
@XmlElement(name = "school_address", required = true)