diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java index 16733ad4c..cd8980df6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java @@ -29,9 +29,9 @@ public class AnnotationProxy implements Annotation, Invoca * * @param annotation 注解 */ + @SuppressWarnings("unchecked") public AnnotationProxy(T annotation) { this.annotation = annotation; - //noinspection unchecked this.type = (Class) annotation.annotationType(); this.attributes = initAttributes(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index cd6deba6b..c90018e21 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -74,13 +74,13 @@ public class AnnotationUtil { * @return 注解对象数组 * @since 5.8.0 */ + @SuppressWarnings("unchecked") public static T[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Class annotationType) { final Annotation[] annotations = getAnnotations(annotationEle, isToCombination, (annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass()))); final T[] result = ArrayUtil.newArray(annotationType, annotations.length); for (int i = 0; i < annotations.length; i++) { - //noinspection unchecked result[i] = (T) annotations[i]; } return result; diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java index 2752733d7..9837b1b5f 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java @@ -34,6 +34,7 @@ public class BeanToMapCopier extends AbsCopier { this.targetType = targetType; } + @SuppressWarnings("unchecked") @Override public Map copy() { Class actualEditable = source.getClass(); @@ -73,7 +74,6 @@ public class BeanToMapCopier extends AbsCopier { // 目标赋值 if(null != sValue || false == copyOptions.ignoreNullValue){ - //noinspection unchecked target.put(sFieldName, sValue); } }); diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java index 8e8a0a5a5..bc05c0482 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java @@ -23,18 +23,18 @@ public class Base16Codec implements Encoder, Decoder>> 4];// 高位 - out[j++] = alphabets[0x0F & data[i]];// 低位 + out[j++] = hexDigit(data[i] >> 4);// 高位 + out[j++] = hexDigit(data[i]);// 低位 } return out; } @@ -79,12 +79,12 @@ public class Base16Codec implements Encoder, Decoder> 12) & 15] +// - alphabets[(ch >> 8) & 15] +// - alphabets[(ch >> 4) & 15] +// - alphabets[(ch) & 15]; + public String toUnicodeHex(final char ch) { + return "\\u" + + hexDigit(ch >> 12) + + hexDigit(ch >> 8) + + hexDigit(ch >> 4) + + hexDigit(ch); } /** @@ -94,10 +94,21 @@ public class Base16Codec implements Encoder, Decoder>> 4;//高位 - int low = b & 0x0f;//低位 - builder.append(alphabets[high]); - builder.append(alphabets[low]); + //高位 + builder.append(hexDigit(b >> 4)); + //低位 + builder.append(hexDigit(b)); + } + + /** + * 将byte值转为16进制 + * + * @param b byte + * @return hex char + * @since 6.0.0 + */ + public char hexDigit(final int b) { + return alphabets[b & 0x0f]; } /** @@ -108,7 +119,7 @@ public class Base16Codec implements Encoder, Decoder, Serializable { private static final long serialVersionUID = 1L; - /** - * 从已知PercentCodec创建PercentCodec,会复制给定PercentCodec的安全字符 - * - * @param codec PercentCodec - * @return PercentCodec - */ - public static PercentCodec of(PercentCodec codec) { - return new PercentCodec((BitSet) codec.safeCharacters.clone()); - } - - /** - * 创建PercentCodec,使用指定字符串中的字符作为安全字符 - * - * @param chars 安全字符合集 - * @return PercentCodec - */ - public static PercentCodec of(CharSequence chars) { - final PercentCodec codec = new PercentCodec(); - final int length = chars.length(); - for (int i = 0; i < length; i++) { - codec.addSafe(chars.charAt(i)); - } - return codec; - } + private static final char DEFAULT_SIZE = 256; + private static final char ESCAPE_CHAR = CharPool.PERCENT; /** * 存放安全编码 @@ -75,7 +55,7 @@ public class PercentCodec implements Serializable { * [a-zA-Z0-9]默认不被编码 */ public PercentCodec() { - this(new BitSet(256)); + this(new BitSet(DEFAULT_SIZE)); } /** @@ -88,68 +68,33 @@ public class PercentCodec implements Serializable { } /** - * 增加安全字符
- * 安全字符不被编码 + * 检查给定字符是否为安全字符 * * @param c 字符 - * @return this + * @return {@code true}表示安全,否则非安全字符 + * @since 6.0.0 */ - public PercentCodec addSafe(char c) { - safeCharacters.set(c); - return this; + public boolean isSafe(char c) { + return this.safeCharacters.get(c); } - /** - * 移除安全字符
- * 安全字符不被编码 - * - * @param c 字符 - * @return this - */ - public PercentCodec removeSafe(char c) { - safeCharacters.clear(c); - return this; - } + @Override + public byte[] encode(byte[] bytes) { + // 初始容量计算,简单粗暴假设所有byte都需要转义,容量是三倍 + final ByteBuffer buffer = ByteBuffer.allocate(bytes.length * 3); + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < bytes.length; i++) { + encodeTo(buffer, bytes[i]); + } - /** - * 增加安全字符到挡墙的PercentCodec - * - * @param codec PercentCodec - * @return this - */ - public PercentCodec or(PercentCodec codec) { - this.safeCharacters.or(codec.safeCharacters); - return this; - } - - /** - * 组合当前PercentCodec和指定PercentCodec为一个新的PercentCodec,安全字符为并集 - * - * @param codec PercentCodec - * @return 新的PercentCodec - */ - public PercentCodec orNew(PercentCodec codec) { - return of(this).or(codec); - } - - /** - * 是否将空格编码为+
- * 如果为{@code true},则将空格编码为"+",此项只在"application/x-www-form-urlencoded"中使用
- * 如果为{@code false},则空格编码为"%20",此项一般用于URL的Query部分(RFC3986规范) - * - * @param encodeSpaceAsPlus 是否将空格编码为+ - * @return this - */ - public PercentCodec setEncodeSpaceAsPlus(boolean encodeSpaceAsPlus) { - this.encodeSpaceAsPlus = encodeSpaceAsPlus; - return this; + return buffer.array(); } /** * 将URL中的字符串编码为%形式 * - * @param path 需要编码的字符串 - * @param charset 编码, {@code null}返回原字符串,表示不编码 + * @param path 需要编码的字符串 + * @param charset 编码, {@code null}返回原字符串,表示不编码 * @param customSafeChar 自定义安全字符 * @return 编码后的字符串 */ @@ -158,7 +103,7 @@ public class PercentCodec implements Serializable { return StrUtil.str(path); } - final StringBuilder rewrittenPath = new StringBuilder(path.length()); + final StringBuilder rewrittenPath = new StringBuilder(path.length() * 3); final ByteArrayOutputStream buf = new ByteArrayOutputStream(); final OutputStreamWriter writer = new OutputStreamWriter(buf, charset); @@ -184,7 +129,7 @@ public class PercentCodec implements Serializable { byte[] ba = buf.toByteArray(); for (byte toEncode : ba) { // Converting each byte in the buffer - rewrittenPath.append('%'); + rewrittenPath.append(ESCAPE_CHAR); HexUtil.appendHex(rewrittenPath, toEncode, false); } buf.reset(); @@ -192,4 +137,132 @@ public class PercentCodec implements Serializable { } return rewrittenPath.toString(); } + + /** + * 将单一byte转义到{@link ByteBuffer}中 + * + * @param buffer {@link ByteBuffer} + * @param b 字符byte + */ + private void encodeTo(final ByteBuffer buffer, final byte b) { + if (safeCharacters.get(b)) { + // 跳过安全字符 + buffer.put(b); + } else if (encodeSpaceAsPlus && b == CharPool.SPACE) { + // 对于空格单独处理 + buffer.put((byte) CharPool.PLUS); + } else { + buffer.put((byte) ESCAPE_CHAR); + buffer.put((byte) Base16Codec.CODEC_UPPER.hexDigit(b >> 4)); + buffer.put((byte) Base16Codec.CODEC_UPPER.hexDigit(b)); + } + } + + /** + * {@link PercentCodec}构建器
+ * 由于{@link PercentCodec}本身应该是只读对象,因此将此对象的构建放在Builder中 + * + * @author looly + * @since 6.0.0 + */ + public static class Builder implements cn.hutool.core.builder.Builder { + /** + * 从已知PercentCodec创建PercentCodec,会复制给定PercentCodec的安全字符 + * + * @param codec PercentCodec + * @return PercentCodec + */ + public static Builder of(PercentCodec codec) { + return new Builder(new PercentCodec((BitSet) codec.safeCharacters.clone())); + } + + /** + * 创建PercentCodec,使用指定字符串中的字符作为安全字符 + * + * @param chars 安全字符合集 + * @return PercentCodec + */ + public static Builder of(CharSequence chars) { + Builder builder = of(new PercentCodec()); + final int length = chars.length(); + for (int i = 0; i < length; i++) { + builder.addSafe(chars.charAt(i)); + } + return builder; + } + + private final PercentCodec codec; + + private Builder(PercentCodec codec) { + this.codec = codec; + } + + /** + * 增加安全字符
+ * 安全字符不被编码 + * + * @param c 字符 + * @return this + */ + public Builder addSafe(char c) { + codec.safeCharacters.set(c); + return this; + } + + /** + * 增加安全字符
+ * 安全字符不被编码 + * + * @param chars 安全字符 + * @return this + */ + public Builder addSafes(String chars) { + final int length = chars.length(); + for (int i = 0; i < length; i++) { + addSafe(chars.charAt(i)); + } + return this; + } + + /** + * 移除安全字符
+ * 安全字符不被编码 + * + * @param c 字符 + * @return this + */ + public Builder removeSafe(char c) { + codec.safeCharacters.clear(c); + return this; + } + + /** + * 增加安全字符到当前的PercentCodec + * + * @param otherCodec {@link PercentCodec} + * @return this + */ + public Builder or(PercentCodec otherCodec) { + codec.safeCharacters.or(otherCodec.safeCharacters); + return this; + } + + /** + * 是否将空格编码为+
+ * 如果为{@code true},则将空格编码为"+",此项只在"application/x-www-form-urlencoded"中使用
+ * 如果为{@code false},则空格编码为"%20",此项一般用于URL的Query部分(RFC3986规范) + * + * @param encodeSpaceAsPlus 是否将空格编码为+ + * @return this + */ + public Builder setEncodeSpaceAsPlus(boolean encodeSpaceAsPlus) { + codec.encodeSpaceAsPlus = encodeSpaceAsPlus; + return this; + } + + @Override + public PercentCodec build() { + return codec; + } + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/UniqueKeySet.java b/hutool-core/src/main/java/cn/hutool/core/collection/UniqueKeySet.java index 0c5e3f46f..e89d37ee4 100755 --- a/hutool-core/src/main/java/cn/hutool/core/collection/UniqueKeySet.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/UniqueKeySet.java @@ -115,9 +115,9 @@ public class UniqueKeySet extends AbstractSet implements Serializable { return map.isEmpty(); } + @SuppressWarnings("unchecked") @Override public boolean contains(Object o) { - //noinspection unchecked return map.containsKey(this.uniqueGenerator.apply((V) o)); } @@ -151,9 +151,9 @@ public class UniqueKeySet extends AbstractSet implements Serializable { return modified; } + @SuppressWarnings("unchecked") @Override public boolean remove(Object o) { - //noinspection unchecked return null != map.remove(this.uniqueGenerator.apply((V) o)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java index 879597cd8..625d35f81 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java @@ -101,15 +101,6 @@ public class FastByteArrayOutputStream extends OutputStream { return toString(CharsetUtil.defaultCharset()); } - /** - * 转为字符串 - * @param charsetName 编码 - * @return 字符串 - */ - public String toString(String charsetName) { - return toString(CharsetUtil.charset(charsetName)); - } - /** * 转为字符串 * @param charset 编码,null表示默认编码 diff --git a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java index d38d40d0e..54296974f 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java @@ -567,6 +567,7 @@ public class IoUtil extends NioUtil { * @throws IORuntimeException IO异常 * @throws UtilException ClassNotFoundException包装 */ + @SuppressWarnings("unchecked") public static T readObj(ValidateObjectInputStream in, Class clazz) throws IORuntimeException, UtilException { if (in == null) { throw new IllegalArgumentException("The InputStream must not be null"); @@ -575,7 +576,6 @@ public class IoUtil extends NioUtil { in.accept(clazz); } try { - //noinspection unchecked return (T) in.readObject(); } catch (IOException e) { throw new IORuntimeException(e); diff --git a/hutool-core/src/main/java/cn/hutool/core/map/CamelCaseMap.java b/hutool-core/src/main/java/cn/hutool/core/map/CamelCaseMap.java index ae75ed97a..9bd311853 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/CamelCaseMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/CamelCaseMap.java @@ -71,12 +71,12 @@ public class CamelCaseMap extends FuncKeyMap { * * @param emptyMapBuilder Map构造器,必须构造空的Map */ + @SuppressWarnings("unchecked") CamelCaseMap(MapBuilder emptyMapBuilder) { super(emptyMapBuilder.build(), (key) -> { if (key instanceof CharSequence) { key = StrUtil.toCamelCase(key.toString()); } - //noinspection unchecked return (K) key; }); } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/CaseInsensitiveMap.java b/hutool-core/src/main/java/cn/hutool/core/map/CaseInsensitiveMap.java index 40f805ad0..88b6e594d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/CaseInsensitiveMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/CaseInsensitiveMap.java @@ -71,12 +71,12 @@ public class CaseInsensitiveMap extends FuncKeyMap { * * @param emptyMapBuilder 被包装的自定义Map创建器 */ + @SuppressWarnings("unchecked") CaseInsensitiveMap(MapBuilder emptyMapBuilder) { super(emptyMapBuilder.build(), (key)->{ if (key instanceof CharSequence) { key = key.toString().toLowerCase(); } - //noinspection unchecked return (K) key; }); } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/CustomKeyMap.java b/hutool-core/src/main/java/cn/hutool/core/map/CustomKeyMap.java index 701f0d13e..4d5dde881 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/CustomKeyMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/CustomKeyMap.java @@ -24,9 +24,9 @@ public abstract class CustomKeyMap extends TransMap { super(emptyMap); } + @SuppressWarnings("unchecked") @Override protected V customValue(Object value) { - //noinspection unchecked return (V)value; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/FuncKeyMap.java b/hutool-core/src/main/java/cn/hutool/core/map/FuncKeyMap.java index 91a6f231a..9254e540f 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/FuncKeyMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/FuncKeyMap.java @@ -37,12 +37,12 @@ public class FuncKeyMap extends CustomKeyMap { * @param key KEY * @return 驼峰Key */ + @SuppressWarnings("unchecked") @Override protected K customKey(Object key) { if (null != this.keyFunc) { return keyFunc.apply(key); } - //noinspection unchecked return (K)key; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/FuncMap.java b/hutool-core/src/main/java/cn/hutool/core/map/FuncMap.java index 7007a2822..6aa6c83a0 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/FuncMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/FuncMap.java @@ -53,21 +53,21 @@ public class FuncMap extends TransMap { * @param key KEY * @return 驼峰Key */ + @SuppressWarnings("unchecked") @Override protected K customKey(Object key) { if (null != this.keyFunc) { return keyFunc.apply(key); } - //noinspection unchecked return (K) key; } + @SuppressWarnings("unchecked") @Override protected V customValue(Object value) { if (null != this.valueFunc) { return valueFunc.apply(value); } - //noinspection unchecked return (V) value; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsTable.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsTable.java index ac040164f..730fb76dc 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsTable.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsTable.java @@ -69,9 +69,9 @@ public abstract class AbsTable implements Table { return new TransIter<>(cellSet().iterator(), Cell::getValue); } + @SuppressWarnings("unchecked") @Override public boolean contains(Object o) { - //noinspection unchecked return containsValue((V) o); } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java b/hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java index ddd4d1c72..789b326b6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java @@ -14,6 +14,6 @@ public class FormUrlencoded { * query中的value,默认除"-", "_", ".", "*"外都编码
* 这个类似于JDK提供的{@link java.net.URLEncoder} */ - public static final PercentCodec ALL = PercentCodec.of(RFC3986.UNRESERVED) - .removeSafe('~').addSafe('*').setEncodeSpaceAsPlus(true); + public static final PercentCodec ALL = PercentCodec.Builder.of(RFC3986.UNRESERVED) + .removeSafe('~').addSafe('*').setEncodeSpaceAsPlus(true).build(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java b/hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java index d3811b162..596770e14 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java @@ -14,29 +14,29 @@ public class RFC3986 { /** * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" */ - public static final PercentCodec GEN_DELIMS = PercentCodec.of(":/?#[]@"); + public static final PercentCodec GEN_DELIMS = PercentCodec.Builder.of(":/?#[]@").build(); /** * sub-delims = "!" / "$" / "{@code &}" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" */ - public static final PercentCodec SUB_DELIMS = PercentCodec.of("!$&'()*+,;="); + public static final PercentCodec SUB_DELIMS = PercentCodec.Builder.of("!$&'()*+,;=").build(); /** * reserved = gen-delims / sub-delims
* see:https://www.ietf.org/rfc/rfc3986.html#section-2.2 */ - public static final PercentCodec RESERVED = GEN_DELIMS.orNew(SUB_DELIMS); + public static final PercentCodec RESERVED = PercentCodec.Builder.of(GEN_DELIMS).or(SUB_DELIMS).build(); /** * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* see: https://www.ietf.org/rfc/rfc3986.html#section-2.3 */ - public static final PercentCodec UNRESERVED = PercentCodec.of(unreservedChars()); + public static final PercentCodec UNRESERVED = PercentCodec.Builder.of(unreservedChars()).build(); /** * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */ - public static final PercentCodec PCHAR = UNRESERVED.orNew(SUB_DELIMS).or(PercentCodec.of(":@")); + public static final PercentCodec PCHAR = PercentCodec.Builder.of(UNRESERVED).or(SUB_DELIMS).addSafes(":@").build(); /** * segment = pchar
@@ -46,17 +46,17 @@ public class RFC3986 { /** * segment-nz-nc = SEGMENT ; non-zero-length segment without any colon ":" */ - public static final PercentCodec SEGMENT_NZ_NC = PercentCodec.of(SEGMENT).removeSafe(':'); + public static final PercentCodec SEGMENT_NZ_NC = PercentCodec.Builder.of(SEGMENT).removeSafe(':').build(); /** * path = segment / "/" */ - public static final PercentCodec PATH = SEGMENT.orNew(PercentCodec.of("/")); + public static final PercentCodec PATH = PercentCodec.Builder.of(SEGMENT).addSafe('/').build(); /** * query = pchar / "/" / "?" */ - public static final PercentCodec QUERY = PCHAR.orNew(PercentCodec.of("/?")); + public static final PercentCodec QUERY = PercentCodec.Builder.of(PCHAR).addSafes("/?").build(); /** * fragment = pchar / "/" / "?" @@ -67,13 +67,13 @@ public class RFC3986 { * query中的value
* value不能包含"{@code &}",可以包含 "=" */ - public static final PercentCodec QUERY_PARAM_VALUE = PercentCodec.of(QUERY).removeSafe('&'); + public static final PercentCodec QUERY_PARAM_VALUE = PercentCodec.Builder.of(QUERY).removeSafe('&').build(); /** * query中的key
* key不能包含"{@code &}" 和 "=" */ - public static final PercentCodec QUERY_PARAM_NAME = PercentCodec.of(QUERY_PARAM_VALUE).removeSafe('='); + public static final PercentCodec QUERY_PARAM_NAME = PercentCodec.Builder.of(QUERY_PARAM_VALUE).removeSafe('=').build(); /** * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java b/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java index a61b03836..4c18abec4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java @@ -143,7 +143,7 @@ public class URLDecoder implements Serializable { if (bytes == null) { return null; } - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(bytes.length); + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(bytes.length * 3); int b; for (int i = 0; i < bytes.length; i++) { b = bytes[i]; diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java b/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java index 228f02209..bc764bfa2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java @@ -83,4 +83,12 @@ public interface CharPool { * 字符常量:艾特 {@code '@'} */ char AT = '@'; + /** + * 字符常量:加号 {@code '+'} + */ + char PLUS = '+'; + /** + * 字符常量:百分号 {@code '%'} + */ + char PERCENT = '%'; } diff --git a/hutool-core/src/test/java/cn/hutool/core/codec/PercentCodecTest.java b/hutool-core/src/test/java/cn/hutool/core/codec/PercentCodecTest.java new file mode 100644 index 000000000..edfa2cefa --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/codec/PercentCodecTest.java @@ -0,0 +1,18 @@ +package cn.hutool.core.codec; + +import org.junit.Assert; +import org.junit.Test; + +public class PercentCodecTest { + + @Test + public void isSafeTest(){ + PercentCodec codec = PercentCodec.Builder.of("=").build(); + Assert.assertTrue(codec.isSafe('=')); + + codec = PercentCodec.Builder.of("=").or(PercentCodec.Builder.of("abc").build()).build(); + Assert.assertTrue(codec.isSafe('a')); + Assert.assertTrue(codec.isSafe('b')); + Assert.assertTrue(codec.isSafe('c')); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java b/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java index 57d9ee16b..2e223689f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java @@ -6,6 +6,12 @@ import org.junit.Test; public class RFC3986Test { + @Test + public void pacharTest(){ + final String encode = RFC3986.PCHAR.encode("=", CharsetUtil.UTF_8); + Assert.assertEquals("=", encode); + } + @Test public void encodeQueryTest(){ String encode = RFC3986.QUERY_PARAM_VALUE.encode("a=b", CharsetUtil.UTF_8); diff --git a/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java b/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java index 75ca99522..bea5c1a0e 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java @@ -21,4 +21,12 @@ public class URLEncoderTest { String encode2 = URLEncoder.encodeQuery(body); Assert.assertEquals("+", encode2); } + + @Test + public void encodeEmojiTest(){ + String emoji = "🐶😊😂🤣"; + String encode = URLEncoder.encodeAll(emoji); + Assert.assertEquals("%F0%9F%90%B6%F0%9F%98%8A%F0%9F%98%82%F0%9F%A4%A3", encode); + Assert.assertEquals(emoji, URLDecoder.decode(encode)); + } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java index 8164662c6..9fec11932 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java @@ -103,6 +103,7 @@ public class JSONConverter implements Converter { * @throws ConvertException 转换失败 * @since 5.7.10 */ + @SuppressWarnings("unchecked") protected static T jsonToBean(Type targetType, Object value, boolean ignoreError) throws ConvertException { if (JSONUtil.isNull(value)) { return null; @@ -111,7 +112,6 @@ public class JSONConverter implements Converter { if(value instanceof JSON){ final JSONDeserializer deserializer = GlobalSerializeMapping.getDeserializer(targetType); if(null != deserializer) { - //noinspection unchecked return (T) deserializer.deserialize((JSON) value); } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelBase.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelBase.java index 0e0481b7e..081cac9fd 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelBase.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelBase.java @@ -182,6 +182,7 @@ public class ExcelBase> implements Closeable { * @return this * @since 5.7.10 */ + @SuppressWarnings("unchecked") public T cloneSheet(int sheetIndex, String newSheetName, boolean setAsCurrentSheet) { Sheet sheet; if (this.workbook instanceof XSSFWorkbook) { @@ -194,7 +195,6 @@ public class ExcelBase> implements Closeable { if (setAsCurrentSheet) { this.sheet = sheet; } - //noinspection unchecked return (T) this; } @@ -526,9 +526,9 @@ public class ExcelBase> implements Closeable { * @param headerAlias 别名Map * @return this */ + @SuppressWarnings("unchecked") public T setHeaderAlias(Map headerAlias) { this.headerAlias = headerAlias; - //noinspection unchecked return (T) this; } @@ -539,6 +539,7 @@ public class ExcelBase> implements Closeable { * @param alias 别名 * @return this */ + @SuppressWarnings("unchecked") public T addHeaderAlias(String header, String alias) { Map headerAlias = this.headerAlias; if (null == headerAlias) { @@ -546,7 +547,6 @@ public class ExcelBase> implements Closeable { } this.headerAlias = headerAlias; this.headerAlias.put(header, alias); - //noinspection unchecked return (T) this; } @@ -556,9 +556,9 @@ public class ExcelBase> implements Closeable { * @param header 标题 * @return this */ + @SuppressWarnings("unchecked") public T removeHeaderAlias(String header) { this.headerAlias.remove(header); - //noinspection unchecked return (T) this; } @@ -567,9 +567,9 @@ public class ExcelBase> implements Closeable { * * @return this */ + @SuppressWarnings("unchecked") public T clearHeaderAlias() { this.headerAlias = null; - //noinspection unchecked return (T) this; } } diff --git a/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java b/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java index 6bbd18ee8..4f985db35 100755 --- a/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java @@ -84,10 +84,10 @@ public class YamlUtil { * @param isCloseReader 加载完毕后是否关闭{@link Reader} * @return 加载的内容,默认Map */ + @SuppressWarnings("unchecked") public static T load(Reader reader, Class type, boolean isCloseReader) { Assert.notNull(reader, "Reader must be not null !"); if (null == type) { - //noinspection unchecked type = (Class) Object.class; } diff --git a/pom.xml b/pom.xml index 04d799563..00a67925a 100755 --- a/pom.xml +++ b/pom.xml @@ -36,15 +36,15 @@ 8 - 4.13.2 + 5.8.2 1.18.24 - junit - junit + org.junit.vintage + junit-vintage-engine ${junit.version} test