From fecf69357887802d427db870ff78c10673d8fd60 Mon Sep 17 00:00:00 2001 From: Timi Date: Mon, 27 Apr 2026 23:49:37 +0800 Subject: [PATCH] v0.0.3 --- .gitea/workflows/ci.yml | 210 +++++++++--------- pom.xml | 41 +++- src/main/java/com/imyeyu/java/TimiJava.java | 67 +++++- .../java/com/imyeyu/java/bean/BasePage.java | 35 +-- .../com/imyeyu/java/bean/BasePageResult.java | 27 +-- .../java/com/imyeyu/java/bean/Callback.java | 5 + .../com/imyeyu/java/bean/CallbackArg.java | 2 + .../imyeyu/java/bean/CallbackArgReturn.java | 3 + .../com/imyeyu/java/bean/CallbackReturn.java | 1 + .../java/com/imyeyu/java/bean/Language.java | 68 +----- .../com/imyeyu/java/bean/LanguageMapping.java | 34 +++ .../imyeyu/java/bean/LanguageMsgMapping.java | 53 +++++ .../com/imyeyu/java/bean/timi/TimiCode.java | 19 +- .../com/imyeyu/java/bean/timi/TimiError.java | 11 +- .../imyeyu/java/bean/timi/TimiException.java | 11 +- .../imyeyu/java/bean/timi/TimiResponse.java | 50 +---- .../com/imyeyu/java/obs/ChangeListener.java | 21 +- .../java/obs/CollectionChangeListener.java | 26 ++- .../imyeyu/java/obs/MapChangeListener.java | 30 ++- .../java/com/imyeyu/java/obs/Observable.java | 23 ++ .../imyeyu/java/obs/ObservableBoolean.java | 14 +- .../com/imyeyu/java/obs/ObservableDouble.java | 14 +- .../com/imyeyu/java/obs/ObservableFloat.java | 14 +- .../imyeyu/java/obs/ObservableInteger.java | 13 +- .../com/imyeyu/java/obs/ObservableList.java | 80 ++++++- .../com/imyeyu/java/obs/ObservableLong.java | 14 +- .../com/imyeyu/java/obs/ObservableMap.java | 42 +++- .../com/imyeyu/java/obs/ObservableObject.java | 20 +- .../com/imyeyu/java/obs/ObservableSet.java | 46 +++- .../com/imyeyu/java/obs/ObservableString.java | 29 ++- src/main/java/com/imyeyu/java/ref/Ref.java | 86 +++---- .../java/com/imyeyu/java/ref/RefField.java | 53 ++--- .../java/thread/AsyncRetryExecutor.java | 126 ++++++----- .../imyeyu/java/AsyncRetryExecutorTest.java} | 19 +- .../imyeyu/java/ObservableTest.java} | 21 +- src/test/java/com/imyeyu/java/RefTest.java | 109 +++++++++ .../java/com/imyeyu/java/TimiJavaTest.java | 87 ++++++++ src/test/java/test/TestRef.java | 96 -------- 38 files changed, 1058 insertions(+), 562 deletions(-) rename src/test/java/{test/TestThread.java => com/imyeyu/java/AsyncRetryExecutorTest.java} (65%) rename src/test/java/{test/TestObs.java => com/imyeyu/java/ObservableTest.java} (69%) create mode 100644 src/test/java/com/imyeyu/java/RefTest.java create mode 100644 src/test/java/com/imyeyu/java/TimiJavaTest.java delete mode 100644 src/test/java/test/TestRef.java diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index c964697..18424e7 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,111 +1,111 @@ name: CI/CD on: - pull_request: - branches: - - master - types: - - closed + pull_request: + branches: + - master + types: + - closed jobs: - build-deploy: - runs-on: act_runner_java - if: ${{ github.event.pull_request.merged == true }} - env: - JAVA_HOME: /usr/lib/jvm/java-21-openjdk - steps: - - name: Checkout code - run: | - git clone ${{ github.server_url }}/${{ github.repository }}.git . - git checkout ${{ github.sha }} - - name: Set up environment - run: | - echo "PR #${{ github.event.number }} merged into master" - echo "Source branch: ${{ github.event.pull_request.head.ref }}" - echo "Target branch: ${{ github.event.pull_request.base.ref }}" - - name: Run tests - run: | - echo "Running test suite..." - - name: Build project - run: | - mvn -B -DskipTests clean package source:jar javadoc:jar - - name: Deploy to Nexus - if: success() - run: | - if [ -z "${{ secrets.NEXUS_USERNAME }}" ] || [ -z "${{ secrets.NEXUS_PASSWORD }}" ]; then - echo "Missing secrets.NEXUS_USERNAME or secrets.NEXUS_PASSWORD" - exit 1 - fi - mkdir -p ~/.m2 - cat > ~/.m2/settings.xml < - - - timi-nexus - ${{ secrets.NEXUS_USERNAME }} - ${{ secrets.NEXUS_PASSWORD }} - - - - EOF - version=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version) - artifact_id=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.artifactId) - main_jar="target/${artifact_id}-${version}.jar" - sources_jar="target/${artifact_id}-${version}-sources.jar" - javadoc_jar="target/${artifact_id}-${version}-javadoc.jar" - if [ ! -f "$main_jar" ] || [ ! -f "$sources_jar" ] || [ ! -f "$javadoc_jar" ]; then - echo "Missing build artifacts in target" - exit 1 - fi - mvn -B deploy:deploy-file \ - -Dfile="$main_jar" \ - -Dsources="$sources_jar" \ - -Djavadoc="$javadoc_jar" \ - -DpomFile="./pom.xml" \ - -Durl="https://nexus.imyeyu.com/repository/maven-releases/" \ - -DrepositoryId="timi-nexus" \ - -Dhttps.protocols=TLSv1.2 \ - -Djdk.tls.client.protocols=TLSv1.2 - - name: Create release - if: ${{ success() && startsWith(github.event.pull_request.title, 'v') }} + build-deploy: + runs-on: act_runner_java + if: ${{ github.event.pull_request.merged == true }} env: - GITEA_TOKEN: ${{ secrets.RUNNER_TOKEN }} - GITEA_SERVER_URL: ${{ github.server_url }} - GITEA_REPOSITORY: ${{ github.repository }} - RELEASE_TAG: ${{ github.event.pull_request.title }} - RELEASE_TARGET: ${{ github.sha }} - run: | - if [ -z "$GITEA_TOKEN" ]; then - echo "Missing secrets.RUNNER_TOKEN" - exit 1 - fi - api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases" - payload=$(cat < ~/.m2/settings.xml < + + + timi-nexus + ${{ secrets.NEXUS_USERNAME }} + ${{ secrets.NEXUS_PASSWORD }} + + + + EOF + version=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version) + artifact_id=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.artifactId) + main_jar="target/${artifact_id}-${version}.jar" + sources_jar="target/${artifact_id}-${version}-sources.jar" + javadoc_jar="target/${artifact_id}-${version}-javadoc.jar" + if [ ! -f "$main_jar" ] || [ ! -f "$sources_jar" ] || [ ! -f "$javadoc_jar" ]; then + echo "Missing build artifacts in target" + exit 1 + fi + mvn -B deploy:deploy-file \ + -Dfile="$main_jar" \ + -Dsources="$sources_jar" \ + -Djavadoc="$javadoc_jar" \ + -DpomFile="./pom.xml" \ + -Durl="https://nexus.imyeyu.com/repository/maven-releases/" \ + -DrepositoryId="timi-nexus" \ + -Dhttps.protocols=TLSv1.2 \ + -Djdk.tls.client.protocols=TLSv1.2 + - name: Create release + if: ${{ success() && startsWith(github.event.pull_request.title, 'v') }} + env: + GITEA_TOKEN: ${{ secrets.RUNNER_TOKEN }} + GITEA_SERVER_URL: ${{ github.server_url }} + GITEA_REPOSITORY: ${{ github.repository }} + RELEASE_TAG: ${{ github.event.pull_request.title }} + RELEASE_TARGET: ${{ github.sha }} + run: | + if [ -z "$GITEA_TOKEN" ]; then + echo "Missing secrets.RUNNER_TOKEN" + exit 1 + fi + api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases" + payload=$(cat <com.imyeyu.java timi-java - 0.0.2 + 0.0.3 jar + true 21 21 UTF-8 - true @@ -28,10 +28,42 @@ maven-source-plugin 3.3.1 + + org.projectlombok + lombok-maven-plugin + 1.18.20.0 + + ${project.basedir}/src/main/java + ${project.build.directory}/delombok + false + UTF-8 + + + + generate-sources + + delombok + + + + + + org.projectlombok + lombok + 1.18.36 + + + org.apache.maven.plugins maven-javadoc-plugin 3.11.2 + + ${project.build.directory}/delombok + UTF-8 + UTF-8 + UTF-8 + @@ -57,6 +89,11 @@ + + org.projectlombok + lombok + 1.18.40 + org.junit.jupiter junit-jupiter diff --git a/src/main/java/com/imyeyu/java/TimiJava.java b/src/main/java/com/imyeyu/java/TimiJava.java index 1f8fafc..cfae7d5 100644 --- a/src/main/java/com/imyeyu/java/TimiJava.java +++ b/src/main/java/com/imyeyu/java/TimiJava.java @@ -5,14 +5,17 @@ import java.io.StringWriter; import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Objects; /** + * 通用工具 * * @author 夜雨 * @since 2021-02-13 11:39 */ public interface TimiJava { + /** 全 0 UUID */ String ZERO_UUID = "00000000-0000-0000-0000-000000000000"; /** @@ -69,41 +72,87 @@ public interface TimiJava { return !isEmpty(object); } + /** + * 为空时取默认值 + * + * @param obj 判空对象 + * @param defaultObj 默认对象 + * @return 最终值 + * @param 对象类型 + */ static T defaultIfNull(T obj, T defaultObj) { - return firstNotNull(obj, defaultObj); + return Objects.requireNonNullElse(obj, defaultObj); } + /** + * 为空时取默认值 + * + * @param obj 判空对象 + * @param defaultObj 默认对象 + * @return 最终值 + * @param 对象类型 + */ static T defaultIfEmpty(T obj, T defaultObj) { - return firstNotEmpty(obj, defaultObj); + if (isEmpty(obj)) { + return defaultObj; + } + return obj; } + /** + * 取第一个非空对象 + * + * @param objects 对象列表 + * @return 最终值 + * @param 对象类型 + */ @SafeVarargs static T firstNotNull(T... objects) { - for (int i = 0; i < objects.length; i++) { - if (objects[i] != null) { - return objects[i]; + for (T object : objects) { + if (object != null) { + return object; } } return null; } + /** + * 取第一个非空对象 + * + * @param objects 对象列表 + * @return 最终值 + * @param 对象类型 + */ @SafeVarargs static T firstNotEmpty(T... objects) { - for (int i = 0; i < objects.length; i++) { - if (TimiJava.isNotEmpty(objects[i])) { - return objects[i]; + for (T object : objects) { + if (TimiJava.isNotEmpty(object)) { + return object; } } return null; } - static String toString(Exception e) { + /** + * 打印异常 + * + * @param e 异常 + * @return 异常文本 + */ + static String serializeThrowable(Throwable e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); return sw.toString(); } + /** + * 空安全迭代器,使 for 迭代可以入参为空 + * + * @param iterable 可迭代对象 + * @return 安全迭代对象 + * @param 迭代对象类型 + */ static Iterable safeIterable(Iterable iterable) { return defaultIfNull(iterable, Collections::emptyIterator); } diff --git a/src/main/java/com/imyeyu/java/bean/BasePage.java b/src/main/java/com/imyeyu/java/bean/BasePage.java index 668e6f0..778c081 100644 --- a/src/main/java/com/imyeyu/java/bean/BasePage.java +++ b/src/main/java/com/imyeyu/java/bean/BasePage.java @@ -1,9 +1,18 @@ package com.imyeyu.java.bean; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + /** + * 分页 + * * @author 夜雨 * @since 2025-07-25 11:04 */ +@Data +@NoArgsConstructor +@AllArgsConstructor public class BasePage { /** 下标 */ @@ -12,35 +21,13 @@ public class BasePage { /** 数据量 */ protected long size = 16; - public BasePage() { - } - - public BasePage(int index, long size) { - this.index = index; - this.size = size; - } - + /** 上一页 */ public void prev() { index--; } + /** 下一页 */ public void next() { index++; } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } } diff --git a/src/main/java/com/imyeyu/java/bean/BasePageResult.java b/src/main/java/com/imyeyu/java/bean/BasePageResult.java index f01ef8c..3a40a0a 100644 --- a/src/main/java/com/imyeyu/java/bean/BasePageResult.java +++ b/src/main/java/com/imyeyu/java/bean/BasePageResult.java @@ -1,13 +1,17 @@ package com.imyeyu.java.bean; import com.imyeyu.java.TimiJava; +import lombok.Data; import java.util.List; /** + * 分页结果 + * * @author 夜雨 * @since 2025-07-25 11:04 */ +@Data public class BasePageResult { /** 总数据量 */ @@ -16,6 +20,7 @@ public class BasePageResult { /** 总页数 */ protected int pages; + /** 分页数据列表 */ protected List list; /** @@ -36,15 +41,6 @@ public class BasePageResult { return !isEmpty(); } - /** - * 获取总数据量 - * - * @return 总数据量 - */ - public long getTotal() { - return total; - } - /** * 设置总数据量 * @@ -57,18 +53,15 @@ public class BasePageResult { } } - public List getList() { - return list; - } - + /** + * 设置分页数据列表 + * + * @param list 分页数据列表 + */ public void setList(List list) { this.list = list; if (TimiJava.isNotEmpty(list)) { pages = (int) Math.ceil(1D * total / list.size()); } } - - public int getPages() { - return pages; - } } diff --git a/src/main/java/com/imyeyu/java/bean/Callback.java b/src/main/java/com/imyeyu/java/bean/Callback.java index 83f041e..bdf9ab3 100644 --- a/src/main/java/com/imyeyu/java/bean/Callback.java +++ b/src/main/java/com/imyeyu/java/bean/Callback.java @@ -11,6 +11,11 @@ public interface Callback { /** 执行程序 */ void handler() throws RuntimeException; + /** + * 非空时执行回调 + * + * @param callback 回调 + */ static void handle(Callback callback) { if (callback == null) { return; diff --git a/src/main/java/com/imyeyu/java/bean/CallbackArg.java b/src/main/java/com/imyeyu/java/bean/CallbackArg.java index 7fcf092..d8492b2 100644 --- a/src/main/java/com/imyeyu/java/bean/CallbackArg.java +++ b/src/main/java/com/imyeyu/java/bean/CallbackArg.java @@ -21,7 +21,9 @@ public interface CallbackArg { /** * 非空时执行回调 * + * @param t 参数 * @param callbackArg 回调 + * @param 入参类型 */ static void handle(T t, CallbackArg callbackArg) { if (callbackArg == null) { diff --git a/src/main/java/com/imyeyu/java/bean/CallbackArgReturn.java b/src/main/java/com/imyeyu/java/bean/CallbackArgReturn.java index 3881b9b..c2ab79c 100644 --- a/src/main/java/com/imyeyu/java/bean/CallbackArgReturn.java +++ b/src/main/java/com/imyeyu/java/bean/CallbackArgReturn.java @@ -23,7 +23,10 @@ public interface CallbackArgReturn { /** * 非空时执行回调 * + * @param t 参数 * @param callbackArgReturn 回调 + * @param 入参类型 + * @param 返回类型 */ static R handle(T t, CallbackArgReturn callbackArgReturn) { if (callbackArgReturn == null) { diff --git a/src/main/java/com/imyeyu/java/bean/CallbackReturn.java b/src/main/java/com/imyeyu/java/bean/CallbackReturn.java index d36a566..2b7ec17 100644 --- a/src/main/java/com/imyeyu/java/bean/CallbackReturn.java +++ b/src/main/java/com/imyeyu/java/bean/CallbackReturn.java @@ -22,6 +22,7 @@ public interface CallbackReturn { * 非空时执行回调 * * @param callbackReturn 回调 + * @param 返回类型 */ static R handle(CallbackReturn callbackReturn) { if (callbackReturn == null) { diff --git a/src/main/java/com/imyeyu/java/bean/Language.java b/src/main/java/com/imyeyu/java/bean/Language.java index c10f3a1..1102ee6 100644 --- a/src/main/java/com/imyeyu/java/bean/Language.java +++ b/src/main/java/com/imyeyu/java/bean/Language.java @@ -1,6 +1,7 @@ package com.imyeyu.java.bean; import com.imyeyu.java.ref.Ref; +import lombok.Data; /** * 多语言 @@ -8,9 +9,12 @@ import com.imyeyu.java.ref.Ref; * @author 夜雨 * @since 2022-02-23 11:25 */ +@Data public class Language { /** + * 支持语言枚举 + * * @author 夜雨 * @since 2025-12-05 14:31 */ @@ -67,68 +71,4 @@ public class Language { throw new RuntimeException(e); } } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getZhCN() { - return zhCN; - } - - public void setZhCN(String zhCN) { - this.zhCN = zhCN; - } - - public String getZhTW() { - return zhTW; - } - - public void setZhTW(String zhTW) { - this.zhTW = zhTW; - } - - public String getEnUS() { - return enUS; - } - - public void setEnUS(String enUS) { - this.enUS = enUS; - } - - public String getRuRU() { - return ruRU; - } - - public void setRuRU(String ruRU) { - this.ruRU = ruRU; - } - - public String getKoKR() { - return koKR; - } - - public void setKoKR(String koKR) { - this.koKR = koKR; - } - - public String getJaJP() { - return jaJP; - } - - public void setJaJP(String jaJP) { - this.jaJP = jaJP; - } - - public String getDeDE() { - return deDE; - } - - public void setDeDE(String deDE) { - this.deDE = deDE; - } } diff --git a/src/main/java/com/imyeyu/java/bean/LanguageMapping.java b/src/main/java/com/imyeyu/java/bean/LanguageMapping.java index 85d4a8e..f2d5fa5 100644 --- a/src/main/java/com/imyeyu/java/bean/LanguageMapping.java +++ b/src/main/java/com/imyeyu/java/bean/LanguageMapping.java @@ -3,18 +3,52 @@ package com.imyeyu.java.bean; import java.util.Map; /** + * 多语言映射接口 + * * @author 夜雨 * @since 2024-04-03 11:27 */ public interface LanguageMapping { + /** + * 添加映射 + * + * @param key 键 + * @param value 值 + */ void add(String key, String value); + /** + * 是否存在映射 + * + * @param key 键 + * @return true 为存在 + */ boolean has(String key); + /** + * 获取映射值 + * + * @param key 键 + * @return 值 + */ String text(String key); + /** + * 获取映射值,不存在时使用默认值 + * + * @param key 键 + * @param def 默认值 + * @return 值 + */ String text(String key, String def); + /** + * 获取映射值并插入参数 + * + * @param key 键 + * @param argsMap 参数列表 + * @return 值 + */ String textArgs(String key, Map argsMap); } diff --git a/src/main/java/com/imyeyu/java/bean/LanguageMsgMapping.java b/src/main/java/com/imyeyu/java/bean/LanguageMsgMapping.java index 635d956..6340fe5 100644 --- a/src/main/java/com/imyeyu/java/bean/LanguageMsgMapping.java +++ b/src/main/java/com/imyeyu/java/bean/LanguageMsgMapping.java @@ -3,26 +3,79 @@ package com.imyeyu.java.bean; import java.util.Map; /** + * 多语言消息接口 + * * @author 夜雨 * @since 2024-04-01 10:28 */ public interface LanguageMsgMapping { + /** + * 设置消息 + * + * @param msg 消息 + * @return 原对象 + */ T msg(String msg); + /** + * 设置消息多语言键 + * + * @param msgKey 键 + * @return 原对象 + */ T msgKey(String msgKey); + /** + * 设置消息多语言键并附加插值参数 + * + * @param msgKey 键 + * @param msgArgs 插值参数 + * @return 原对象 + */ T msgKey(String msgKey, Map msgArgs); + /** + * 设置消息 + * + * @param msg 消息 + */ void setMsg(String msg); + /** + * 获取消息 + * + * @return 消息 + */ String getMsg(); + /** + * 设置消息多语言键 + * + * @param msgKey 键 + */ void setMsgKey(String msgKey); + + /** + * 设置消息多语言键并附加插值参数列表 + * + * @param msgKey 键 + * @param msgArgs 插值参数 + */ void setMsgKey(String msgKey, Map msgArgs); + /** + * 获取消息多语言键 + * + * @return 键 + */ String getMsgKey(); + /** + * 获取附加插值参数 + * + * @return 附加插值参数列表 + */ Map getMsgArgs(); } diff --git a/src/main/java/com/imyeyu/java/bean/timi/TimiCode.java b/src/main/java/com/imyeyu/java/bean/timi/TimiCode.java index d2fed91..0ffbc58 100644 --- a/src/main/java/com/imyeyu/java/bean/timi/TimiCode.java +++ b/src/main/java/com/imyeyu/java/bean/timi/TimiCode.java @@ -1,11 +1,14 @@ package com.imyeyu.java.bean.timi; +import lombok.Getter; + /** * 通用代码(基于 HTTP 代码扩展) * * @author 夜雨 * @since 2021-05-21 14:32 */ +@Getter public enum TimiCode { // ---------- 200 正常 ---------- @@ -74,6 +77,7 @@ public enum TimiCode { /** 服务繁忙 */ ERROR_SERVICE_BUSY(50300); + /** 代码 */ final Integer value; TimiCode(Integer value) { @@ -108,15 +112,6 @@ public enum TimiCode { return new TimiResponse<>(this).msg(toString()); } - /** - * 获取代码 - * - * @return 代码 - */ - public Integer getValue() { - return value; - } - /** * 根据代码返回对象 * @@ -125,9 +120,9 @@ public enum TimiCode { */ public static TimiCode fromCode(int code) { TimiCode[] codes = values(); - for (int i = 0; i < codes.length; i++) { - if (codes[i].getValue() == code) { - return codes[i]; + for (TimiCode timiCode : codes) { + if (timiCode.getValue() == code) { + return timiCode; } } return null; diff --git a/src/main/java/com/imyeyu/java/bean/timi/TimiError.java b/src/main/java/com/imyeyu/java/bean/timi/TimiError.java index 3e9a8d7..b1949f8 100644 --- a/src/main/java/com/imyeyu/java/bean/timi/TimiError.java +++ b/src/main/java/com/imyeyu/java/bean/timi/TimiError.java @@ -1,6 +1,7 @@ package com.imyeyu.java.bean.timi; import com.imyeyu.java.bean.LanguageMsgMapping; +import lombok.Getter; import java.util.Map; @@ -13,6 +14,7 @@ import java.util.Map; public class TimiError extends AssertionError implements LanguageMsgMapping { /** 代码 */ + @Getter protected final TimiCode code; protected transient String msgKey; @@ -35,15 +37,6 @@ public class TimiError extends AssertionError implements LanguageMsgMapping toResponse() { return new TimiResponse<>(code).msg(getMessage()).msgKey(msgKey, msgArgs); } diff --git a/src/main/java/com/imyeyu/java/bean/timi/TimiException.java b/src/main/java/com/imyeyu/java/bean/timi/TimiException.java index 1800915..e173fc1 100644 --- a/src/main/java/com/imyeyu/java/bean/timi/TimiException.java +++ b/src/main/java/com/imyeyu/java/bean/timi/TimiException.java @@ -3,6 +3,7 @@ package com.imyeyu.java.bean.timi; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.CallbackReturn; import com.imyeyu.java.bean.LanguageMsgMapping; +import lombok.Getter; import java.util.Map; @@ -15,6 +16,7 @@ import java.util.Map; public class TimiException extends RuntimeException implements LanguageMsgMapping { /** 代码 */ + @Getter protected final TimiCode code; protected transient String msgKey; @@ -48,15 +50,6 @@ public class TimiException extends RuntimeException implements LanguageMsgMappin this.code = code; } - /** - * 获取代码 - * - * @return 代码 - */ - public TimiCode getCode() { - return code; - } - public TimiResponse toResponse() { return new TimiResponse<>(code).msg(getMessage()).msgKey(msgKey, msgArgs); } diff --git a/src/main/java/com/imyeyu/java/bean/timi/TimiResponse.java b/src/main/java/com/imyeyu/java/bean/timi/TimiResponse.java index d124247..892182a 100644 --- a/src/main/java/com/imyeyu/java/bean/timi/TimiResponse.java +++ b/src/main/java/com/imyeyu/java/bean/timi/TimiResponse.java @@ -1,6 +1,9 @@ package com.imyeyu.java.bean.timi; import com.imyeyu.java.bean.LanguageMsgMapping; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import java.io.Serializable; import java.util.Map; @@ -11,9 +14,12 @@ import java.util.Map; * @author 夜雨 * @since 2021-07-01 20:18 */ +@NoArgsConstructor public class TimiResponse implements Serializable, LanguageMsgMapping> { - /** 代码 */ + /** 响应代码 */ + @Setter + @Getter protected Integer code; /** 消息 */ @@ -24,12 +30,10 @@ public class TimiResponse implements Serializable, LanguageMsgMapping msgArgs; /** 数据体 */ + @Setter + @Getter protected T data; - /** 默认构造器 */ - public TimiResponse() { - } - /** * 构造器 * @@ -85,42 +89,6 @@ public class TimiResponse implements Serializable, LanguageMsgMapping 监听值类型 * @author 夜雨 * @since 2024-09-01 15:15 */ public interface ChangeListener { + /** + * 处理值变更事件 + * + * @param from 变更前值 + * @param to 变更后值 + */ void handler(T from, T to); + /** + * 通知全部监听器处理本次变更 + * + * @param listenerList 监听器列表 + * @param from 变更前值 + * @param to 变更后值 + * @param 监听值类型 + */ static void notifyListener(List> listenerList, T from, T to) { - for (int i = 0; i < listenerList.size(); i++) { - listenerList.get(i).handler(from, to); + for (ChangeListener listener : listenerList) { + listener.handler(from, to); } } } diff --git a/src/main/java/com/imyeyu/java/obs/CollectionChangeListener.java b/src/main/java/com/imyeyu/java/obs/CollectionChangeListener.java index c075b35..124a849 100644 --- a/src/main/java/com/imyeyu/java/obs/CollectionChangeListener.java +++ b/src/main/java/com/imyeyu/java/obs/CollectionChangeListener.java @@ -3,27 +3,49 @@ package com.imyeyu.java.obs; import java.util.List; /** + * 集合元素变更监听器 + * + * @param 元素类型 * @author 夜雨 * @since 2024-09-01 15:59 */ public interface CollectionChangeListener { /** + * 集合变更类型 + * * @author 夜雨 * @since 2024-09-01 19:47 */ enum ChangeType { + /** 新增元素 */ ADD, + /** 删除元素 */ REMOVE } + /** + * 处理集合元素变更 + * + * @param type 变更类型 + * @param e 本次变更元素 + * @throws RuntimeException 监听器处理失败时抛出 + */ void handler(ChangeType type, E e) throws RuntimeException; + /** + * 通知全部集合监听器处理本次变更 + * + * @param listenerList 监听器列表 + * @param type 变更类型 + * @param element 本次变更元素 + * @param 元素类型 + */ static void notifyListener(List> listenerList, ChangeType type, E element) { - for (int i = 0; i < listenerList.size(); i++) { - listenerList.get(i).handler(type, element); + for (CollectionChangeListener listener : listenerList) { + listener.handler(type, element); } } } diff --git a/src/main/java/com/imyeyu/java/obs/MapChangeListener.java b/src/main/java/com/imyeyu/java/obs/MapChangeListener.java index b343b96..d9eaf48 100644 --- a/src/main/java/com/imyeyu/java/obs/MapChangeListener.java +++ b/src/main/java/com/imyeyu/java/obs/MapChangeListener.java @@ -3,32 +3,56 @@ package com.imyeyu.java.obs; import java.util.List; /** + * 映射变更监听器 + * + * @param 键类型 + * @param 值类型 * @author 夜雨 * @since 2024-09-01 18:01 */ public interface MapChangeListener { /** - * + * 映射变更类型 * * @author 夜雨 * @since 2024-09-01 23:51 */ enum ChangeType { + /** 新增键值对 */ ADD, + /** 更新既有键值对 */ UPDATE, + /** 删除键值对 */ REMOVE } + /** + * 处理映射变更 + * + * @param type 变更类型 + * @param key 变更键 + * @param value 变更值 + */ void handler(ChangeType type, K key, V value); + /** + * 通知全部映射监听器处理本次变更 + * + * @param listenerList 监听器列表 + * @param type 变更类型 + * @param key 变更键 + * @param value 变更值 + * @param 键类型 + * @param 值类型 + */ @SuppressWarnings("unchecked") static void notifyListener(List> listenerList, ChangeType type, Object key, V value) { - for (int i = 0; i < listenerList.size(); i++) { - listenerList.get(i).handler(type, (K) key, value); + for (MapChangeListener kvMapChangeListener : listenerList) { + kvMapChangeListener.handler(type, (K) key, value); } } } diff --git a/src/main/java/com/imyeyu/java/obs/Observable.java b/src/main/java/com/imyeyu/java/obs/Observable.java index 07fa696..f096d8f 100644 --- a/src/main/java/com/imyeyu/java/obs/Observable.java +++ b/src/main/java/com/imyeyu/java/obs/Observable.java @@ -1,16 +1,39 @@ package com.imyeyu.java.obs; /** + * 可观察对象接口 + * + * @param 可观察值类型 * @author 夜雨 * @since 2024-09-01 15:07 */ public interface Observable { + /** + * 获取当前值 + * + * @return 当前值 + */ T get(); + /** + * 设置当前值 + * + * @param value 新值 + */ void set(T value); + /** + * 添加值变更监听器 + * + * @param changeListener 值变更监听器 + */ void addListener(ChangeListener changeListener); + /** + * 移除值变更监听器 + * + * @param changeListener 值变更监听器 + */ void removeListener(ChangeListener changeListener); } diff --git a/src/main/java/com/imyeyu/java/obs/ObservableBoolean.java b/src/main/java/com/imyeyu/java/obs/ObservableBoolean.java index b65a8e2..6a867ec 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableBoolean.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableBoolean.java @@ -1,15 +1,21 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + /** + * 可观察布尔值 + * * @author 夜雨 * @since 2024-09-01 18:43 */ +@NoArgsConstructor public class ObservableBoolean extends ObservableObject { - public ObservableBoolean() { - super(); - } - + /** + * 使用指定初始值创建可观察布尔值 + * + * @param value 初始值 + */ public ObservableBoolean(Boolean value) { super(value); } diff --git a/src/main/java/com/imyeyu/java/obs/ObservableDouble.java b/src/main/java/com/imyeyu/java/obs/ObservableDouble.java index 316741b..b7970f0 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableDouble.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableDouble.java @@ -1,15 +1,21 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + /** + * 可观察双精度值 + * * @author 夜雨 * @since 2024-09-01 18:43 */ +@NoArgsConstructor public class ObservableDouble extends ObservableObject { - public ObservableDouble() { - super(); - } - + /** + * 使用指定数值创建可观察双精度值 + * + * @param value 初始值 + */ public ObservableDouble(Number value) { super(value.doubleValue()); } diff --git a/src/main/java/com/imyeyu/java/obs/ObservableFloat.java b/src/main/java/com/imyeyu/java/obs/ObservableFloat.java index 1a3c2ab..6f42152 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableFloat.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableFloat.java @@ -1,15 +1,21 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + /** + * 可观察浮点值 + * * @author 夜雨 * @since 2024-09-01 18:43 */ +@NoArgsConstructor public class ObservableFloat extends ObservableObject { - public ObservableFloat() { - super(); - } - + /** + * 使用指定初始值创建可观察浮点值 + * + * @param value 初始值 + */ public ObservableFloat(Float value) { super(value); } diff --git a/src/main/java/com/imyeyu/java/obs/ObservableInteger.java b/src/main/java/com/imyeyu/java/obs/ObservableInteger.java index 9047cc6..4723073 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableInteger.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableInteger.java @@ -1,14 +1,21 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + /** + * 可观察整型值 + * * @author 夜雨 * @since 2024-09-01 15:06 */ +@NoArgsConstructor public class ObservableInteger extends ObservableObject { - public ObservableInteger() { - } - + /** + * 使用指定初始值创建可观察整型值 + * + * @param value 初始值 + */ public ObservableInteger(Integer value) { super(value); } diff --git a/src/main/java/com/imyeyu/java/obs/ObservableList.java b/src/main/java/com/imyeyu/java/obs/ObservableList.java index 6dce667..dac20da 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableList.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableList.java @@ -7,28 +7,56 @@ import java.util.List; import java.util.function.Predicate; /** + * 可观察列表,支持监听元素新增和删除事件 + * + * @param 元素类型 * @author 夜雨 * @since 2024-09-01 17:51 */ public class ObservableList extends ArrayList { + /** 集合变更监听器列表 */ private final List> changeListenerList = new ArrayList<>(); + /** + * 创建空的可观察列表 + */ public ObservableList() { } + /** + * 使用指定集合创建可观察列表 + * + * @param c 初始化集合 + */ public ObservableList(Collection c) { super(c); } + /** + * 添加集合变更监听器 + * + * @param listener 集合变更监听器 + */ public void addChangeListener(CollectionChangeListener listener) { changeListenerList.add(listener); } + /** + * 移除集合变更监听器 + * + * @param listener 集合变更监听器 + */ public void removeChangeListener(CollectionChangeListener listener) { - changeListenerList.add(listener); + changeListenerList.remove(listener); } + /** + * 新增元素并通知监听器 + * + * @param e 待新增元素 + * @return true 表示列表发生变化 + */ @Override public boolean add(E e) { boolean result = super.add(e); @@ -38,12 +66,24 @@ public class ObservableList extends ArrayList { return result; } + /** + * 在指定下标新增元素并通知监听器 + * + * @param index 插入下标 + * @param element 待新增元素 + */ @Override public void add(int index, E element) { super.add(index, element); CollectionChangeListener.notifyListener(changeListenerList, CollectionChangeListener.ChangeType.ADD, element); } + /** + * 批量新增元素并逐个通知监听器 + * + * @param c 待新增元素集合 + * @return true 表示列表发生变化 + */ @Override public boolean addAll(Collection c) { boolean result = super.addAll(c); @@ -55,6 +95,13 @@ public class ObservableList extends ArrayList { return result; } + /** + * 从指定下标开始批量新增元素并逐个通知监听器 + * + * @param index 起始下标 + * @param c 待新增元素集合 + * @return true 表示列表发生变化 + */ @Override public boolean addAll(int index, Collection c) { boolean result = super.addAll(index, c); @@ -66,6 +113,12 @@ public class ObservableList extends ArrayList { return result; } + /** + * 删除指定下标元素并通知监听器 + * + * @param index 待删除元素下标 + * @return 被删除元素 + */ @Override public E remove(int index) { E removed = super.remove(index); @@ -75,11 +128,23 @@ public class ObservableList extends ArrayList { return removed; } + /** + * 删除指定元素并通知监听器 + * + * @param o 待删除元素 + * @return true 表示删除成功 + */ @Override public boolean remove(Object o) { return remove(indexOf(o)) != null; } + /** + * 批量删除元素并逐个通知监听器 + * + * @param c 待删除元素集合 + * @return true 表示列表发生变化 + */ @SuppressWarnings("unchecked") @Override public boolean removeAll(Collection c) { @@ -92,6 +157,12 @@ public class ObservableList extends ArrayList { return result; } + /** + * 按条件删除元素 + * + * @param filter 删除条件 + * @return true 表示至少删除一个元素 + */ @Override public boolean removeIf(Predicate filter) { boolean removed = false; @@ -106,6 +177,13 @@ public class ObservableList extends ArrayList { return removed; } + /** + * 获取子列表的可观察副本 + * + * @param fromIndex 起始下标(含) + * @param toIndex 结束下标(不含) + * @return 子列表副本 + */ @Override public ObservableList subList(int fromIndex, int toIndex) { List subList = super.subList(fromIndex, toIndex); diff --git a/src/main/java/com/imyeyu/java/obs/ObservableLong.java b/src/main/java/com/imyeyu/java/obs/ObservableLong.java index 985be58..428eef4 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableLong.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableLong.java @@ -1,15 +1,21 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + /** + * 可观察长整型值 + * * @author 夜雨 * @since 2024-09-01 18:43 */ +@NoArgsConstructor public class ObservableLong extends ObservableObject { - public ObservableLong() { - super(); - } - + /** + * 使用指定初始值创建可观察长整型值 + * + * @param value 初始值 + */ public ObservableLong(Long value) { super(value); } diff --git a/src/main/java/com/imyeyu/java/obs/ObservableMap.java b/src/main/java/com/imyeyu/java/obs/ObservableMap.java index c74167b..6a7f7f8 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableMap.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableMap.java @@ -6,21 +6,43 @@ import java.util.List; import java.util.Map; /** + * 可观察映射,支持监听键值对新增、更新和删除事件 + * + * @param 键类型 + * @param 值类型 * @author 夜雨 * @since 2024-09-01 18:32 */ public class ObservableMap extends HashMap { + /** 映射变更监听器列表 */ private final List> changeListenerList = new ArrayList<>(); + /** + * 添加映射变更监听器 + * + * @param listener 映射变更监听器 + */ public void addChangeListener(MapChangeListener listener) { changeListenerList.add(listener); } + /** + * 移除映射变更监听器 + * + * @param listener 映射变更监听器 + */ public void removeChangeListener(MapChangeListener listener) { - changeListenerList.add(listener); + changeListenerList.remove(listener); } + /** + * 写入键值对并在必要时通知监听器 + * + * @param key 键 + * @param value 值 + * @return 旧值,不存在则为 null + */ @Override public V put(K key, V value) { V v = super.put(key, value); @@ -32,6 +54,11 @@ public class ObservableMap extends HashMap { return v; } + /** + * 批量写入键值对 + * + * @param m 待写入映射 + */ @Override public void putAll(Map m) { for (Map.Entry item : m.entrySet()) { @@ -39,6 +66,12 @@ public class ObservableMap extends HashMap { } } + /** + * 删除指定键并通知监听器 + * + * @param key 键 + * @return 被删除值,不存在则为 null + */ @Override public V remove(Object key) { V removed = super.remove(key); @@ -48,6 +81,13 @@ public class ObservableMap extends HashMap { return removed; } + /** + * 仅当键值都匹配时删除并通知监听器 + * + * @param key 键 + * @param value 值 + * @return true 表示删除成功 + */ @SuppressWarnings("unchecked") @Override public boolean remove(Object key, Object value) { diff --git a/src/main/java/com/imyeyu/java/obs/ObservableObject.java b/src/main/java/com/imyeyu/java/obs/ObservableObject.java index c35f98b..ab97a80 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableObject.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableObject.java @@ -1,30 +1,42 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + import java.util.ArrayList; import java.util.List; /** + * 可观察对象抽象基类 + * + * @param 可观察值类型 * @author 夜雨 * @since 2024-09-01 15:22 */ +@NoArgsConstructor public abstract class ObservableObject implements Observable { + /** 值变更监听器列表 */ private final List> changeListenerList = new ArrayList<>(); + /** 当前值 */ private T value; - public ObservableObject() { - } - + /** + * 使用指定初始值创建可观察对象 + * + * @param value 初始值 + */ public ObservableObject(T value) { this.value = value; } + /** {@inheritDoc} */ @Override public final T get() { return value; } + /** {@inheritDoc} */ @Override public final void set(T toValue) { final T from = this.value; @@ -35,11 +47,13 @@ public abstract class ObservableObject implements Observable { } } + /** {@inheritDoc} */ @Override public void addListener(ChangeListener changeListener) { changeListenerList.add(changeListener); } + /** {@inheritDoc} */ @Override public void removeListener(ChangeListener changeListener) { changeListenerList.remove(changeListener); diff --git a/src/main/java/com/imyeyu/java/obs/ObservableSet.java b/src/main/java/com/imyeyu/java/obs/ObservableSet.java index bf13e91..3e01c28 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableSet.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableSet.java @@ -8,21 +8,41 @@ import java.util.List; import java.util.function.Predicate; /** + * 可观察集合,支持监听元素新增和删除事件 + * + * @param 元素类型 * @author 夜雨 * @since 2024-09-01 18:29 */ public class ObservableSet extends HashSet { + /** 集合变更监听器列表 */ private final List> changeListenerList = new ArrayList<>(); + /** + * 添加集合变更监听器 + * + * @param listener 集合变更监听器 + */ public void addChangeListener(CollectionChangeListener listener) { changeListenerList.add(listener); } + /** + * 移除集合变更监听器 + * + * @param listener 集合变更监听器 + */ public void removeChangeListener(CollectionChangeListener listener) { - changeListenerList.add(listener); + changeListenerList.remove(listener); } + /** + * 新增元素并通知监听器 + * + * @param e 待新增元素 + * @return true 表示集合发生变化 + */ @Override public boolean add(E e) { boolean result = super.add(e); @@ -32,6 +52,12 @@ public class ObservableSet extends HashSet { return result; } + /** + * 批量新增元素并逐个通知监听器 + * + * @param c 待新增元素集合 + * @return true 表示集合发生变化 + */ @Override public boolean addAll(Collection c) { boolean result = super.addAll(c); @@ -43,6 +69,12 @@ public class ObservableSet extends HashSet { return result; } + /** + * 删除指定元素并通知监听器 + * + * @param o 待删除元素 + * @return true 表示删除成功 + */ @SuppressWarnings("unchecked") @Override public boolean remove(Object o) { @@ -53,6 +85,12 @@ public class ObservableSet extends HashSet { return removed; } + /** + * 批量删除元素并逐个通知监听器 + * + * @param c 待删除元素集合 + * @return true 表示集合发生变化 + */ @SuppressWarnings("unchecked") @Override public boolean removeAll(Collection c) { @@ -65,6 +103,12 @@ public class ObservableSet extends HashSet { return result; } + /** + * 按条件删除元素 + * + * @param filter 删除条件 + * @return true 表示至少删除一个元素 + */ @Override public boolean removeIf(Predicate filter) { boolean removed = false; diff --git a/src/main/java/com/imyeyu/java/obs/ObservableString.java b/src/main/java/com/imyeyu/java/obs/ObservableString.java index 870f78f..98e8ce7 100644 --- a/src/main/java/com/imyeyu/java/obs/ObservableString.java +++ b/src/main/java/com/imyeyu/java/obs/ObservableString.java @@ -1,27 +1,48 @@ package com.imyeyu.java.obs; +import lombok.NoArgsConstructor; + /** + * 可观察字符串值 + * * @author 夜雨 * @since 2024-09-01 18:43 */ +@NoArgsConstructor public class ObservableString extends ObservableObject { - public ObservableString() { - super(); - } - + /** + * 使用指定初始值创建可观察字符串值 + * + * @param value 初始值 + */ public ObservableString(String value) { super(value); } + /** + * 判断当前字符串是否为空或全空白 + * + * @return true 表示空串或全空白 + */ public boolean isEmpty() { return get().isEmpty() || get().trim().isEmpty(); } + /** + * 判断当前字符串是否非空且非全空白 + * + * @return true 表示非空且包含非空白字符 + */ public boolean isNotEmpty() { return !isEmpty(); } + /** + * 获取当前字符串值 + * + * @return 当前字符串值 + */ @Override public String toString() { return get(); diff --git a/src/main/java/com/imyeyu/java/ref/Ref.java b/src/main/java/com/imyeyu/java/ref/Ref.java index 59caf83..9e59cfe 100644 --- a/src/main/java/com/imyeyu/java/ref/Ref.java +++ b/src/main/java/com/imyeyu/java/ref/Ref.java @@ -7,7 +7,7 @@ import java.util.Collections; import java.util.List; /** - * 反射相关 + * 反射工具类,提供字段与方法查找、字段读写、字符串转枚举等能力 * * @author 夜雨 * @since 2023-05-04 15:05 @@ -15,9 +15,9 @@ import java.util.List; public class Ref { /** - * 获取类字段列表 + * 获取指定类声明的字段列表(不包含父类) * - * @param clazz 类 + * @param clazz 类型对象 * @return 字段列表 */ public static List listFields(Class clazz) { @@ -25,9 +25,9 @@ public class Ref { } /** - * 获取类字段列表(包括父类) + * 获取指定类及其父类声明的字段列表(直到 {@link Object} 之前) * - * @param clazz 类 + * @param clazz 类型对象 * @return 字段列表 */ public static List listAllFields(Class clazz) { @@ -40,20 +40,21 @@ public class Ref { } /** + * 将外部键名转换为 Java 字段名 * - * @param keyName - * @return + * @param keyName 外部键名,支持中划线、下划线和空格分隔 + * @return 驼峰命名字段名 */ public static String getFieldName(String keyName) { String[] splits = {"-", "_", " "}; StringBuilder full = new StringBuilder(keyName.substring(0, 1).toUpperCase() + keyName.substring(1)); - for (int i = 0; i < splits.length; i++) { - if (keyName.contains(splits[i])) { - // 存在分隔符 + for (String split : splits) { + if (keyName.contains(split)) { + // 存在分隔符时,先按分隔符拆词,再按驼峰拼接 full.setLength(0); - String[] word = keyName.split(splits[i]); - for (int j = 0; j < word.length; j++) { - full.append(word[j].substring(0, 1).toUpperCase()).append(word[j].substring(1)); + String[] word = keyName.split(split); + for (String s : word) { + full.append(s.substring(0, 1).toUpperCase()).append(s.substring(1)); } break; } @@ -62,11 +63,12 @@ public class Ref { } /** - * 反射获取对象字段,包括父级类,直至 {@link Object},如果都不存在则返回 null + * 反射获取对象字段,包括父级类,直至 {@link Object},如果都不存在则抛出异常 * * @param clazz 类 * @param fieldName 字段名 - * @return 字段 + * @return 字段对象 + * @throws NullPointerException 找不到字段时抛出异常 */ public static Field getField(Class clazz, String fieldName) { do { @@ -78,7 +80,7 @@ public class Ref { clazz = clazz.getSuperclass(); } } while (clazz != Object.class); - throw new NullPointerException(String.format("not found field: %s in %s", fieldName, clazz)); + throw new NullPointerException("not found field: %s in %s".formatted(fieldName, clazz)); } /** @@ -105,7 +107,7 @@ public class Ref { * @param 返回类型 * @return 字段值 * @throws IllegalAccessException 反射访问失败 - * @throws NullPointerException 向上反射直至 {@link Object} 也找不到该字段 + * @throws NullPointerException 字段对象为空 */ public static T getFieldValue(Object object, Field field, Class toClass) throws IllegalAccessException, NullPointerException { if (field == null) { @@ -120,7 +122,7 @@ public class Ref { * * @param objectClass 类 * @param fieldName 字段名 - * @return 字段 + * @return 字段对象,不存在时返回 null */ public static Field getClassField(Class objectClass, String fieldName) { try { @@ -142,7 +144,7 @@ public class Ref { * @param 值类型 * @return 字段值 * @throws IllegalAccessException 反射访问失败 - * @throws NoSuchFieldException 字段不存在 + * @throws NoSuchFieldException 字段不存在 */ public static T getClassFieldValue(Object object, Class objectClass, String fieldName, Class toClass) throws IllegalAccessException, NoSuchFieldException { Field field = getClassField(objectClass, fieldName); @@ -160,16 +162,19 @@ public class Ref { * @param fieldName 字段名 * @param value 字段值 * @throws IllegalAccessException 反射访问失败 - * @throws NoSuchFieldException 向上反射直至 {@link Object} 也找不到该字段 */ - public static void setFieldValue(Object object, String fieldName, Object value) throws IllegalAccessException, NoSuchFieldException { - Field field = getField(object.getClass(), fieldName); - if (field == null) { - throw new NoSuchFieldException("not found " + fieldName + " field in " + object.getClass().getSimpleName()); - } - setFieldValue(object, field, value); + public static void setFieldValue(Object object, String fieldName, Object value) throws IllegalAccessException { + setFieldValue(object, getField(object.getClass(), fieldName), value); } + /** + * 反射设置对象字段值 + * + * @param object 对象 + * @param field 字段对象 + * @param value 字段值 + * @throws IllegalAccessException 反射访问失败 + */ public static void setFieldValue(Object object, Field field, Object value) throws IllegalAccessException { field.setAccessible(true); field.set(object, value); @@ -200,7 +205,8 @@ public class Ref { * @param clazz 类 * @param methodName 方法名 * @param parameterTypes 可选参 - * @return 方法对象 + * @return 方法对象,不存在时返回 null + * @throws NullPointerException 类对象为空 */ public static Method getMethod(Class clazz, String methodName, Class... parameterTypes) { if (clazz == null) { @@ -224,7 +230,8 @@ public class Ref { * @param clazz 枚举类 * @param string 字符串 * @param 泛型 - * @return 泛型 + * @return 匹配到的枚举值,找不到或输入为空时返回 null + * @throws IllegalArgumentException 传入类型不是枚举类型 */ public static > T toType(Class clazz, String string) { if (string == null) { @@ -234,31 +241,32 @@ public class Ref { if (ts == null) { throw new IllegalArgumentException(clazz.getName() + " is not an enum type"); } - for (int i = 0; i < ts.length; i++) { - if (ts[i].name().equalsIgnoreCase(string)) { - return ts[i]; + for (T t : ts) { + if (t.name().equalsIgnoreCase(string)) { + return t; } } return null; } /** + * 创建字段反射元信息对象 * - * - * @param owner - * @param keyName - * @return + * @param owner 字段所属类型 + * @param keyName 字段键名 + * @return 字段反射元信息 */ public static RefField field(Class owner, String keyName) { return new RefField(owner, keyName); } /** + * 通过无参构造器创建实例 * - * @param type - * @return - * @param - * @throws Exception + * @param type 类型对象 + * @param 泛型类型 + * @return 新实例 + * @throws Exception 反射创建实例异常 */ public static T newInstance(Class type) throws Exception { return type.getDeclaredConstructor().newInstance(); diff --git a/src/main/java/com/imyeyu/java/ref/RefField.java b/src/main/java/com/imyeyu/java/ref/RefField.java index 93aa3f6..c1f10ed 100644 --- a/src/main/java/com/imyeyu/java/ref/RefField.java +++ b/src/main/java/com/imyeyu/java/ref/RefField.java @@ -1,21 +1,39 @@ package com.imyeyu.java.ref; +import lombok.Getter; +import lombok.Setter; + import java.lang.reflect.Field; import java.lang.reflect.Method; /** - * + * 字段反射元信息,包含字段类型以及对应的 getter/setter 方法 * * @author 夜雨 * @since 2024-04-26 15:46 */ +@Getter +@Setter public class RefField { + /** 字段类型 */ private Class type; + + /** 字段对象 */ private Field field; + + /** 字段 setter 方法 */ private Method setter; + + /** 字段 getter 方法 */ private Method getter; + /** + * 根据拥有者类型和键名构建字段反射元信息 + * + * @param owner 字段所属类型 + * @param keyName 字段键名,支持中划线、下划线和空格形式 + */ RefField(Class owner, String keyName) { String fieldName = Ref.getFieldName(keyName); String fieldNameUpper = String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1); @@ -38,40 +56,7 @@ public class RefField { setterName = "set" + fieldNameUpper; getterName = "get" + fieldNameUpper; } - setter = Ref.getMethod(owner, setterName, field.getType()); getter = Ref.getMethod(owner, getterName); } - - public Class getType() { - return type; - } - - public void setType(Class type) { - this.type = type; - } - - public Field getField() { - return field; - } - - public void setField(Field field) { - this.field = field; - } - - public Method getSetter() { - return setter; - } - - public void setSetter(Method setter) { - this.setter = setter; - } - - public Method getGetter() { - return getter; - } - - public void setGetter(Method getter) { - this.getter = getter; - } } diff --git a/src/main/java/com/imyeyu/java/thread/AsyncRetryExecutor.java b/src/main/java/com/imyeyu/java/thread/AsyncRetryExecutor.java index 01e8200..9ffc7c3 100644 --- a/src/main/java/com/imyeyu/java/thread/AsyncRetryExecutor.java +++ b/src/main/java/com/imyeyu/java/thread/AsyncRetryExecutor.java @@ -2,10 +2,15 @@ package com.imyeyu.java.thread; import com.imyeyu.java.bean.Callback; import com.imyeyu.java.bean.CallbackArg; +import com.imyeyu.java.bean.timi.TimiException; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; import java.util.concurrent.TimeUnit; /** + * 异步可重试执行器 * * @author 夜雨 * @since 2025-11-06 17:45 @@ -24,16 +29,30 @@ public class AsyncRetryExecutor { /** true 为守护进程 */ private static final boolean DEFAULT_DAEMON = false; + /** 实际执行重试逻辑的线程 */ private final Thread thread; + + /** true 为执行成功 */ + @Getter private volatile boolean isSuccess = false; + + /** true 为处于运行状态 */ + @Getter private volatile boolean isRunning = false; - private AsyncRetryExecutor(Builder builder) { + /** + * 根据构建器参数创建异步重试执行器 + * + * @param task 构建器对象 + */ + private AsyncRetryExecutor(Task task) { + TimiException.required(task, "not found task"); + TimiException.required(task.getCallback(), "not found task.callback"); thread = new Thread(() -> { int retryCount = 0; - while (isRunning && !isSuccess && (builder.maxRetry < 0 || retryCount <= builder.maxRetry)) { + while (isRunning && !isSuccess && (task.maxRetry < 0 || retryCount <= task.maxRetry)) { try { - builder.callback.handler(); + task.callback.handler(); isSuccess = true; } catch (Exception e) { retryCount++; @@ -41,22 +60,22 @@ public class AsyncRetryExecutor { // 中断 break; } - if (0 < builder.maxRetry && builder.maxRetry < retryCount) { + if (0 < task.maxRetry && task.maxRetry < retryCount) { // 超过重试次数 - builder.onRetryExhausted.handler(e); + task.onRetryExhausted.handler(e); break; } // 重试 try { - TimeUnit.MILLISECONDS.sleep(builder.retryInterval); + TimeUnit.MILLISECONDS.sleep(task.retryInterval); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); break; } } } - }, builder.threadNamePrefix + Thread.currentThread().threadId()); - thread.setDaemon(builder.daemon); + }, task.threadNamePrefix + Thread.currentThread().threadId()); + thread.setDaemon(task.daemon); } /** @@ -65,64 +84,64 @@ public class AsyncRetryExecutor { * @author 夜雨 * @since 2025-11-06 23:37 */ - public static class Builder { + @Data + @Builder + public static class Task { - // 必需参数 - private final Callback callback; + /** 必填回调方法 */ + private Callback callback; - // 可选参数(带默认值) + /** 最大重试次数,-1 为无限重试 */ private int maxRetry = DEFAULT_MAX_RETRY; + + /** 重试间隔毫秒数 */ private long retryInterval = DEFAULT_RETRY_INTERVAL; + + /** 线程名前缀 */ private String threadNamePrefix = DEFAULT_THREAD_NAME_PREFIX; + + /** 是否设置为守护线程 */ private boolean daemon = DEFAULT_DAEMON; + + /** 重试耗尽时的异常回调 */ private CallbackArg onRetryExhausted; - - public Builder(Callback callback) { - this.callback = callback; - } - - public Builder maxRetry(int maxRetry) { - this.maxRetry = maxRetry; - return this; - } - - public Builder retryInterval(long retryInterval) { - this.retryInterval = retryInterval; - return this; - } - - public Builder threadNamePrefix(String prefix) { - this.threadNamePrefix = prefix; - return this; - } - - public Builder daemon(boolean daemon) { - this.daemon = daemon; - return this; - } - - public Builder onRetryExhausted(CallbackArg onRetryExhausted) { - this.onRetryExhausted = onRetryExhausted; - return this; - } - - public AsyncRetryExecutor build() { - return new AsyncRetryExecutor(this); - } } + /** + * 使用默认参数创建执行器 + * + * @param callback 执行回调 + * @return 执行器实例 + */ public static AsyncRetryExecutor create(Callback callback) { - return new Builder(callback).build(); + return new AsyncRetryExecutor(Task.builder().callback(callback).build()); } + /** + * 使用指定最大重试次数创建执行器 + * + * @param callback 执行回调 + * @param maxRetry 最大重试次数 + * @return 执行器实例 + */ public static AsyncRetryExecutor create(Callback callback, int maxRetry) { - return new Builder(callback).maxRetry(maxRetry).build(); + return new AsyncRetryExecutor(Task.builder().callback(callback).maxRetry(maxRetry).build()); } + /** + * 使用指定重试间隔创建执行器 + * + * @param callback 执行回调 + * @param interval 重试间隔毫秒数 + * @return 执行器实例 + */ public static AsyncRetryExecutor create(Callback callback, long interval) { - return new Builder(callback).retryInterval(interval).build(); + return new AsyncRetryExecutor(Task.builder().callback(callback).retryInterval(interval).build()); } + /** + * 启动异步执行 + */ public void start() { if (!isRunning) { isRunning = true; @@ -131,18 +150,13 @@ public class AsyncRetryExecutor { } } + /** + * 中断执行并停止后续重试 + */ public void interrupt() { isRunning = false; if (thread.isAlive() && !thread.isInterrupted()) { thread.interrupt(); } } - - public boolean isSuccess() { - return isSuccess; - } - - public boolean isRunning() { - return isRunning; - } } diff --git a/src/test/java/test/TestThread.java b/src/test/java/com/imyeyu/java/AsyncRetryExecutorTest.java similarity index 65% rename from src/test/java/test/TestThread.java rename to src/test/java/com/imyeyu/java/AsyncRetryExecutorTest.java index 8199710..17cc348 100644 --- a/src/test/java/test/TestThread.java +++ b/src/test/java/com/imyeyu/java/AsyncRetryExecutorTest.java @@ -1,14 +1,23 @@ -package test; +package com.imyeyu.java; import com.imyeyu.java.thread.AsyncRetryExecutor; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** + * 线程工具相关测试 + * * @author 夜雨 * @since 2025-11-06 23:59 */ -public class TestThread { +public class AsyncRetryExecutorTest { + /** + * 验证异步重试执行器在成功后状态为成功 + * + * @throws InterruptedException 等待异步完成时中断异常 + */ @Test public void testAsyncRetryExecutor() throws InterruptedException { Object lock = new Object(); @@ -25,11 +34,9 @@ public class TestThread { } }); executor.start(); - synchronized (lock) { lock.wait(); } - - assert executor.isSuccess(); + assertTrue(executor.isSuccess()); } -} \ No newline at end of file +} diff --git a/src/test/java/test/TestObs.java b/src/test/java/com/imyeyu/java/ObservableTest.java similarity index 69% rename from src/test/java/test/TestObs.java rename to src/test/java/com/imyeyu/java/ObservableTest.java index 9c4a9f7..419d1eb 100644 --- a/src/test/java/test/TestObs.java +++ b/src/test/java/com/imyeyu/java/ObservableTest.java @@ -1,4 +1,4 @@ -package test; +package com.imyeyu.java; import com.imyeyu.java.obs.ObservableList; import com.imyeyu.java.obs.ObservableMap; @@ -7,12 +7,18 @@ import org.junit.jupiter.api.Test; import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + /** + * 可观察对象相关测试 + * * @author 夜雨 * @since 2024-09-01 23:26 */ -public class TestObs { +public class ObservableTest { + /** 验证可观察字符串赋值后值会更新 */ @Test public void testString() { ObservableString obsString = new ObservableString("test1"); @@ -20,9 +26,10 @@ public class TestObs { obsString.addListener((from, to) -> System.out.printf("from %s to %s%n", from, to)); obsString.set("test2"); System.out.println("now value = " + obsString); - assert obsString.get().equals("test2"); + assertEquals("test2", obsString.get()); } + /** 验证可观察列表在多次增删后的最终状态 */ @Test public void testList() { ObservableList list = new ObservableList<>(); @@ -40,8 +47,10 @@ public class TestObs { list.removeAll(List.of("test3", "test4")); list.removeIf(item -> item.equals("test1")); // 移除 0, 1, 2, 3, 4 System.out.println(list); + assertEquals(List.of("test5", "test7", "test8"), list); } + /** 验证可观察映射在新增、更新与删除后的最终状态 */ @Test public void testMap() { ObservableMap map = new ObservableMap<>(); @@ -56,5 +65,11 @@ public class TestObs { map.remove("t1"); map.remove("t2", "test2"); System.out.println(map); + assertEquals(3, map.size()); + assertEquals("test3", map.get("t3")); + assertEquals("test4", map.get("t4")); + assertEquals("test5", map.get("t5")); + assertFalse(map.containsKey("t1")); + assertFalse(map.containsKey("t2")); } } diff --git a/src/test/java/com/imyeyu/java/RefTest.java b/src/test/java/com/imyeyu/java/RefTest.java new file mode 100644 index 0000000..c11928e --- /dev/null +++ b/src/test/java/com/imyeyu/java/RefTest.java @@ -0,0 +1,109 @@ +package com.imyeyu.java; + +import com.imyeyu.java.ref.Ref; +import com.imyeyu.java.ref.RefField; +import lombok.Data; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * 反射工具相关测试 + * + * @author 夜雨 + * @since 2024-04-26 11:05 + */ +@Data +public class RefTest { + + /** 布尔字段,使用 is 前缀 */ + private boolean isBoy; + /** 布尔字段,不使用 is 前缀 */ + private boolean boy; + /** 普通字符串字段 */ + private String fieldName; + + /** 验证字段名标准化转换规则 */ + @Test + public void test() { + String t1 = Ref.getFieldName("is-boy"); + assertEquals("isBoy", t1); + String t2 = Ref.getFieldName("is_boy"); + assertEquals("isBoy", t2); + String t3 = Ref.getFieldName("is boy"); + assertEquals("isBoy", t3); + String t4 = Ref.getFieldName("isBoy"); + assertEquals("isBoy", t4); + String t5 = Ref.getFieldName("boy"); + assertEquals("boy", t5); + String t6 = Ref.getFieldName("fieldName"); + assertEquals("fieldName", t6); + String t7 = Ref.getFieldName("field name"); + assertEquals("fieldName", t7); + String t8 = Ref.getFieldName("field-Name"); + assertEquals("fieldName", t8); + String t9 = Ref.getFieldName("field_Name"); + assertEquals("fieldName", t9); + } + + /** 验证布尔字段 is-boy 能映射到标准 getter/setter */ + @Test + public void refBooleanField() { + RefField refField = Ref.field(RefTest.class, "is-boy"); + assertNotNull(refField.getSetter()); + assertEquals("setBoy", refField.getSetter().getName()); + assertNotNull(refField.getGetter()); + assertEquals("isBoy", refField.getGetter().getName()); + } + + /** 验证布尔字段 boy 能映射到标准 getter/setter */ + @Test + public void refBoolean2Field() { + RefField refField = Ref.field(RefTest.class, "boy"); + assertNotNull(refField.getSetter()); + assertEquals("setBoy", refField.getSetter().getName()); + assertNotNull(refField.getGetter()); + assertEquals("isBoy", refField.getGetter().getName()); + } + + /** 验证字段名 fieldName 能映射到标准 getter/setter */ + @Test + public void refStringField() { + RefField refField = Ref.field(RefTest.class, "fieldName"); + assertNotNull(refField.getSetter()); + assertEquals("setFieldName", refField.getSetter().getName()); + assertNotNull(refField.getGetter()); + assertEquals("getFieldName", refField.getGetter().getName()); + } + + /** 验证字段名 field-name 能映射到标准 getter/setter */ + @Test + public void refString2Field() { + RefField refField = Ref.field(RefTest.class, "field-name"); + assertNotNull(refField.getSetter()); + assertEquals("setFieldName", refField.getSetter().getName()); + assertNotNull(refField.getGetter()); + assertEquals("getFieldName", refField.getGetter().getName()); + } + + /** 验证字段名 field_name 能映射到标准 getter/setter */ + @Test + public void refString3Field() { + RefField refField = Ref.field(RefTest.class, "field_name"); + assertNotNull(refField.getSetter()); + assertEquals("setFieldName", refField.getSetter().getName()); + assertNotNull(refField.getGetter()); + assertEquals("getFieldName", refField.getGetter().getName()); + } + + /** 验证字段名 field name 能映射到标准 getter/setter */ + @Test + public void refString4Field() { + RefField refField = Ref.field(RefTest.class, "field name"); + assertNotNull(refField.getSetter()); + assertEquals("setFieldName", refField.getSetter().getName()); + assertNotNull(refField.getGetter()); + assertEquals("getFieldName", refField.getGetter().getName()); + } +} diff --git a/src/test/java/com/imyeyu/java/TimiJavaTest.java b/src/test/java/com/imyeyu/java/TimiJavaTest.java new file mode 100644 index 0000000..84a9ecb --- /dev/null +++ b/src/test/java/com/imyeyu/java/TimiJavaTest.java @@ -0,0 +1,87 @@ +package com.imyeyu.java; + +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link TimiJava} 静态工具方法测试 + * + * @author 夜雨 + * @since 2026-04-27 10:00 + */ +public class TimiJavaTest { + + /** 验证 isEmpty 与 isNotEmpty 的主要判空分支 */ + @Test + public void testEmptyCheck() { + assertTrue(TimiJava.isEmpty(null)); + assertTrue(TimiJava.isEmpty("")); + assertTrue(TimiJava.isEmpty(" ")); + assertTrue(TimiJava.isEmpty(Collections.emptyList())); + assertTrue(TimiJava.isEmpty(Collections.emptyMap())); + assertFalse(TimiJava.isEmpty("value")); + assertTrue(TimiJava.isNotEmpty("value")); + } + + /** 验证 defaultIfNull 与 defaultIfEmpty 返回默认值逻辑 */ + @Test + public void testDefaultValue() { + assertEquals("default", TimiJava.defaultIfNull(null, "default")); + assertEquals("value", TimiJava.defaultIfNull("value", "default")); + assertEquals("default", TimiJava.defaultIfEmpty(" ", "default")); + assertEquals("value", TimiJava.defaultIfEmpty("value", "default")); + } + + /** 验证 firstNotNull 与 firstNotEmpty 的首个命中逻辑 */ + @Test + public void testFirstValue() { + assertEquals("v1", TimiJava.firstNotNull(null, "v1", "v2")); + assertNull(TimiJava.firstNotNull(null, null)); + assertEquals("v1", TimiJava.firstNotEmpty("", " ", "v1", "v2")); + assertNull(TimiJava.firstNotEmpty("", " ", null)); + } + + /** 验证异常序列化结果包含异常类型与消息 */ + @Test + public void testSerializeThrowable() { + String text = TimiJava.serializeThrowable(new IllegalArgumentException("bad")); + assertTrue(text.contains(IllegalArgumentException.class.getName())); + assertTrue(text.contains("bad")); + } + + /** 验证 safeIterable 在空值与非空场景下都可安全迭代 */ + @Test + public void testSafeIterable() { + Iterable empty = TimiJava.safeIterable(null); + assertNotNull(empty); + assertFalse(empty.iterator().hasNext()); + + Iterable values = TimiJava.safeIterable(List.of("a", "b")); + assertIterableEquals(List.of("a", "b"), values); + } + + /** 验证 ZERO_UUID 常量值 */ + @Test + public void testZeroUuid() { + assertEquals("00000000-0000-0000-0000-000000000000", TimiJava.ZERO_UUID); + } + + /** 验证数组和映射判空路径 */ + @Test + public void testArrayAndMapEmptyCheck() { + assertTrue(TimiJava.isEmpty(new String[]{})); + assertFalse(TimiJava.isEmpty(new String[]{"v"})); + assertTrue(TimiJava.isEmpty(Map.of())); + assertFalse(TimiJava.isEmpty(Map.of("k", "v"))); + } +} diff --git a/src/test/java/test/TestRef.java b/src/test/java/test/TestRef.java deleted file mode 100644 index 7328f4f..0000000 --- a/src/test/java/test/TestRef.java +++ /dev/null @@ -1,96 +0,0 @@ -package test; - -import com.imyeyu.java.ref.Ref; -import com.imyeyu.java.ref.RefField; -import org.junit.jupiter.api.Test; - -/** - * @author 夜雨 - * @since 2024-04-26 11:05 - */ -public class TestRef { - - private boolean isBoy; - private boolean boy; - private String fieldName; - - @Test - public void test() { - String t1 = Ref.getFieldName("is-boy"); - assert t1.equals("isBoy"); - String t2 = Ref.getFieldName("is_boy"); - assert t2.equals("isBoy"); - String t3 = Ref.getFieldName("is boy"); - assert t3.equals("isBoy"); - String t4 = Ref.getFieldName("isBoy"); - assert t4.equals("isBoy"); - String t5 = Ref.getFieldName("boy"); - assert t5.equals("boy"); - String t6 = Ref.getFieldName("fieldName"); - assert t6.equals("fieldName"); - String t7 = Ref.getFieldName("field name"); - assert t7.equals("fieldName"); - String t8 = Ref.getFieldName("field-Name"); - assert t8.equals("fieldName"); - String t9 = Ref.getFieldName("field_Name"); - assert t9.equals("fieldName"); - } - - @Test - public void refBooleanField() { - RefField refField = Ref.field(TestRef.class, "is-boy"); - assert refField.getSetter() != null && refField.getSetter().getName().equals("setBoy"); - assert refField.getGetter() != null && refField.getGetter().getName().equals("isBoy"); - } - - @Test - public void refBoolean2Field() { - RefField refField = Ref.field(TestRef.class, "boy"); - assert refField.getSetter() != null && refField.getSetter().getName().equals("setBoy"); - assert refField.getGetter() != null && refField.getGetter().getName().equals("isBoy"); - } - - @Test - public void refStringField() { - RefField refField = Ref.field(TestRef.class, "fieldName"); - assert refField.getSetter() != null && refField.getSetter().getName().equals("setFieldName"); - assert refField.getGetter() != null && refField.getGetter().getName().equals("getFieldName"); - } - - @Test - public void refString2Field() { - RefField refField = Ref.field(TestRef.class, "field-name"); - assert refField.getSetter() != null && refField.getSetter().getName().equals("setFieldName"); - assert refField.getGetter() != null && refField.getGetter().getName().equals("getFieldName"); - } - - @Test - public void refString3Field() { - RefField refField = Ref.field(TestRef.class, "field_name"); - assert refField.getSetter() != null && refField.getSetter().getName().equals("setFieldName"); - assert refField.getGetter() != null && refField.getGetter().getName().equals("getFieldName"); - } - - @Test - public void refString4Field() { - RefField refField = Ref.field(TestRef.class, "field name"); - assert refField.getSetter() != null && refField.getSetter().getName().equals("setFieldName"); - assert refField.getGetter() != null && refField.getGetter().getName().equals("getFieldName"); - } - - public boolean isBoy() { - return isBoy; - } - - public void setBoy(boolean boy) { - isBoy = boy; - } - - public String getFieldName() { - return fieldName; - } - - public void setFieldName(String fieldName) { - this.fieldName = fieldName; - } -} \ No newline at end of file