diff --git a/src/main/java/xyz/zhouxy/plusone/commons/base/IWithIntCode.java b/src/main/java/xyz/zhouxy/plusone/commons/base/IWithIntCode.java index 480ab75..dcd9b03 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/base/IWithIntCode.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/base/IWithIntCode.java @@ -16,15 +16,12 @@ package xyz.zhouxy.plusone.commons.base; -import xyz.zhouxy.plusone.commons.exception.BaseException; - /** * 规定实现类带有 {@code getCode} 方法。 * 用于像自定义异常等需要带有 {@code code} 字段的类, * 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。 * * @author ZhouXY - * @see BaseException */ public interface IWithIntCode { int getCode(); diff --git a/src/main/java/xyz/zhouxy/plusone/commons/base/IWithLongCode.java b/src/main/java/xyz/zhouxy/plusone/commons/base/IWithLongCode.java new file mode 100644 index 0000000..759ef21 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/base/IWithLongCode.java @@ -0,0 +1,28 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package xyz.zhouxy.plusone.commons.base; + +/** + * 规定实现类带有 {@code getCode} 方法。 + * 用于像自定义异常等需要带有 {@code code} 字段的类, + * 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。 + * + * @author ZhouXY + */ +public interface IWithLongCode { + long getCode(); +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/collection/AbstractMapWrapper.java b/src/main/java/xyz/zhouxy/plusone/commons/collection/AbstractMapWrapper.java index ca6f2f5..2ab3e56 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/collection/AbstractMapWrapper.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/collection/AbstractMapWrapper.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; @@ -29,6 +30,8 @@ import javax.annotation.Nullable; import com.google.common.annotations.Beta; +import xyz.zhouxy.plusone.commons.util.ConcurrentHashMapUtil; + @Beta public abstract class AbstractMapWrapper> { @@ -141,12 +144,12 @@ public abstract class AbstractMapWrapper mappingFunction) { - V v = this.map.get(key); - if (null == v) { - this.map.putIfAbsent(key, mappingFunction.apply(key)); - v = this.map.get(key); + if (this.map instanceof ConcurrentHashMap) { + return ConcurrentHashMapUtil.computIfAbsent( + (ConcurrentHashMap) this.map, key, mappingFunction); + } else { + return this.map.computeIfAbsent(key, mappingFunction); } - return v; } public final Map exportMap() { diff --git a/src/main/java/xyz/zhouxy/plusone/commons/collection/SafeConcurrentHashMap.java b/src/main/java/xyz/zhouxy/plusone/commons/collection/SafeConcurrentHashMap.java index 97e01bb..100c05c 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/collection/SafeConcurrentHashMap.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/collection/SafeConcurrentHashMap.java @@ -1,14 +1,30 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package xyz.zhouxy.plusone.commons.collection; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import javax.annotation.concurrent.ThreadSafe; -import xyz.zhouxy.plusone.commons.base.JRE; +import xyz.zhouxy.plusone.commons.util.ConcurrentHashMapUtil; +// TODO 添加文档注释 @ThreadSafe public class SafeConcurrentHashMap extends ConcurrentHashMap { @@ -86,27 +102,6 @@ public class SafeConcurrentHashMap extends ConcurrentHashMap { /** {@inheritDoc} */ @Override public V computeIfAbsent(K key, Function mappingFunction) { - Objects.requireNonNull(mappingFunction); - if (JRE.isJava8()) { - V v = get(key); - if (null == v) { - // this bug fix methods maybe cause `mappingFunction.apply` multiple calls. - v = mappingFunction.apply(key); - if (null == v) { - return null; - } - final V res = putIfAbsent(key, v); - if (null != res) { - // if pre value present, means other thread put value already, - // and putIfAbsent not effect - // return exist value - return res; - } - // if pre value is null, means putIfAbsent effected, return current value - } - return v; - } else { - return computeIfAbsent(key, mappingFunction); - } + return ConcurrentHashMapUtil.computIfAbsent(this, key, mappingFunction); } } diff --git a/src/main/java/xyz/zhouxy/plusone/commons/exception/BaseException.java b/src/main/java/xyz/zhouxy/plusone/commons/exception/BaseException.java index 27bc36e..ae976d8 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/exception/BaseException.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/exception/BaseException.java @@ -45,7 +45,7 @@ public abstract class BaseException extends RuntimeException implements IWithInt } @Override - public int getCode() { + public final int getCode() { return this.code; } } diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/ConcurrentHashMapUtil.java b/src/main/java/xyz/zhouxy/plusone/commons/util/ConcurrentHashMapUtil.java new file mode 100644 index 0000000..c5ca312 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/ConcurrentHashMapUtil.java @@ -0,0 +1,50 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package xyz.zhouxy.plusone.commons.util; + +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import xyz.zhouxy.plusone.commons.base.JRE; + +public class ConcurrentHashMapUtil { // TODO 添加文档注释 + + public static V computIfAbsent(ConcurrentHashMap map, final K key, final Function mappingFunction) { + if (JRE.isJava8()) { + Objects.requireNonNull(mappingFunction); + V v = map.get(key); + if (null == v) { + v = mappingFunction.apply(key); + if (null == v) { + return null; + } + final V res = map.putIfAbsent(key, v); + if (null != res) { + return res; + } + } + return v; + } else { + return map.computeIfAbsent(key, mappingFunction); + } + } + + private ConcurrentHashMapUtil() { + throw new IllegalStateException("Utility class"); + } +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/ErrorResult.java b/src/main/java/xyz/zhouxy/plusone/commons/util/ErrorResult.java new file mode 100644 index 0000000..7ad1726 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/ErrorResult.java @@ -0,0 +1,40 @@ +package xyz.zhouxy.plusone.commons.util; + +import com.google.common.base.Strings; + +import xyz.zhouxy.plusone.commons.base.IWithCode; + +/** + * 错误结果 + * + * @author zhouxy + */ +final class ErrorResult extends UnifiedResponse { + private static final String DEFAULT_ERR_STATUS = "9999999"; + + ErrorResult(String message) { + super(DEFAULT_ERR_STATUS, message); + } + + ErrorResult(String message, Object data) { + super(DEFAULT_ERR_STATUS, message, data); + } + + ErrorResult(Object status, String message) { + super(status, message); + } + + ErrorResult(Object status, String message, Object data) { + super(status, message, data); + } + + ErrorResult(Object status, Throwable e) { + super(status, Strings.nullToEmpty(e.getMessage())); + } + + > ErrorResult(E e) { + super(e.getCode(), Strings.nullToEmpty(e.getMessage())); + } + + private static final long serialVersionUID = -1680792957826923092L; +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/OrdinaryResult.java b/src/main/java/xyz/zhouxy/plusone/commons/util/OrdinaryResult.java new file mode 100644 index 0000000..0659cc0 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/OrdinaryResult.java @@ -0,0 +1,19 @@ +package xyz.zhouxy.plusone.commons.util; + +/** + * 普通结果 + * + * @author zhouxy + */ +final class OrdinaryResult extends UnifiedResponse { + + OrdinaryResult(Object status, String message) { + super(status, message); + } + + OrdinaryResult(Object status, String message, Object data) { + super(status, message, data); + } + + private static final long serialVersionUID = -5794887914598566589L; +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java b/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java index b566a6e..e71e391 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java @@ -18,9 +18,11 @@ package xyz.zhouxy.plusone.commons.util; import java.util.Arrays; import java.util.Map; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.base.Preconditions; @@ -28,7 +30,7 @@ import com.google.common.base.Preconditions; import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap; /** - * 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用(最多缓存 256 个)。 + * 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用(最多缓存大概 256 个)。 * * @author ZhouXY * @@ -37,8 +39,8 @@ public final class RegexUtil { private static final int DEFAULT_CACHE_INITIAL_CAPACITY = 64; private static final int MAX_CACHE_SIZE = 256; - private static final Map PATTERN_CACHE = new SafeConcurrentHashMap<>( - DEFAULT_CACHE_INITIAL_CAPACITY); + private static final Map PATTERN_CACHE + = new SafeConcurrentHashMap<>(DEFAULT_CACHE_INITIAL_CAPACITY); /** * 获取 {@link Pattern} 实例。 @@ -49,15 +51,7 @@ public final class RegexUtil { */ public static Pattern getPattern(final String pattern, final boolean cachePattern) { Preconditions.checkNotNull(pattern, "The pattern can not be null."); - Pattern result = PATTERN_CACHE.get(pattern); - if (result == null) { - result = Pattern.compile(pattern); - if (cachePattern && PATTERN_CACHE.size() < MAX_CACHE_SIZE) { - PATTERN_CACHE.putIfAbsent(pattern, result); - result = PATTERN_CACHE.get(pattern); - } - } - return result; + return cachePattern ? getAndCachePatternInternal(pattern) : getPatternInternal(pattern); } /** @@ -68,11 +62,7 @@ public final class RegexUtil { */ public static Pattern getPattern(final String pattern) { Preconditions.checkNotNull(pattern, "The pattern can not be null."); - Pattern result = PATTERN_CACHE.get(pattern); - if (result == null) { - result = Pattern.compile(pattern); - } - return result; + return getPatternInternal(pattern); } /** @@ -83,10 +73,11 @@ public final class RegexUtil { * @return {@link Pattern} 实例数组 */ public static Pattern[] getPatterns(final String[] patterns, final boolean cachePattern) { - Preconditions.checkNotNull(patterns, "The patterns can not be null."); - return Arrays.stream(patterns) - .map(pattern -> getPattern(pattern, cachePattern)) - .toArray(Pattern[]::new); + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return cachePattern + ? getAndCachePatternsInternal(patterns) + : getPatternsInternal(patterns); } /** @@ -96,10 +87,9 @@ public final class RegexUtil { * @return {@link Pattern} 实例数组 */ public static Pattern[] getPatterns(final String[] patterns) { - Preconditions.checkNotNull(patterns, "The patterns can not be null."); - return Arrays.stream(patterns) - .map(RegexUtil::getPattern) - .toArray(Pattern[]::new); + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return getPatternsInternal(patterns); } /** @@ -109,12 +99,13 @@ public final class RegexUtil { * @return 缓存的 Pattern 实例。如果缓存已满,则返回 {@code null}。 */ public static Pattern cachePattern(final Pattern pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); if (PATTERN_CACHE.size() >= MAX_CACHE_SIZE) { return null; } final String patternStr = pattern.pattern(); - PATTERN_CACHE.putIfAbsent(patternStr, pattern); - return PATTERN_CACHE.get(patternStr); + final Pattern pre = PATTERN_CACHE.putIfAbsent(patternStr, pattern); + return pre != null ? pre : pattern; } /** @@ -126,7 +117,7 @@ public final class RegexUtil { */ public static boolean matches(@Nullable final CharSequence input, final Pattern pattern) { Preconditions.checkNotNull(pattern, "The pattern can not be null."); - return input != null && pattern.matcher(input).matches(); + return matchesInternal(input, pattern); } /** @@ -137,16 +128,9 @@ public final class RegexUtil { * @return 判断结果 */ public static boolean matchesOne(@Nullable final CharSequence input, final Pattern[] patterns) { - Preconditions.checkNotNull(patterns, "The patterns can not be null."); - if (input == null) { - return false; - } - for (Pattern pattern : patterns) { - if (matches(input, pattern)) { - return true; - } - } - return false; + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return matchesOneInternal(input, patterns); } /** @@ -157,16 +141,9 @@ public final class RegexUtil { * @return 判断结果 */ public static boolean matchesAll(@Nullable final CharSequence input, final Pattern[] patterns) { - Preconditions.checkNotNull(patterns, "The patterns can not be null."); - if (input == null) { - return false; - } - for (Pattern pattern : patterns) { - if (!matches(input, pattern)) { - return false; - } - } - return true; + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return matchesAllInternal(input, patterns); } /** @@ -179,7 +156,11 @@ public final class RegexUtil { */ public static boolean matches(@Nullable final CharSequence input, final String pattern, final boolean cachePattern) { - return matches(input, getPattern(pattern, cachePattern)); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + Pattern p = cachePattern + ? getAndCachePatternInternal(pattern) + : getPatternInternal(pattern); + return matchesInternal(input, p); } /** @@ -190,7 +171,8 @@ public final class RegexUtil { * @return 判断结果 */ public static boolean matches(@Nullable final CharSequence input, final String pattern) { - return matches(input, getPattern(pattern)); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return matchesInternal(input, getPatternInternal(pattern)); } /** @@ -203,8 +185,12 @@ public final class RegexUtil { */ public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns, final boolean cachePattern) { - final Pattern[] patternSet = getPatterns(patterns, cachePattern); - return matchesOne(input, patternSet); + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = cachePattern + ? getAndCachePatternsInternal(patterns) + : getPatternsInternal(patterns); + return matchesOneInternal(input, patternSet); } /** @@ -215,8 +201,10 @@ public final class RegexUtil { * @return 判断结果 */ public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns) { - final Pattern[] patternSet = getPatterns(patterns); - return matchesOne(input, patternSet); + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = getPatternsInternal(patterns); + return matchesOneInternal(input, patternSet); } /** @@ -229,8 +217,12 @@ public final class RegexUtil { */ public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns, final boolean cachePattern) { - final Pattern[] patternSet = getPatterns(patterns, cachePattern); - return matchesAll(input, patternSet); + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = cachePattern + ? getAndCachePatternsInternal(patterns) + : getPatternsInternal(patterns); + return matchesAllInternal(input, patternSet); } /** @@ -241,25 +233,27 @@ public final class RegexUtil { * @return 判断结果 */ public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns) { - final Pattern[] patternSet = getPatterns(patterns); - return matchesAll(input, patternSet); + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = getPatternsInternal(patterns); + return matchesAllInternal(input, patternSet); } /** - * 生成匹配器。 + * 生成 Matcher。 * * @param input 输入 * @param pattern 正则 * @return 结果 */ public static Matcher getMatcher(final CharSequence input, final Pattern pattern) { - Preconditions.checkNotNull(input, "The input can not be null"); - Preconditions.checkNotNull(pattern, "The pattern can not be null"); + Preconditions.checkNotNull(input, "The input can not be null."); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); return pattern.matcher(input); } /** - * 生成匹配器。 + * 生成 Matcher。 * * @param input 输入 * @param pattern 正则表达式 @@ -267,20 +261,132 @@ public final class RegexUtil { * @return 结果 */ public static Matcher getMatcher(final CharSequence input, final String pattern, boolean cachePattern) { - Preconditions.checkNotNull(input, "The input can not be null"); - return getPattern(pattern, cachePattern).matcher(input); + Preconditions.checkNotNull(input, "The input can not be null."); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + final Pattern p = cachePattern + ? getAndCachePatternInternal(pattern) + : getPatternInternal(pattern); + return p.matcher(input); } /** - * 生成匹配器。不缓存 {@link Pattern} 实例。 + * 生成 Matcher。不缓存 {@link Pattern} 实例。 * * @param input 输入 * @param pattern 正则表达式 * @return 结果 */ public static Matcher getMatcher(final CharSequence input, final String pattern) { - Preconditions.checkNotNull(input, "The input can not be null"); - return getPattern(pattern).matcher(input); + Preconditions.checkNotNull(input, "The input can not be null."); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return getPatternInternal(pattern).matcher(input); + } + + // ========== internal methods ========== + + /** + * 获取 {@link Pattern} 实例。 + * + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return {@link Pattern} 实例 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern getAndCachePatternInternal(@Nonnull final String pattern) { + if (PATTERN_CACHE.size() < MAX_CACHE_SIZE) { + return PATTERN_CACHE.computeIfAbsent(pattern, Pattern::compile); + } + Pattern result = PATTERN_CACHE.get(pattern); + if (result != null) { + return result; + } + return Pattern.compile(pattern); + } + + /** + * 获取 {@link Pattern} 实例,不缓存。 + * + * @param pattern 正则表达式 + * @return {@link Pattern} 实例 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern getPatternInternal(@Nonnull final String pattern) { + Pattern result = PATTERN_CACHE.get(pattern); + if (result == null) { + result = Pattern.compile(pattern); + } + return result; + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例。 + * + * @param patterns 正则表达式 + * @return {@link Pattern} 实例数组 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern[] getAndCachePatternsInternal(@Nonnull final String[] patterns) { + return Arrays.stream(patterns) + .map(RegexUtil::getAndCachePatternInternal) + .toArray(Pattern[]::new); + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例。 + * + * @param patterns 正则表达式 + * @return {@link Pattern} 实例数组 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern[] getPatternsInternal(@Nonnull final String[] patterns) { + return Arrays.stream(patterns) + .map(RegexUtil::getPatternInternal) + .toArray(Pattern[]::new); + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。 + * + * @param input 输入 + * @param pattern 正则 + * @return 判断结果 + */ + private static boolean matchesInternal(@Nullable final CharSequence input, @Nonnull final Pattern pattern) { + return input != null && pattern.matcher(input).matches(); + } + + @SuppressWarnings("null") + private static boolean matchesOneInternal(@Nullable final CharSequence input, @Nonnull final Pattern[] patterns) { + if (input == null) { + return false; + } + for (Pattern pattern : patterns) { + if (matchesInternal(input, pattern)) { + return true; + } + } + return false; + } + + @SuppressWarnings("null") + private static boolean matchesAllInternal(final CharSequence input, final Pattern[] patterns) { + if (input == null) { + return false; + } + for (Pattern pattern : patterns) { + if (!matchesInternal(input, pattern)) { + return false; + } + } + return true; + } + + private static boolean allNotNull(T[] array) { + return Arrays.stream(array).allMatch(Objects::nonNull); } private RegexUtil() { diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/RestfulResult.java b/src/main/java/xyz/zhouxy/plusone/commons/util/RestfulResult.java index 5a52811..d517d68 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/util/RestfulResult.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/RestfulResult.java @@ -28,7 +28,9 @@ import com.google.common.base.Preconditions; * 对返回给前端的数据进行封装 * * @author ZhouXY + * @deprecated 已被 {@link UnifiedResponse} 代替。 */ +@Deprecated @JsonInclude(JsonInclude.Include.NON_NULL) public class RestfulResult { diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/SuccessResult.java b/src/main/java/xyz/zhouxy/plusone/commons/util/SuccessResult.java new file mode 100644 index 0000000..660f82b --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/SuccessResult.java @@ -0,0 +1,25 @@ +package xyz.zhouxy.plusone.commons.util; + +/** + * 成功结果 + * + * @author zhouxy + */ +final class SuccessResult extends UnifiedResponse { + private static final String SUCCESS_STATUS = "000000"; + private static final String DEFAULT_SUCCESS_MSG = "SUCCESS"; + + SuccessResult() { + super(SUCCESS_STATUS, DEFAULT_SUCCESS_MSG); + } + + SuccessResult(String message) { + super(SUCCESS_STATUS, message); + } + + SuccessResult(String message, Object data) { + super(SUCCESS_STATUS, message, data); + } + + private static final long serialVersionUID = -7509096647748429661L; +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/UnifiedResponse.java b/src/main/java/xyz/zhouxy/plusone/commons/util/UnifiedResponse.java new file mode 100644 index 0000000..8512079 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/UnifiedResponse.java @@ -0,0 +1,246 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package xyz.zhouxy.plusone.commons.util; + +import xyz.zhouxy.plusone.commons.base.IWithCode; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.BooleanSupplier; +import java.util.function.Function; +import java.util.function.Supplier; + +import com.google.common.base.Preconditions; + +/** + * 统一结果,对返回给前端的数据进行封装。 + * + * @author ZhouXY + */ +public abstract class UnifiedResponse extends HashMap { + private static final long serialVersionUID = -6198220274571286031L; + + private static final String STATUS_KEY = "status"; + private static final String MESSAGE_KEY = "message"; + private static final String DATA_KEY = "data"; + + public static UnifiedResponse success() { + return new SuccessResult(); + } + + public static UnifiedResponse success(String message) { + return new SuccessResult(message); + } + + public static UnifiedResponse success(String message, Object data) { + return new SuccessResult(message, data); + } + + public static UnifiedResponse error(String message) { + return new ErrorResult(message); + } + + public static UnifiedResponse error(String message, Object data) { + return new ErrorResult(message, data); + } + + public static UnifiedResponse error(Object status, String message) { + return new ErrorResult(status, message); + } + + public static UnifiedResponse error(Object status, String message, Object data) { + return new ErrorResult(status, message, data); + } + + public static UnifiedResponse error(Object status, Throwable e) { + return new ErrorResult(status, e); + } + + public static > UnifiedResponse error(E e) { + return new ErrorResult(e); + } + + public static UnifiedResponse of(Object status, String message) { + return new OrdinaryResult(status, message); + } + + public static UnifiedResponse of(Object status, String message, Object data) { + return new OrdinaryResult(status, message, data); + } + + public static UnifiedResponse of(final boolean isSuccess, + final Supplier success, final Supplier error) { + Preconditions.checkNotNull(success, "Success supplier must not be null."); + Preconditions.checkNotNull(error, "Error supplier must not be null."); + return isSuccess ? success.get() : error.get(); + } + + public static UnifiedResponse of(final BooleanSupplier isSuccess, + final Supplier success, final Supplier error) { + Preconditions.checkNotNull(isSuccess, "Conditions for success must not be null."); + Preconditions.checkNotNull(success, "Success supplier must not be null."); + Preconditions.checkNotNull(error, "Error supplier must not be null."); + return isSuccess.getAsBoolean() ? success.get() : error.get(); + } + + protected UnifiedResponse(Object status, String message) { + setStatus(status); + setMessage(message); + } + + protected UnifiedResponse(Object status, String message, Object data) { + setStatus(status); + setMessage(message); + setData(data); + } + + private void setStatus(Object status) { + Objects.requireNonNull(status); + if (status instanceof String) { + super.put(STATUS_KEY, status); + } else { + super.put(STATUS_KEY, status.toString()); + } + } + + private void setData(Object data) { + super.put(DATA_KEY, Objects.requireNonNull(data)); + } + + private void setMessage(String message) { + super.put(MESSAGE_KEY, Objects.requireNonNull(message)); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object put(String key, Object value) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object remove(Object key) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object putIfAbsent(String key, Object value) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public boolean replace(String key, Object oldValue, Object newValue) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object replace(String key, Object value) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object computeIfAbsent(String key, Function mappingFunction) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object computeIfPresent(String key, BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object compute(String key, BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public Object merge(String key, Object value, BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Unsupported operation. + */ + @Deprecated + @Override + public void replaceAll(BiFunction function) { + throw new UnsupportedOperationException(); + } +}