Looly 6 years ago
parent
commit
83460af7ef

+ 4 - 1
CHANGELOG.md

@@ -8,11 +8,14 @@
 ### 新特性
 * 【core 】      解决NumberUtil导致的ambiguous问题(issue#630@Github)
 * 【core 】      BeanUtil.isEmpty()忽略字段支持,增加isNotEmpty(issue#629@Github)
-* 【extra 】     邮件发送后获取message-id(issue#I15FKR@Gitee)
+* 【extra】      邮件发送后获取message-id(issue#I15FKR@Gitee)
+* 【core 】      CaseInsensitiveMap/CamelCaseMap增加toString(issue#636@Github)
+* 【core 】      XmlUtil多节点改进(issue#I15I0R@Gitee)
 
 ### Bug修复
 * 【extra】      修复SFTP.upload上传失败的问题
 * 【db】         修复findLike匹配错误问题
+* 【core 】      修复scale方法透明无效问题(issue#I15L5S@Gitee)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 31 - 1
hutool-core/src/main/java/cn/hutool/core/convert/Convert.java

@@ -4,6 +4,8 @@ import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.nio.charset.Charset;
+import java.time.Instant;
+import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 
@@ -444,7 +446,35 @@ public class Convert {
 	public static Date toDate(Object value, Date defaultValue) {
 		return convertQuietly(Date.class, value, defaultValue);
 	}
-	
+
+	/**
+	 * LocalDateTime<br>
+	 * 如果给定的值为空,或者转换失败,返回默认值<br>
+	 * 转换失败不会报错
+	 *
+	 * @param value 被转换的值
+	 * @param defaultValue 转换错误时的默认值
+	 * @return 结果
+	 * @since 5.0.7
+	 */
+	public static Date toLocalDateTime(Object value, Date defaultValue) {
+		return convertQuietly(LocalDateTime.class, value, defaultValue);
+	}
+
+	/**
+	 * Instant<br>
+	 * 如果给定的值为空,或者转换失败,返回默认值<br>
+	 * 转换失败不会报错
+	 *
+	 * @param value 被转换的值
+	 * @param defaultValue 转换错误时的默认值
+	 * @return 结果
+	 * @since 5.0.7
+	 */
+	public static Date toInstant(Object value, Date defaultValue) {
+		return convertQuietly(Instant.class, value, defaultValue);
+	}
+
 	/**
 	 * 转换为Date<br>
 	 * 如果给定的值为空,或者转换失败,返回<code>null</code><br>

+ 19 - 31
hutool-core/src/main/java/cn/hutool/core/getter/OptNullBasicTypeFromObjectGetter.java

@@ -10,21 +10,20 @@ import cn.hutool.core.convert.Convert;
  * 基本类型的getter接口抽象实现,所有类型的值获取都是通过将getObj获得的值转换而来<br>
  * 用户只需实现getObj方法即可,其他类型将会从Object结果中转换
  * 在不提供默认值的情况下, 如果值不存在或获取错误,返回null<br>
+ *
  * @author Looly
  */
-public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTypeGetter<K>{
+public interface OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTypeGetter<K>{
 	
-	@Override
-	public String getStr(K key, String defaultValue) {
+	default String getStr(K key, String defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
 		}
 		return Convert.toStr(obj, defaultValue);
 	}
-	
-	@Override
-	public Integer getInt(K key, Integer defaultValue) {
+
+	default Integer getInt(K key, Integer defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -32,8 +31,7 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toInt(obj, defaultValue);
 	}
 
-	@Override
-	public Short getShort(K key, Short defaultValue) {
+	default Short getShort(K key, Short defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -41,8 +39,7 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toShort(obj, defaultValue);
 	}
 
-	@Override
-	public Boolean getBool(K key, Boolean defaultValue) {
+	default Boolean getBool(K key, Boolean defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -50,8 +47,7 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toBool(obj, defaultValue);
 	}
 
-	@Override
-	public Long getLong(K key, Long defaultValue) {
+	default Long getLong(K key, Long defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -59,17 +55,15 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toLong(obj, defaultValue);
 	}
 
-	@Override
-	public Character getChar(K key, Character defaultValue) {
+	default Character getChar(K key, Character defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
 		}
 		return Convert.toChar(obj, defaultValue);
 	}
-	
-	@Override
-	public Float getFloat(K key, Float defaultValue) {
+
+	default Float getFloat(K key, Float defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -77,8 +71,7 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toFloat(obj, defaultValue);
 	}
 
-	@Override
-	public Double getDouble(K key, Double defaultValue) {
+	default Double getDouble(K key, Double defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -86,8 +79,7 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toDouble(obj, defaultValue);
 	}
 
-	@Override
-	public Byte getByte(K key, Byte defaultValue) {
+	default Byte getByte(K key, Byte defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -95,8 +87,7 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toByte(obj, defaultValue);
 	}
 
-	@Override
-	public BigDecimal getBigDecimal(K key, BigDecimal defaultValue) {
+	default BigDecimal getBigDecimal(K key, BigDecimal defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
@@ -104,26 +95,23 @@ public abstract class OptNullBasicTypeFromObjectGetter<K> extends OptNullBasicTy
 		return Convert.toBigDecimal(obj, defaultValue);
 	}
 
-	@Override
-	public BigInteger getBigInteger(K key, BigInteger defaultValue) {
+	default BigInteger getBigInteger(K key, BigInteger defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
 		}
 		return Convert.toBigInteger(obj, defaultValue);
 	}
-	
-	@Override
-	public <E extends Enum<E>> E getEnum(Class<E> clazz, K key, E defaultValue) {
+
+	default <E extends Enum<E>> E getEnum(Class<E> clazz, K key, E defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;
 		}
 		return Convert.toEnum(clazz, obj, defaultValue);
 	}
-	
-	@Override
-	public Date getDate(K key, Date defaultValue) {
+
+	default Date getDate(K key, Date defaultValue) {
 		final Object obj = getObj(key);
 		if(null == obj) {
 			return defaultValue;

+ 14 - 27
hutool-core/src/main/java/cn/hutool/core/getter/OptNullBasicTypeFromStringGetter.java

@@ -12,70 +12,57 @@ import cn.hutool.core.convert.Convert;
  * 
  * @author Looly
  */
-public abstract class OptNullBasicTypeFromStringGetter<K> extends OptNullBasicTypeGetter<K> {
+public interface OptNullBasicTypeFromStringGetter<K> extends OptNullBasicTypeGetter<K> {
 
-	@Override
-	public Object getObj(K key, Object defaultValue) {
+	default Object getObj(K key, Object defaultValue) {
 		return getStr(key, null == defaultValue ? null : defaultValue.toString());
 	}
 
-	@Override
-	public Integer getInt(K key, Integer defaultValue) {
+	default Integer getInt(K key, Integer defaultValue) {
 		return Convert.toInt(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Short getShort(K key, Short defaultValue) {
+	default Short getShort(K key, Short defaultValue) {
 		return Convert.toShort(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Boolean getBool(K key, Boolean defaultValue) {
+	default Boolean getBool(K key, Boolean defaultValue) {
 		return Convert.toBool(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Long getLong(K key, Long defaultValue) {
+	default Long getLong(K key, Long defaultValue) {
 		return Convert.toLong(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Character getChar(K key, Character defaultValue) {
+	default Character getChar(K key, Character defaultValue) {
 		return Convert.toChar(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Float getFloat(K key, Float defaultValue) {
+	default Float getFloat(K key, Float defaultValue) {
 		return Convert.toFloat(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Double getDouble(K key, Double defaultValue) {
+	default Double getDouble(K key, Double defaultValue) {
 		return Convert.toDouble(getStr(key), defaultValue);
 	}
 
-	@Override
-	public Byte getByte(K key, Byte defaultValue) {
+	default Byte getByte(K key, Byte defaultValue) {
 		return Convert.toByte(getStr(key), defaultValue);
 	}
 
-	@Override
-	public BigDecimal getBigDecimal(K key, BigDecimal defaultValue) {
+	default BigDecimal getBigDecimal(K key, BigDecimal defaultValue) {
 		return Convert.toBigDecimal(getStr(key), defaultValue);
 	}
 
-	@Override
-	public BigInteger getBigInteger(K key, BigInteger defaultValue) {
+	default BigInteger getBigInteger(K key, BigInteger defaultValue) {
 		return Convert.toBigInteger(getStr(key), defaultValue);
 	}
 
-	@Override
-	public <E extends Enum<E>> E getEnum(Class<E> clazz, K key, E defaultValue) {
+	default <E extends Enum<E>> E getEnum(Class<E> clazz, K key, E defaultValue) {
 		return Convert.toEnum(clazz, getStr(key), defaultValue);
 	}
 
-	@Override
-	public Date getDate(K key, Date defaultValue) {
+	default Date getDate(K key, Date defaultValue) {
 		return Convert.toDate(getStr(key), defaultValue);
 	}
 }

+ 17 - 31
hutool-core/src/main/java/cn/hutool/core/getter/OptNullBasicTypeGetter.java

@@ -8,13 +8,12 @@ import java.util.Date;
  * 基本类型的getter接口抽象实现<br>
  * 提供一个统一的接口定义返回不同类型的值(基本类型)<br>
  * 在不提供默认值的情况下, 如果值不存在或获取错误,返回null<br>
- * 用户只需实现{@code com.xiaoleilu.hutool.getter.OptBasicTypeGetter}接口即可
+ * 用户只需实现{@link OptBasicTypeGetter}接口即可
  * @author Looly
  */
-public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, OptBasicTypeGetter<K>{
+public interface OptNullBasicTypeGetter<K> extends BasicTypeGetter<K>, OptBasicTypeGetter<K>{
 	
-	@Override
-	public Object getObj(K key) {
+	default Object getObj(K key) {
 		return getObj(key, null);
 	}
 	
@@ -25,8 +24,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public String getStr(K key){
+	default String getStr(K key){
 		return this.getStr(key, null);
 	}
 	
@@ -37,8 +35,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Integer getInt(K key) {
+	default Integer getInt(K key) {
 		return this.getInt(key, null);
 	}
 	
@@ -49,8 +46,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Short getShort(K key){
+	default Short getShort(K key){
 		return this.getShort(key, null);
 	}
 	
@@ -61,8 +57,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Boolean getBool(K key){
+	default Boolean getBool(K key){
 		return this.getBool(key, null);
 	}
 	
@@ -73,8 +68,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Long getLong(K key){
+	default Long getLong(K key){
 		return this.getLong(key, null);
 	}
 	
@@ -85,8 +79,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Character getChar(K key){
+	default Character getChar(K key){
 		return this.getChar(key, null);
 	}
 	
@@ -97,8 +90,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Float getFloat(K key){
+	default Float getFloat(K key){
 		return this.getFloat(key, null);
 	}
 	
@@ -109,11 +101,10 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Double getDouble(K key){
+	default Double getDouble(K key){
 		return this.getDouble(key, null);
 	}
-	
+
 	/**
 	 * 获取byte型属性值<br>
 	 * 无值或获取错误返回null
@@ -121,8 +112,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Byte getByte(K key){
+	default Byte getByte(K key){
 		return this.getByte(key, null);
 	}
 	
@@ -133,8 +123,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public BigDecimal getBigDecimal(K key){
+	default BigDecimal getBigDecimal(K key){
 		return this.getBigDecimal(key, null);
 	}
 	
@@ -145,8 +134,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public BigInteger getBigInteger(K key){
+	default BigInteger getBigInteger(K key){
 		return this.getBigInteger(key, null);
 	}
 	
@@ -158,8 +146,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public <E extends Enum<E>> E getEnum(Class<E> clazz, K key) {
+	default <E extends Enum<E>> E getEnum(Class<E> clazz, K key) {
 		return this.getEnum(clazz, key, null);
 	}
 	
@@ -170,8 +157,7 @@ public abstract class OptNullBasicTypeGetter<K> implements BasicTypeGetter<K>, O
 	 * @param key 属性名
 	 * @return 属性值
 	 */
-	@Override
-	public Date getDate(K key) {
+	default Date getDate(K key) {
 		return this.getDate(key, null);
 	}
 }

+ 23 - 6
hutool-core/src/main/java/cn/hutool/core/img/Img.java

@@ -53,7 +53,7 @@ public class Img implements Serializable {
 	/**
 	 * 目标图片文件格式,用于写出
 	 */
-	private String targetImageType = ImgUtil.IMAGE_TYPE_JPG;
+	private String targetImageType;
 	/**
 	 * 计算x,y坐标的时候是否从中心做为原始坐标开始计算
 	 */
@@ -140,7 +140,22 @@ public class Img implements Serializable {
 	 * @param srcImage 来源图片
 	 */
 	public Img(BufferedImage srcImage) {
+		this(srcImage, null);
+	}
+
+	/**
+	 * 构造
+	 *
+	 * @param srcImage 来源图片
+	 * @param targetImageType 目标图片类型
+	 * @since 5.0.7
+	 */
+	public Img(BufferedImage srcImage, String targetImageType) {
 		this.srcImage = srcImage;
+		if(null == targetImageType){
+			targetImageType = ImgUtil.IMAGE_TYPE_JPG;
+		}
+		this.targetImageType = targetImageType;
 	}
 
 	/**
@@ -294,15 +309,14 @@ public class Img implements Serializable {
 		srcHeight = srcImage.getHeight(null);
 		srcWidth = srcImage.getWidth(null);
 
-		if (null == fixedColor) {// 补白
-			fixedColor = Color.WHITE;
-		}
 		final BufferedImage image = new BufferedImage(width, height, getTypeInt());
 		Graphics2D g = image.createGraphics();
 
 		// 设置背景
-		g.setBackground(fixedColor);
-		g.clearRect(0, 0, width, height);
+		if(null != fixedColor){
+			g.setBackground(fixedColor);
+			g.clearRect(0, 0, width, height);
+		}
 
 		// 在中间贴图
 		g.drawImage(srcImage, (width - srcWidth) / 2, (height - srcHeight) / 2, srcWidth, srcHeight, fixedColor, null);
@@ -586,6 +600,7 @@ public class Img implements Serializable {
 		}
 
 		if (targetFile.exists()) {
+			//noinspection ResultOfMethodCallIgnored
 			targetFile.delete();
 		}
 
@@ -624,6 +639,7 @@ public class Img implements Serializable {
 	 * @see BufferedImage#TYPE_INT_RGB
 	 */
 	private int getTypeInt() {
+		//noinspection SwitchStatementWithTooFewBranches
 		switch (this.targetImageType) {
 			case ImgUtil.IMAGE_TYPE_PNG:
 				return BufferedImage.TYPE_INT_ARGB;
@@ -678,6 +694,7 @@ public class Img implements Serializable {
 		if (degree >= 90) {
 			if (degree / 90 % 2 == 1) {
 				int temp = height;
+				//noinspection SuspiciousNameCombination
 				height = width;
 				width = temp;
 			}

+ 8 - 5
hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java

@@ -171,17 +171,20 @@ public class ImgUtil {
 
 	/**
 	 * 缩放图像(按高度和宽度缩放)<br>
-	 * 缩放后默认为jpeg格式
+	 * 缩放后默认格式与源图片相同,无法识别原图片默认JPG
 	 *
 	 * @param srcImageFile  源图像文件地址
 	 * @param destImageFile 缩放后的图像地址
 	 * @param width         缩放后的宽度
 	 * @param height        缩放后的高度
-	 * @param fixedColor    比例不对时补充的颜色,不补充为<code>null</code>
+	 * @param fixedColor    补充的颜色,不补充为<code>null</code>
 	 * @throws IORuntimeException IO异常
 	 */
 	public static void scale(File srcImageFile, File destImageFile, int width, int height, Color fixedColor) throws IORuntimeException {
-		write(scale(read(srcImageFile), width, height, fixedColor), destImageFile);
+		Img.from(srcImageFile)//
+				.setTargetImageType(FileUtil.extName(destImageFile))//
+				.scale(width, height, fixedColor)//
+				.write(destImageFile);
 	}
 
 	/**
@@ -397,12 +400,12 @@ public class ImgUtil {
 				if (srcWidth % destWidth == 0) {
 					cols = srcWidth / destWidth;
 				} else {
-					cols = (int) Math.floor(srcWidth / destWidth) + 1;
+					cols = (int) Math.floor((double)srcWidth / destWidth) + 1;
 				}
 				if (srcHeight % destHeight == 0) {
 					rows = srcHeight / destHeight;
 				} else {
-					rows = (int) Math.floor(srcHeight / destHeight) + 1;
+					rows = (int) Math.floor((double)srcHeight / destHeight) + 1;
 				}
 				// 循环建立切片
 				Image tag;

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/map/CamelCaseLinkedMap.java

@@ -60,7 +60,7 @@ public class CamelCaseLinkedMap<K, V> extends CamelCaseMap<K, V> {
 	 * @param loadFactor 加载因子
 	 */
 	public CamelCaseLinkedMap(int initialCapacity, float loadFactor) {
-		super(new HashMap<K, V>(initialCapacity, loadFactor));
+		super(new HashMap<>(initialCapacity, loadFactor));
 	}
 	// ------------------------------------------------------------------------- Constructor end
 }

+ 2 - 2
hutool-core/src/main/java/cn/hutool/core/map/CamelCaseMap.java

@@ -62,7 +62,7 @@ public class CamelCaseMap<K, V> extends CustomKeyMap<K, V> {
 	 * @param loadFactor 加载因子
 	 */
 	public CamelCaseMap(int initialCapacity, float loadFactor) {
-		super(new HashMap<K, V>(initialCapacity, loadFactor));
+		super(new HashMap<>(initialCapacity, loadFactor));
 	}
 	// ------------------------------------------------------------------------- Constructor end
 
@@ -74,7 +74,7 @@ public class CamelCaseMap<K, V> extends CustomKeyMap<K, V> {
 	 */
 	@Override
 	protected Object customKey(Object key) {
-		if (null != key && key instanceof CharSequence) {
+		if (key instanceof CharSequence) {
 			key = StrUtil.toCamelCase(key.toString());
 		}
 		return key;

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/map/CaseInsensitiveLinkedMap.java

@@ -61,7 +61,7 @@ public class CaseInsensitiveLinkedMap<K, V> extends CaseInsensitiveMap<K, V> {
 	 * @param loadFactor 加载因子
 	 */
 	public CaseInsensitiveLinkedMap(int initialCapacity, float loadFactor) {
-		super(new LinkedHashMap<K, V>(initialCapacity, loadFactor));
+		super(new LinkedHashMap<>(initialCapacity, loadFactor));
 	}
 	// ------------------------------------------------------------------------- Constructor end
 }

+ 5 - 5
hutool-core/src/main/java/cn/hutool/core/map/MapProxy.java

@@ -21,7 +21,7 @@ import cn.hutool.core.util.StrUtil;
  * @author looly
  * @since 3.2.0
  */
-public class MapProxy extends OptNullBasicTypeFromObjectGetter<Object> implements Map<Object, Object>, InvocationHandler, Serializable {
+public class MapProxy implements Map<Object, Object>, OptNullBasicTypeFromObjectGetter<Object>, InvocationHandler, Serializable {
 	private static final long serialVersionUID = 1L;
 
 	@SuppressWarnings("rawtypes")
@@ -89,7 +89,7 @@ public class MapProxy extends OptNullBasicTypeFromObjectGetter<Object> implement
 		return map.remove(key);
 	}
 
-	@SuppressWarnings("unchecked")
+	@SuppressWarnings({"unchecked", "NullableProblems"})
 	@Override
 	public void putAll(Map<?, ?> m) {
 		map.putAll(m);
@@ -100,19 +100,19 @@ public class MapProxy extends OptNullBasicTypeFromObjectGetter<Object> implement
 		map.clear();
 	}
 
-	@SuppressWarnings("unchecked")
+	@SuppressWarnings({"unchecked", "NullableProblems"})
 	@Override
 	public Set<Object> keySet() {
 		return map.keySet();
 	}
 
-	@SuppressWarnings("unchecked")
+	@SuppressWarnings({"unchecked", "NullableProblems"})
 	@Override
 	public Collection<Object> values() {
 		return map.values();
 	}
 
-	@SuppressWarnings("unchecked")
+	@SuppressWarnings({"unchecked", "NullableProblems"})
 	@Override
 	public Set<Entry<Object, Object>> entrySet() {
 		return map.entrySet();

+ 13 - 4
hutool-core/src/main/java/cn/hutool/core/map/MapWrapper.java

@@ -79,6 +79,7 @@ public class MapWrapper<K, V> implements Map<K, V>, Iterable<Map.Entry<K, V>>, S
 	}
 
 	@Override
+	@SuppressWarnings("NullableProblems")
 	public void putAll(Map<? extends K, ? extends V> m) {
 		raw.putAll(m);
 	}
@@ -89,23 +90,31 @@ public class MapWrapper<K, V> implements Map<K, V>, Iterable<Map.Entry<K, V>>, S
 	}
 
 	@Override
-	public Set<K> keySet() {
-		return raw.keySet();
+	@SuppressWarnings("NullableProblems")
+	public Collection<V> values() {
+		return raw.values();
 	}
 
 	@Override
-	public Collection<V> values() {
-		return raw.values();
+	@SuppressWarnings("NullableProblems")
+	public Set<K> keySet() {
+		return raw.keySet();
 	}
 
 	@Override
+	@SuppressWarnings("NullableProblems")
 	public Set<Entry<K, V>> entrySet() {
 		return raw.entrySet();
 	}
 
 	@Override
+	@SuppressWarnings("NullableProblems")
 	public Iterator<Entry<K, V>> iterator() {
 		return this.entrySet().iterator();
 	}
 
+	@Override
+	public String toString() {
+		return raw.toString();
+	}
 }

+ 7 - 1
hutool-core/src/main/java/cn/hutool/core/util/XmlUtil.java

@@ -33,6 +33,7 @@ import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
+import cn.hutool.core.collection.CollUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -756,7 +757,12 @@ public class XmlUtil {
 			childNode = nodeList.item(i);
 			if (isElement(childNode)) {
 				childEle = (Element) childNode;
-				result.put(childEle.getNodeName(), childEle.getTextContent());
+				final Object value = result.get(childEle.getNodeName());
+				if(null != value){
+					result.put(childEle.getNodeName(), CollUtil.newArrayList(value, childEle.getTextContent()));
+				} else{
+					result.put(childEle.getNodeName(), childEle.getTextContent());
+				}
 			}
 		}
 		return result;

+ 15 - 7
hutool-core/src/test/java/cn/hutool/core/util/XmlUtilTest.java

@@ -1,17 +1,16 @@
 package cn.hutool.core.util;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.xml.xpath.XPathConstants;
-
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapBuilder;
+import cn.hutool.core.map.MapUtil;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.w3c.dom.Document;
 
-import cn.hutool.core.map.MapBuilder;
-import cn.hutool.core.map.MapUtil;
+import javax.xml.xpath.XPathConstants;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 /**
  * {@link XmlUtil} 工具类
@@ -87,6 +86,15 @@ public class XmlUtilTest {
 	}
 
 	@Test
+	public void xmlToMapTest2() {
+		String xml = "<root><name>张三</name><name>李四</name></root>";
+		Map<String, Object> map = XmlUtil.xmlToMap(xml);
+
+		Assert.assertEquals(1, map.size());
+		Assert.assertEquals(CollUtil.newArrayList("张三", "李四"), map.get("name"));
+	}
+
+	@Test
 	public void mapToXmlTest() {
 		Map<String, Object> map = MapBuilder.create(new LinkedHashMap<String, Object>())//
 				.put("name", "张三")//

+ 15 - 3
hutool-json/src/main/java/cn/hutool/json/JSONArray.java

@@ -19,6 +19,8 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.RandomAccess;
 
+import static cn.hutool.json.JSONConverter.*;
+
 /**
  * JSON数组<br>
  * JSON数组是表示中括号括住的数据表现形式<br>
@@ -30,7 +32,7 @@ import java.util.RandomAccess;
  * 
  * @author looly
  */
-public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>, RandomAccess {
+public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, RandomAccess {
 	private static final long serialVersionUID = 2664900568717612292L;
 
 	/** 默认初始大小 */
@@ -236,7 +238,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 
 	@Override
 	public <T> T getByPath(String expression, Class<T> resultType) {
-		return JSONConverter.jsonConvert(resultType, getByPath(expression), true);
+		return jsonConvert(resultType, getByPath(expression), true);
 	}
 
 	@Override
@@ -314,6 +316,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		}
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public Iterator<Object> iterator() {
 		return rawList.iterator();
@@ -344,13 +347,14 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		return rawList.contains(o);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public Object[] toArray() {
 		return rawList.toArray();
 	}
 
 	@Override
-	@SuppressWarnings("unchecked")
+	@SuppressWarnings({"unchecked", "NullableProblems"})
 	public <T> T[] toArray(T[] a) {
 		return (T[]) JSONConverter.toArray(this, a.getClass().getComponentType());
 	}
@@ -370,11 +374,13 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		return rawList.remove(o);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public boolean containsAll(Collection<?> c) {
 		return rawList.containsAll(c);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public boolean addAll(Collection<?> c) {
 		if (CollUtil.isEmpty(c)) {
@@ -386,6 +392,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		return true;
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public boolean addAll(int index, Collection<?> c) {
 		if (CollUtil.isEmpty(c)) {
@@ -398,11 +405,13 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		return rawList.addAll(index, list);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public boolean removeAll(Collection<?> c) {
 		return this.rawList.removeAll(c);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public boolean retainAll(Collection<?> c) {
 		return this.rawList.retainAll(c);
@@ -446,16 +455,19 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		return this.rawList.lastIndexOf(o);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public ListIterator<Object> listIterator() {
 		return this.rawList.listIterator();
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public ListIterator<Object> listIterator(int index) {
 		return this.rawList.listIterator(index);
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public List<Object> subList(int fromIndex, int toIndex) {
 		return this.rawList.subList(fromIndex, toIndex);

+ 9 - 9
hutool-json/src/main/java/cn/hutool/json/JSONGetter.java

@@ -9,7 +9,7 @@ import cn.hutool.core.getter.OptNullBasicTypeFromObjectGetter;
  *
  * @param <K> Key类型
  */
-public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
+public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	
 	/**
 	 * key对应值是否为<code>null</code>或无此key
@@ -17,7 +17,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @param key 键
 	 * @return true 无此key或值为<code>null</code>或{@link JSONNull#NULL}返回<code>false</code>,其它返回<code>true</code>
 	 */
-	public boolean isNull(K key) {
+	default boolean isNull(K key) {
 		return JSONNull.NULL.equals(this.getObj(key));
 	}
 	
@@ -28,7 +28,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @return 字符串类型值
 	 * @since 4.2.2
 	 */
-	public String getStrEscaped(K key) {
+	default String getStrEscaped(K key) {
 		return getStrEscaped(key, null);
 	}
 	
@@ -40,7 +40,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @return 字符串类型值
 	 * @since 4.2.2
 	 */
-	public String getStrEscaped(K key, String defaultValue) {
+	default String getStrEscaped(K key, String defaultValue) {
 		return JSONUtil.escape(getStr(key, defaultValue));
 	}
 	
@@ -51,7 +51,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @param key KEY
 	 * @return JSONArray对象,如果值为null或者非JSONArray类型,返回null
 	 */
-	public JSONArray getJSONArray(K key) {
+	default JSONArray getJSONArray(K key) {
 		final Object object = this.getObj(key);
 		if(null == object) {
 			return null;
@@ -70,7 +70,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @param key KEY
 	 * @return JSONArray对象,如果值为null或者非JSONObject类型,返回null
 	 */
-	public JSONObject getJSONObject(K key) {
+	default JSONObject getJSONObject(K key) {
 		final Object object = this.getObj(key);
 		if(null == object) {
 			return null;
@@ -92,7 +92,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @return Bean对象,如果值为null或者非JSONObject类型,返回null
 	 * @since 3.1.1
 	 */
-	public <T> T getBean(K key, Class<T> beanType) {
+	default <T> T getBean(K key, Class<T> beanType) {
 		final JSONObject obj = getJSONObject(key);
 		return (null == obj) ? null : obj.toBean(beanType);
 	}
@@ -108,7 +108,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @throws ConvertException 转换异常
 	 * @since 3.0.8
 	 */
-	public <T> T get(K key, Class<T> type) throws ConvertException{
+	default <T> T get(K key, Class<T> type) throws ConvertException{
 		return get(key, type, false);
 	}
 	
@@ -123,7 +123,7 @@ public abstract class JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K>{
 	 * @throws ConvertException 转换异常
 	 * @since 3.0.8
 	 */
-	public <T> T get(K key, Class<T> type, boolean ignoreError) throws ConvertException{
+	default <T> T get(K key, Class<T> type, boolean ignoreError) throws ConvertException{
 		final Object value = this.getObj(key);
 		if(null == value){
 			return null;

+ 6 - 3
hutool-json/src/main/java/cn/hutool/json/JSONObject.java

@@ -37,7 +37,7 @@ import java.util.Set;
  * 
  * @author looly
  */
-public class JSONObject extends JSONGetter<String> implements JSON, Map<String, Object> {
+public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object> {
 	private static final long serialVersionUID = -330220388580734346L;
 
 	/** 默认初始大小 */
@@ -163,7 +163,7 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 	 */
 	public JSONObject(Object source, boolean ignoreNullValue, boolean isOrder) {
 		this(source, JSONConfig.create().setOrder(isOrder)//
-				.setIgnoreCase((source instanceof CaseInsensitiveMap) || (source instanceof CaseInsensitiveLinkedMap))//
+				.setIgnoreCase((source instanceof CaseInsensitiveMap))//
 				.setIgnoreNullValue(ignoreNullValue));
 	}
 
@@ -478,16 +478,19 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 		rawHashMap.clear();
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public Set<String> keySet() {
 		return this.rawHashMap.keySet();
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public Collection<Object> values() {
 		return rawHashMap.values();
 	}
 
+	@SuppressWarnings("NullableProblems")
 	@Override
 	public Set<Entry<String, Object>> entrySet() {
 		return rawHashMap.entrySet();
@@ -643,7 +646,7 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 	 * 
 	 * @param source JavaBean或者Map对象或者String
 	 */
-	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@SuppressWarnings({"rawtypes", "unchecked", "StatementWithEmptyBody"})
 	private void init(Object source) {
 		if (null == source) {
 			return;

+ 1 - 1
hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java

@@ -18,7 +18,7 @@ import cn.hutool.log.LogFactory;
  *
  * @author Looly
  */
-public abstract class AbsSetting extends OptNullBasicTypeFromStringGetter<String> implements Serializable {
+public abstract class AbsSetting implements OptNullBasicTypeFromStringGetter<String>, Serializable {
 	private static final long serialVersionUID = 6200156302595905863L;
 	private final static Log log = LogFactory.get();