From a6a8f4126a5f4884ac2075a8a2bb317b140fd428 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:07:47 +0800 Subject: [PATCH 01/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0SFTP=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/able/enums/FileErrorCode.java | 31 +- .../gitee/qdbp/able/model/file/PathInfo.java | 40 + .../i18n/FileErrorCode_zh_CN.properties | 16 +- .../gitee/qdbp/tools/sftp/SftpChannel.java | 805 ++++++++++++++++++ .../com/gitee/qdbp/tools/sftp/SftpClient.java | 127 +++ .../com/gitee/qdbp/tools/sftp/SftpPath.java | 307 +++++++ 6 files changed, 1323 insertions(+), 3 deletions(-) create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java create mode 100644 tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java create mode 100644 tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java create mode 100644 tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java diff --git a/able/src/main/java/com/gitee/qdbp/able/enums/FileErrorCode.java b/able/src/main/java/com/gitee/qdbp/able/enums/FileErrorCode.java index 8f5b571..fbb1e98 100644 --- a/able/src/main/java/com/gitee/qdbp/able/enums/FileErrorCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/enums/FileErrorCode.java @@ -15,12 +15,39 @@ public enum FileErrorCode implements IResultMessage { FILE_NOT_FOUND, /** 文件读取失败 **/ FILE_READ_ERROR, + /** 文件查询失败 **/ + FILE_QUERY_ERROR, /** 文件写入失败 **/ FILE_WRITE_ERROR, + /** 文件保存失败 **/ + FILE_SAVE_ERROR, + /** 文件导入失败 **/ + FILE_IMPORT_ERROR, + /** 文件导出失败 **/ + FILE_EXPORT_ERROR, + /** 文件上传失败 **/ + FILE_UPLOAD_ERROR, + /** 文件下载失败 **/ + FILE_DOWNLOAD_ERROR, + /** 文件重命名失败 **/ + FILE_RENAME_ERROR, + /** 文件删除失败 **/ + FILE_DELETE_ERROR, + /** 文件处理失败 **/ + FILE_HANDLE_ERROR, + + /** 文件模板格式错误 **/ + FILE_TEMPLATE_ERROR, /** 文件格式错误 **/ FILE_FORMAT_ERROR, - /** 文件模板格式错误 **/ - FILE_TEMPLATE_ERROR; + /** 文件路径错误 **/ + FILE_PATH_ERROR, + /** 文件大小超出限制 **/ + FILE_SIZE_OVER_LIMIT, + /** 缺少文件扩展名 **/ + FILE_EXTENSION_LOSE, + /** 不支持的文件类型; **/ + FILE_EXTENSION_ERROR; /** {@inheritDoc} **/ @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java b/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java new file mode 100644 index 0000000..ea6d58c --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java @@ -0,0 +1,40 @@ +package com.gitee.qdbp.able.model.file; + +/** + * 路径信息 + * + * @author zhaohuihua + * @version 20230312 + */ +public interface PathInfo { + + /** 文件所在目录 **/ + String getDirectory(); + + /** 文件在目录下的相对路径 **/ + String getRelativePath(); + + /** 完整路径 **/ + String getPath(); + + /** 上级路径 **/ + String getParent(); + + /** 文件名 **/ + String getName(); + + /** 是不是文件 **/ + boolean isFile(); + + /** 是不是目录 **/ + boolean isDirectory(); + + /** 最后修改时间 **/ + long lastModified(); + + /** 是否存在 **/ + boolean exists(); + + /** 文件大小 **/ + long length(); +} diff --git a/able/src/main/resources/settings/i18n/FileErrorCode_zh_CN.properties b/able/src/main/resources/settings/i18n/FileErrorCode_zh_CN.properties index 10ee81c..253494b 100644 --- a/able/src/main/resources/settings/i18n/FileErrorCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/FileErrorCode_zh_CN.properties @@ -1,6 +1,20 @@ FILE_NOT_FOUND = 文件不存在 FILE_READ_ERROR = 文件读取失败 +FILE_QUERY_ERROR = 文件查询失败 FILE_WRITE_ERROR = 文件写入失败 -FILE_FORMAT_ERROR = 文件格式错误 +FILE_SAVE_ERROR = 文件保存失败 +FILE_IMPORT_ERROR = 文件导入失败 +FILE_EXPORT_ERROR = 文件导出失败 +FILE_UPLOAD_ERROR = 文件上传失败 +FILE_DOWNLOAD_ERROR = 文件下载失败 +FILE_RENAME_ERROR = 文件重命名失败 +FILE_DELETE_ERROR = 文件删除失败 +FILE_HANDLE_ERROR = 文件处理失败 + FILE_TEMPLATE_ERROR = 文件模板格式错误 +FILE_FORMAT_ERROR = 文件格式错误 +FILE_PATH_ERROR = 文件路径错误 +FILE_SIZE_OVER_LIMIT = 文件大小超出限制 +FILE_EXTENSION_LOSE = 缺少文件扩展名 +FILE_EXTENSION_ERROR = 不支持的文件类型 \ No newline at end of file diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java new file mode 100644 index 0000000..3996477 --- /dev/null +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java @@ -0,0 +1,805 @@ +package com.gitee.qdbp.tools.sftp; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Vector; +import com.gitee.qdbp.able.beans.KeyString; +import com.gitee.qdbp.able.enums.FileErrorCode; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.matches.FileMatcher; +import com.gitee.qdbp.able.model.file.PathInfo; +import com.gitee.qdbp.tools.files.FileTools; +import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.ConvertTools; +import com.gitee.qdbp.tools.utils.StringTools; +import com.gitee.qdbp.tools.utils.VerifyTools; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpException; + +/** + * SFTP操作类
+ * 注意: 以/开头的路径表示当前SFTP用户的根路径, 而不是系统的根路径 + * + * @author zhaohuihua + * @version 20230311 + */ +public class SftpChannel implements AutoCloseable { + + private final Session session; + private final ChannelSftp channel; + + public SftpChannel(Session session, ChannelSftp channel) { + this.session = session; + this.channel = channel; + } + + @Override + public void close() { + if (channel != null) { + channel.disconnect(); + } + if (session != null) { + session.disconnect(); + } + } + + /** 当前目录 **/ + public String pwd() { + return doGetPwd(channel, this.home()); + } + + /** 返回SFTP根目录 (系统绝对路径) **/ + public String home() { + return doGetHome(channel); + } + + /** 返回SFTP根目录 (系统绝对路径) **/ + private static String doGetHome(ChannelSftp channel) { + try { + return channel.getHome(); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails("channel.getHome()"); + } + } + + /** 当前目录 **/ + private static String doGetPwd(ChannelSftp channel, String home) { + String pwd; + try { + pwd = channel.pwd(); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails("channel.pwd()"); + } + if (pwd.equals(home)) { + return "/"; + } else { + return PathTools.concat("/", StringTools.removePrefix(pwd, home), "/"); + } + } + + /** + * 文件下载 + * + * @param remotePath 远程文件路径: 既可以是文件名(下载当前目录下的文件), 也可以是全路径+文件名(根据绝对路径下载) + * @return 返回文件流 + * @throws ServiceException 下载失败 + */ + public InputStream downloadFile(String remotePath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + // 拆分文件目录和文件名 + if (rp.endWithSlash) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR) + .setDetails("remotePath=" + rp.original); + } + + // 下载文件 + try { + return channel.get(rp.effectivePath()); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_DOWNLOAD_ERROR, e) + .setDetails("remotePath=" + rp.original); + } + } + } + + /** + * 文件下载并保存到指定位置 + * + * @param remotePath 远程文件路径: 既可以是文件名(下载当前目录下的文件), 也可以是全路径+文件名(根据绝对路径下载) + * @param clientPath 本地文件路径: 既可以是文件目录(以/结尾,保存为远程文件名), 也可以是全路径+文件名(保存到绝对路径) + * @throws ServiceException 下载失败
+ * FILE_DOWNLOAD_ERROR 文件下载失败
+ * FILE_SAVE_ERROR 文件保存失败 + */ + public void downloadSave(String remotePath, String clientPath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + // 拆分远程路径为文件目录和文件名 + if (rp.endWithSlash || rp.name == null) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR).setDetails("remotePath=" + rp); + } + // 拆分本地路径为文件目录和文件名 + ClientPath cp = ClientPath.of(clientPath); + if (cp.endWithSlash) { + cp = cp.enter(rp.name); + } + + // 拼接路径 + // 判断目标文件是否存在 + SftpPath remoteFile = getFileInfo(rp); + if (remoteFile == null || !remoteFile.isFile()) { + throw new ServiceException(FileErrorCode.FILE_NOT_FOUND).setDetails("remotePath=" + rp); + } + // 如果本地目录不存在则创建 + FileTools.mkdirsIfNotExists(cp.fullPathOnRoot()); + try (OutputStream output = new FileOutputStream(cp.fullPathOnRoot())) { + // 下载文件并保存 + try { + channel.get(rp.effectivePath(), output); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_DOWNLOAD_ERROR, e) + .setDetails("remotePath=" + rp); + } + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_SAVE_ERROR, e).setDetails("clientPath=" + cp); + } + } + } + + /** + * 文件上传 + * + * @param input 输入流 + * @param remotePath 远程文件路径: 既可以是文件名(上传到当前目录), 也可以是全路径+文件名(保存到绝对路径) + */ + public void uploadFile(InputStream input, String remotePath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + if (rp.endWithSlash) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR).setDetails("remotePath=" + rp); + } + + // 创建上传目录 + doMakeDirectory(rp.folder); + + // 文件上传 + try { + channel.put(input, rp.effectivePath()); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_UPLOAD_ERROR, e).setDetails("remotePath=" + rp); + } + } + } + + /** + * 文件上传 (保存到当前目录) + * + * @param clientPath 本地文件路径: 全路径+文件名 + */ + public void uploadFile(String clientPath) { + uploadFile(clientPath, null); + } + + /** + * 文件上传 + * + * @param clientPath 本地文件路径: 全路径+文件名 + * @param remotePath 远程文件路径: 既可以是文件目录(以/结尾,保存为本地文件名), 也可以是全路径+文件名(保存到绝对路径) + */ + public void uploadFile(String clientPath, String remotePath) { + // 拆分本地路径为文件目录和文件名 + ClientPath cp = ClientPath.of(clientPath); + if (cp.endWithSlash || cp.name == null) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR).setDetails("clientPath=" + cp); + } + // 判断文件是否存在 + File clientFile = new File(cp.fullPathOnRoot()); + if (!clientFile.exists()) { + throw new ServiceException(FileErrorCode.FILE_NOT_FOUND) + .setDetails("clientPath=" + cp); + } + if (clientFile.isDirectory()) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR) + .setDetails("clientPath=" + cp); + } + // 拆分远程路径为文件目录和文件名 + try (RemotePath rp = parseRemotePath(remotePath, cp.name)) { + // 创建上传目录 + doMakeDirectory(rp.folder); + + // 文件上传 + try (InputStream input = new FileInputStream(clientFile)) { + try { + channel.put(input, rp.effectivePath()); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_UPLOAD_ERROR, e).setDetails("remotePath=" + rp); + } + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails("clientPath=" + cp); + } + } + } + + private RemotePath parseRemotePath(String remotePath, String clientFileName) { + RemotePath rp; + if (VerifyTools.isBlank(remotePath)) { + rp = RemotePath.of(channel, clientFileName); + } else { + rp = RemotePath.of(channel, remotePath); + if (rp.endWithSlash) { + rp = rp.enter(clientFileName); + } + } + return rp; + } + + private boolean isFileNotFound(SftpException e) { + String message = e.getMessage().toLowerCase(); + return message.contains("no such") || message.contains("not found") || message.contains("not find"); + } + + public SftpPath info(String remotePath) { + return getFileInfo(RemotePath.of(channel, remotePath)); + } + + private SftpPath getFileInfo(RemotePath rp) { + try { + SftpATTRS attrs = channel.lstat(rp.effectivePath()); + return newSftpFile(rp, attrs); + } catch (SftpException e) { + if (isFileNotFound(e)) { + return null; + } else { + throw new ServiceException(FileErrorCode.FILE_HANDLE_ERROR, e) + .setDetails("remotePath=" + rp); + } + } + } + + /** + * 判断指定的文件或目录是否存在 + * + * @param remotePath 远程文件路径: 可以是相对路径文件名/相对路径目录/绝对路径文件名/绝对路径目录 + * @return 是否存在 + */ + public boolean exists(String remotePath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + try { + SftpATTRS attrs = channel.lstat(rp.effectivePath()); + return attrs != null; + } catch (SftpException e) { + if (isFileNotFound(e)) { + return false; + } else { + throw new ServiceException(FileErrorCode.FILE_HANDLE_ERROR, e).setDetails("remotePath=" + rp); + } + } + } + } + + /** + * 判断指定路径是不是文件 + * + * @param remotePath 远程文件路径: 可以是相对路径文件名/相对路径目录/绝对路径文件名/绝对路径目录 + * @return 是否存在 + */ + public boolean isFile(String remotePath) { + return !isDirectory(remotePath); + } + + /** + * 判断指定路径是不是目录 + * + * @param remotePath 远程文件路径: 可以是相对路径文件名/相对路径目录/绝对路径文件名/绝对路径目录 + * @return 是否存在 + */ + public boolean isDirectory(String remotePath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + try { + SftpATTRS attrs = channel.lstat(rp.effectivePath()); + return attrs.isDir() || attrs.isLink(); + } catch (SftpException e) { + if (isFileNotFound(e)) { + return false; + } else { + throw new ServiceException(FileErrorCode.FILE_HANDLE_ERROR, e).setDetails("remotePath=" + rp); + } + } + } + } + + public void mkdir(String remotePath) { + makeDirectory(remotePath); + } + + public void makeDirectory(String remotePath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + doMakeDirectory(rp.effectivePath()); + } + } + + private void doMakeDirectory(String remoteFolder) { + if (VerifyTools.isBlank(remoteFolder)) { + return; + } + List names = StringTools.splits(remoteFolder, '/'); + for (int i = 0; i < names.size(); i++) { + String name = names.get(i); + if (VerifyTools.isBlank(name)) { + continue; + } + String path = ConvertTools.joinToString(names.subList(0, i + 1), '/'); + // 判断是否存在 + SftpATTRS attrs = null; + try { + attrs = channel.lstat(path); + } catch (SftpException ignore) { + } + if (attrs != null) { + if (attrs.isDir() || attrs.isLink()) { + continue; + } else { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR).setDetails("remoteFolder=" + path); + } + } + // 创建目录 + try { + channel.mkdir(path); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_HANDLE_ERROR, e).setDetails("remoteFolder=" + path); + } + } + } + + public void cd(String remoteFolder) { + doChangeDirectory(channel, remoteFolder); + } + + public void toHome() { + String remoteFolder = this.home(); + try { + channel.cd(remoteFolder); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR, e) + .setDetails("remoteFolder=" + remoteFolder); + } + } + + private static void doChangeDirectory(ChannelSftp channel, String remoteFolder) { + if (VerifyTools.isBlank(remoteFolder)) { + return; + } + // 如果是绝对路径, 先跳转至home目录, 再按相对路径处理 + String relativeFolder = remoteFolder; + if (PathTools.isAbsolutePath(remoteFolder)) { + doChangeToHome(channel); + relativeFolder = StringTools.trimLeft(remoteFolder, '/'); + } + try { + channel.cd(relativeFolder); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR, e).setDetails("remoteFolder=" + remoteFolder); + } + } + + private static void doChangeToHome(ChannelSftp channel) { + String home = doGetHome(channel); + try { + channel.cd(home); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_PATH_ERROR, e).setDetails("remoteFolder=/"); + } + } + + /** + * 列出指定目录下所有文件 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @return 文件列表 + */ + public List listFiles(String remotePath) { + return listFiles(remotePath, null); + } + + /** + * 列出指定目录下所有文件 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @param matcher 过滤条件 + * @return 文件列表 + */ + public List listFiles(String remotePath, FileMatcher matcher) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + List paths = doScanPaths(rp, 1, false); + return matcher == null ? paths : filterPaths(paths, matcher); + } + } + + /** + * 递归扫描指定目录下所有文件或目录 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @return 文件列表 + */ + public List scanFiles(String remotePath) { + return scanFiles(remotePath, null); + } + + /** + * 递归扫描指定目录下所有文件 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @param matcher 过滤条件 + * @return 文件列表 + */ + public List scanFiles(String remotePath, FileMatcher matcher) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + List paths = doScanPaths(rp, 1, true); + return matcher == null ? paths : filterPaths(paths, matcher); + } + } + + /** + * 列出指定目录下所有文件或目录 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @return 文件列表 + */ + public List listPaths(String remotePath) { + return listPaths(remotePath, null); + } + + /** + * 列出指定目录下所有文件或目录 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @param matcher 过滤条件 + * @return 文件列表 + */ + public List listPaths(String remotePath, FileMatcher matcher) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + List paths = doScanPaths(rp, 0, false); + return matcher == null ? paths : filterPaths(paths, matcher); + } + } + + /** + * 递归扫描指定目录下所有文件或目录 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @return 文件列表 + */ + public List scanPaths(String remotePath) { + return scanPaths(remotePath, null); + } + + /** + * 递归扫描指定目录下所有文件或目录 + * + * @param remotePath 远程文件路径: 既可以是目录名(当前目录), 也可以是全路径+文件名(绝对路径) + * @param matcher 过滤条件 + * @return 文件列表 + */ + public List scanPaths(String remotePath, FileMatcher matcher) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + List paths = doScanPaths(rp, 0, true); + return matcher == null ? paths : filterPaths(paths, matcher); + } + } + + private List filterPaths(List paths, FileMatcher matcher) { + List result = new ArrayList<>(); + for (PathInfo path : paths) { + if (path instanceof SftpPath) { + SftpPath file = (SftpPath) path; + if (matcher.matches(file)) { + result.add(file); + } + } + } + return result; + } + + // fileType: 0=全部|1=文件|2=目录 + private List doScanPaths(RemotePath rp, int fileType, boolean recursive) { + Vector vector; + try { + vector = channel.ls(VerifyTools.nvl(rp.effectivePath(), ".")); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails("remotePath=" + rp); + } + List result = new ArrayList<>(); + for (Object item : vector) { + ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) item; + String fileName = entry.getFilename(); + if (".".equals(fileName) || "..".equals(fileName)) { + continue; + } + // 判断是文件还是目录 + boolean isDirectory = isDirectory(entry.getAttrs()); + // 判断文件类型是否匹配 + boolean matches; + if (isDirectory) { + matches = fileType == 0 || fileType == 2; + } else { + matches = fileType == 0 || fileType == 1; + } + // 下级对象 + RemotePath next = rp.enter(fileName + (isDirectory ? "/" : "")); + // 文件类型匹配则加入结果集 + if (matches) { + SftpPath file = newSftpFile(next, entry.getAttrs()); + result.add(file); + } + // 递归且是目录则继续处理下级对象 + if (recursive && isDirectory) { + result.addAll(doScanPaths(next, fileType, true)); + } + } + return result; + } + + private SftpPath newSftpFile(BasePath path, SftpATTRS attrs) { + String directory = path.invisiblePath(); + String relativePath = path.effectivePath(); + + SftpPath file = new SftpPath(directory, relativePath); + if (attrs != null) { + boolean isDirectory = isDirectory(attrs); + file.setIsFile(!isDirectory); + file.setIsDirectory(isDirectory); + file.setLength(attrs.getSize()); + file.setPermissions(attrs.getPermissions()); + file.setUpdateTime(new Date(attrs.getMTime() * 1000L)); + } + return file; + } + + private boolean isDirectory(SftpATTRS attrs) { + if (attrs == null) { + return false; + } else { + return attrs.isDir() || attrs.isLink(); + } + } + + /** + * 文件重命名 + * + * @param remotePath 远程文件路径: 既可以是文件名(当前目录), 也可以是全路径+文件名(绝对路径) + * @param newName 新文件名 + */ + public void rename(String remotePath, String newName) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + try { + channel.rename(rp.effectivePath(), newName); + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_RENAME_ERROR, e) + .setDetails("remotePath={}, newName={}", rp, newName); + } + } + } + + /** + * 删除文件 + * + * @param remotePath 远程文件路径: 既可以是文件名(当前目录), 也可以是全路径+文件名(绝对路径) + */ + public boolean deleteFile(String remotePath) { + try (RemotePath rp = RemotePath.of(channel, remotePath)) { + // 判断目标文件是否存在 + SftpPath remoteFile = getFileInfo(rp); + if (remoteFile == null || !remoteFile.isFile()) { + throw new ServiceException(FileErrorCode.FILE_NOT_FOUND).setDetails("remotePath=" + rp.original); + } + + try { + channel.rm(rp.effectivePath()); + return true; + } catch (SftpException e) { + throw new ServiceException(FileErrorCode.FILE_DELETE_ERROR, e).setDetails("remotePath=" + rp); + } + } + } + + /** + * 规范远程路径, 将远程路径统一切分为/home/pwd/folder/name共4个部分
+ * home = SFTP的home目录
+ * pwd = 当前所在路径; 如果传入的是以/开头的绝对路径, 此部分为空
+ * folder = 入参的目录部分; 如果传入的是文件名, 此部分为空
+ * name = 入参的文件名部分; 如果传入的是以/结尾的目录, 此部分也取目录的最后一段, 但isDirectory=true
+ */ + protected static class BasePath { + protected final String original; + protected final String home; + protected final String pwd; + protected final String folder; + protected final String name; + /** 入参是不是以/结尾 (如果明确以/结尾就是目录, 不是/结尾有可能是文件也有可能是目录) **/ + protected final boolean endWithSlash; + + protected BasePath(String original, String home, String pwd, String folder, String name, + boolean endWithSlash) { + this.original = original; + this.home = VerifyTools.isBlank(home) ? null : home; + this.pwd = trimPath(pwd); + this.folder = trimPath(folder); + this.name = trimPath(name); + this.endWithSlash = endWithSlash; + } + + /** 相对于根目录的地址, 即全路径, 返回 /home/pwd/folder/name **/ + public String fullPathOnRoot() { + return PathTools.concat(home, pwd, folder, name, endWithSlash ? "/" : ""); + } + + /** 相对于Home目录的地址, 返回 pwd/folder/name **/ + public String fullPathOnHome() { + return PathTools.concat(pwd, folder, name, endWithSlash ? "/" : ""); + } + + /** 相对于根目录的地址, 即全路径, 返回 /home/pwd/folder/ **/ + public String folderOnRoot() { + return PathTools.concat(home, pwd, folder, "/"); + } + + /** 相对于Home目录的地址, 返回 /pwd/folder/ **/ + public String folderOnHome() { + return PathTools.concat(pwd, folder, "/"); + } + + /** 隐含目录, 不是参数传入的前缀路径 **/ + public String invisiblePath() { + return PathTools.concat(home, pwd, "/"); + } + + /** 有效路径, 参数传入的路径 **/ + public String effectivePath() { + return PathTools.concat(folder, name, endWithSlash ? "/" : ""); + } + + private static String trimPath(String path) { + if (VerifyTools.isBlank(path)) { + return null; + } else { + return StringTools.trimLeft(path, '/'); + } + } + + protected static KeyString splitFolderAndName(String path) { + if (VerifyTools.isBlank(path)) { + return new KeyString(); + } + String tempPath = StringTools.trimRight(path, '/'); + String folder; + String name; + if (tempPath.indexOf('/') < 0) { + folder = null; + name = tempPath; + } else { + folder = PathTools.removeFileName(tempPath); + name = PathTools.getFileName(tempPath); + } + return new KeyString(folder, name); + } + } + + protected static class ClientPath extends BasePath { + + protected ClientPath(String original, String home, String pwd, String folder, String name, + boolean endWithSlash) { + super(original, home, pwd, folder, name, endWithSlash); + } + + /** 进入下级路径 **/ + public ClientPath enter(String path) { + boolean endWithSlash = path.charAt(path.length() - 1) == '/'; + String original = PathTools.concat(this.original, path); + KeyString temp = splitFolderAndName(path); + String folder = PathTools.concat(this.folder, this.name, temp.getKey()); + String name = temp.getValue(); + return new ClientPath(original, home, pwd, folder, name, endWithSlash); + } + + @Override + public String toString() { + return fullPathOnRoot(); + } + + public static ClientPath of(String path) { + VerifyTools.requireNotBlank(path, "path"); + String formatted = (".".equals(path) || "./".equals(path)) ? path : PathTools.formatPath(path); + boolean isAbsolute = formatted.length() > 0 && PathTools.isAbsolutePath(formatted); + boolean endWithSlash = formatted.length() > 0 && formatted.charAt(formatted.length() - 1) == '/'; + + String home; + if (formatted.startsWith("/")) { + String osName = System.getProperty("os.name"); + if (osName != null && osName.startsWith("Windows")) { + home = PathTools.formatPath(new File("/").getAbsolutePath()); + } else { + home = "/"; + } + formatted = formatted.substring(1); + } else if (isAbsolute) { + // D:/home/file-center/ 拆分为 D:/ 和 home/file-center/ + int index = formatted.indexOf('/'); + home = formatted.substring(0, index + 1); + formatted = formatted.substring(index + 1); + } else { + home = PathTools.formatPath(new File("./").getAbsolutePath()); + } + + KeyString temp = splitFolderAndName(formatted); + String folder = temp.getKey(); + String name = temp.getValue(); + return new ClientPath(path, home, null, folder, name, endWithSlash); + } + } + + protected static class RemotePath extends BasePath implements AutoCloseable { + + private final ChannelSftp channel; + private final String oldPwd; + + protected RemotePath(ChannelSftp channel, String oldPwd, + String original, String home, String pwd, String folder, String name, boolean endWithSlash) { + super(original, home, pwd, folder, name, endWithSlash); + this.channel = channel; + this.oldPwd = oldPwd; + if (oldPwd != null && !"/".equals(oldPwd)) { + doChangeToHome(channel); + } + } + + /** 进入下级路径 **/ + public RemotePath enter(String path) { + boolean endWithSlash = path.charAt(path.length() - 1) == '/'; + String original = PathTools.concat(this.original, path); + KeyString temp = splitFolderAndName(path); + String folder = PathTools.concat(this.folder, this.name, temp.getKey()); + String name = temp.getValue(); + return new RemotePath(channel, null, original, home, pwd, folder, name, endWithSlash); + } + + @Override + public void close() { + if (oldPwd != null && !"/".equals(oldPwd)) { + doChangeDirectory(channel, oldPwd); + } + } + + @Override + public String toString() { + return new StringBuilder("{") + .append("realPath:").append(effectivePath()).append(",") + .append("original:").append(original).append(",") + .append("absolute:").append(fullPathOnRoot()).append("}") + .toString(); + } + + public static RemotePath of(ChannelSftp channel, String path) { + VerifyTools.requireNotBlank(path, "path"); + + String formatted = (".".equals(path) || "./".equals(path)) ? path : PathTools.formatPath(path); + boolean isAbsolute = formatted.length() > 0 && formatted.charAt(0) == '/'; + boolean endWithSlash = formatted.length() > 0 && formatted.charAt(formatted.length() - 1) == '/'; + String home = doGetHome(channel); + String pwd = doGetPwd(channel, home); + String pathPwd = isAbsolute ? null : pwd; + String oldPwd = isAbsolute ? pwd : null; + + KeyString temp = splitFolderAndName(formatted); + String folder = temp.getKey(); + String name = temp.getValue(); + return new RemotePath(channel, oldPwd, path, home, pathPwd, folder, name, endWithSlash); + } + } +} diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java new file mode 100644 index 0000000..7f46513 --- /dev/null +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java @@ -0,0 +1,127 @@ +package com.gitee.qdbp.tools.sftp; + +import java.util.Properties; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.utils.VerifyTools; +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +/** + * SFTP工具类 + * + * @author zhaohuihua + * @version 20230310 + */ +public class SftpClient { + + private final String host; + private final int port; + private final String account; + private final String password; + + public static Builder builder() { + return new Builder(); + } + + public SftpClient(String host, int port) { + this(host, port, null, null); + } + + private SftpClient(String host, int port, String account, String password) { + VerifyTools.requireNotBlank(host, "host"); + this.host = host; + this.port = port; + this.account = account; + this.password = password; + } + + public SftpChannel connect() { + JSch jsch = new JSch(); + Session session; + try { + session = jsch.getSession(account, host, port); + } catch (JSchException e) { + throw new ServiceException(ResultCode.REMOTE_SERVICE_ERROR, e) + .setDetails("sftp --> {}:{}", host, port); + } + + if (VerifyTools.isNotBlank(password)) { + session.setPassword(password); + } + + Properties sshConfig = new Properties(); + // ssh会把每个访问过的主机公钥记录在~/.ssh/known_hosts + // 当下次访问相同主机时, OpensSSH会核对公钥 + // 如果公钥不同, ssh会发出警告, 以避免受到DNSHijack之类的攻击 + // 设置StrictHostKeyChecking=no关闭该警告 + sshConfig.put("StrictHostKeyChecking", "no"); + session.setConfig(sshConfig); + try { + session.connect(); + } catch (JSchException e) { + session.disconnect(); + throw new ServiceException(ResultCode.REMOTE_SERVICE_ERROR, e) + .setDetails("sftp --> {}:{}", host, port); + } + + Channel channel; + try { + channel = session.openChannel("sftp"); + } catch (JSchException e) { + session.disconnect(); + throw new ServiceException(ResultCode.REMOTE_SERVICE_ERROR, e) + .setDetails("sftp --> {}:{}", host, port); + } + try { + channel.connect(); + } catch (JSchException e) { + session.disconnect(); + channel.disconnect(); + throw new ServiceException(ResultCode.REMOTE_SERVICE_ERROR, e) + .setDetails("sftp --> {}:{}", host, port); + } + + return new SftpChannel(session, (ChannelSftp) channel); + } + + public static class Builder { + + private String host; + private int port = 22; + private String account; + private String password; + + protected Builder() { + } + + public Builder host(String host) { + this.host = host; + return this; + } + + public Builder port(int port) { + this.port = port; + return this; + } + + public Builder account(String account) { + this.account = account; + return this; + } + + public Builder password(String password) { + this.password = password; + return this; + } + + public SftpClient build() { + VerifyTools.requireNotBlank(host, "host"); + return new SftpClient(host, port, account, password); + } + } +} + diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java new file mode 100644 index 0000000..372b8e6 --- /dev/null +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java @@ -0,0 +1,307 @@ +package com.gitee.qdbp.tools.sftp; + +import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.io.Serializable; +import java.nio.file.Path; +import java.util.Date; +import com.gitee.qdbp.able.model.file.PathInfo; +import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.StringTools; + +/** + * SFTP文件信息 + * + * @author zhaohuihua + * @version 20230311 + */ +public class SftpPath extends File implements Serializable, PathInfo { + + private static final long serialVersionUID = 5852748641005853109L; + + private final String fileName; + private final String directory; + private final String relativePath; + private final String absolutePath; + private long fileSize; + private int permissions; + private boolean isFile; + private boolean isDirectory; + private Date updateTime; + + public SftpPath(String directory, String relativePath) { + super(directory, relativePath); + this.directory = PathTools.formatPath(directory); + this.relativePath = PathTools.formatPath(relativePath); + this.absolutePath = PathTools.concat(this.directory, this.relativePath); + this.fileName = PathTools.getFileName(StringTools.trimRight(relativePath, '/')); + } + + @Override + public String getDirectory() { + return directory; + } + + @Override + public String getRelativePath() { + return relativePath; + } + + @Override + public String getName() { + return fileName; + } + + public int getPermissions() { + return permissions; + } + + public void setPermissions(int permissions) { + this.permissions = permissions; + } + + @Override + public boolean isFile() { + return isFile; + } + + protected void setIsFile(boolean isFile) { + this.isFile = isFile; + } + + @Override + public boolean isDirectory() { + return isDirectory; + } + + protected void setIsDirectory(boolean isDirectory) { + this.isDirectory = isDirectory; + } + + @Override + public long lastModified() { + return this.updateTime == null ? -1 : this.updateTime.getTime(); + } + + public Date getUpdateTime() { + return updateTime; + } + + protected void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + @Override + public String getParent() { + String parent = PathTools.concat(true, absolutePath, ".."); + return parent.startsWith("..") ? null : parent; + } + + @Override + public SftpPath getParentFile() { + return null; + } + + @Override + public String getPath() { + return absolutePath; + } + + @Override + public boolean isAbsolute() { + return true; + } + + @Override + public String getAbsolutePath() { + return absolutePath; + } + + @Override + public SftpPath getAbsoluteFile() { + return this; + } + + @Override + public String getCanonicalPath() { + return absolutePath; + } + + @Override + public SftpPath getCanonicalFile() { + return this; + } + + @Override + public boolean canRead() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean canWrite() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isHidden() { + // 输出json时会访问此方法 + // throw new UnsupportedOperationException(); + return false; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public long length() { + return this.fileSize; + } + + protected void setLength(long fileSize) { + this.fileSize = fileSize; + } + + @Override + public int compareTo(File file) { + return this.absolutePath.compareTo(file.getAbsolutePath()); + } + + @Override + public boolean equals(Object object) { + return object instanceof SftpPath && compareTo((SftpPath) object) == 0; + } + + @Override + public int hashCode() { + return this.absolutePath.hashCode(); + } + + @Override + public String toString() { + return this.absolutePath; + } + + @Override + public boolean createNewFile() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean delete() { + throw new UnsupportedOperationException(); + } + + @Override + public void deleteOnExit() { + throw new UnsupportedOperationException(); + } + + @Override + public String[] list() { + throw new UnsupportedOperationException(); + } + + @Override + public String[] list(FilenameFilter filter) { + throw new UnsupportedOperationException(); + } + + @Override + public File[] listFiles() { + throw new UnsupportedOperationException(); + } + + @Override + public File[] listFiles(FilenameFilter filter) { + throw new UnsupportedOperationException(); + } + + + @Override + public File[] listFiles( FileFilter filter) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean mkdir() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean mkdirs() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean renameTo(File dest) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setLastModified(long time) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setReadOnly() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setWritable(boolean writable, boolean ownerOnly) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setWritable(boolean writable) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setReadable(boolean readable, boolean ownerOnly) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setReadable(boolean readable) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setExecutable(boolean executable, boolean ownerOnly) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean setExecutable(boolean executable) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean canExecute() { + return super.canExecute(); + } + + @Override + public long getTotalSpace() { + return -1; + } + + @Override + public long getFreeSpace() { + return -1; + } + + @Override + public long getUsableSpace() { + return -1; + } + + @Override + public Path toPath() { + throw new UnsupportedOperationException(); + } +} -- Gitee From d96b919813b05670b441bf8f323d073a5e55d0fa Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:08:37 +0800 Subject: [PATCH 02/82] =?UTF-8?q?XML=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=E5=89=8D=E7=BC=80=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/utils/XmlTools.java | 232 +++++++++++++++--- 1 file changed, 193 insertions(+), 39 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java index 2725de3..d7ce192 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java @@ -35,40 +35,11 @@ import org.xml.sax.SAXException; public class XmlTools { public static Map xmlToJson(String xml) { - return xmlToJson(xml, "array,list"); + return xmlToJson(xml, ARRAY_NAME); } public static Map xmlToJson(String xml, String arrayNodeNames) { - XmlToJsonOptions options = new XmlToJsonOptions(); - - // 是否使用驼峰命名 - // 如果为true, 则XML中的将会转换为userList - options.setUseCamelNaming(true); - - // 是否使用属性容器: - // 如果为true, 属性都集中放在一个容器中; - // 如果为false则不加容器, 与子元素放在一起; 此时如果属性名与子节点名相同, 子节点会覆盖属性名 - options.setUseAttrContainer(false); - // options.setAttrContainerName("$attrs"); // useAttrContainer=false时无效 - - // 文本内容的字段名称, 如果节点有属性, 则节点中的文本内容需要有字段名称 - // 333 --> { node:{ x:111, y:222, text:333 } } - // 上例, 由于node有属性, 于是node变成了一个map节点, 那么这里的333必须要有字段名, 否则无法保存 - options.setTextContentName("text"); - - // 数组节点名称 - // 1 2 - // 上例: array下全是同名节点, 将会合并为数组 { aa:[1,2] } - // 1 - // 上例: array下只有一个节点, 也会合并为数组 { aa:[1] } - // 1 2 3 444 - // 上例: array下存在不同名的节点, 将会包装为数组 { array:[ {aa:1}, {aa:2}, {bb:3}, 444 ] } - // 1 - // 上例: array下只有一个文本节点, 也会包装为数组 { array:[1] } - if (VerifyTools.isNotBlank(arrayNodeNames)) { - options.setArrayNodeName(arrayNodeNames); - } - + XmlToJsonOptions options = XmlToJsonOptions.defaults().setArrayNodeName(arrayNodeNames); return xmlToJson(xml, options); } @@ -153,10 +124,29 @@ public class XmlTools { } private static String resolveMapKey(String nodeName, XmlToJsonOptions options) { - if (options == null || !options.isUseCamelNaming()) { + if (options == null) { return nodeName; + } else if (!options.isUseCamelNaming()) { + return handleNamespacePrefix(nodeName, options); } else { - return NamingTools.toCamelString(nodeName); + return NamingTools.toCamelString(handleNamespacePrefix(nodeName, options)); + } + } + + private static String handleNamespacePrefix(String nodeName, XmlToJsonOptions options) { + NamespacePrefixStrategy strategy = options == null ? null : options.getNamespacePrefixStrategy(); + if (strategy == null) { + return nodeName; + } + switch (strategy) { + case REMOTE: + return StringTools.removePrefixAt(nodeName, ":"); + case NORMALIZING: + return StringTools.replace(nodeName, ":", "_"); + case DOLLAR_SEPARATOR: + return StringTools.replace(nodeName, ":", "$"); + default: + return nodeName; } } @@ -410,6 +400,133 @@ public class XmlTools { public static class XmlToJsonOptions { + /** + * 推荐选项 (解析结果有可能与旧版本不一致)
+ * 1. 字段使用驼峰命名
+ * -- <USER_LIST>将会转换为userList
+ * 2. 属性不使用容器, 属性与子元素放在一起
+ * -- 如果属性名与子节点名相同, 子节点会覆盖属性名
+ * 3. 文本内容的字段名称为text (如果节点有属性, 则节点中的文本内容需要有字段名称)
+ * -- <node x="111" y="222">333</node> --> { node:{ x:111, y:222, text:333 } }
+ * 4. 数组节点名称为array,list
+ * -- <array> <aa>1</aa> <aa>2</aa> </array> --> { aa:[1,2] }
+ * 5. 命名空间前缀处理策略为移除
+ * -- <soap:Body>转换为为body + * @return 推荐选项 + */ + public static XmlToJsonOptions recommend() { + XmlToJsonOptions options = defaults(); + // REMOTE: 移除, 转换为body + options.setNamespacePrefixStrategy(NamespacePrefixStrategy.REMOTE); + return defaults(); + } + + /** + * 默认选项 (与旧版本保持一致)
+ * 1. 字段使用驼峰命名
+ * -- <USER_LIST>将会转换为userList
+ * 2. 属性不使用容器, 属性与子元素放在一起
+ * -- 如果属性名与子节点名相同, 子节点会覆盖属性名
+ * 3. 文本内容的字段名称为text (如果节点有属性, 则节点中的文本内容需要有字段名称)
+ * -- <node x="111" y="222">333</node> --> { node:{ x:111, y:222, text:333 } }
+ * 4. 数组节点名称为array,list
+ * -- <array> <aa>1</aa> <aa>2</aa> </array> --> { aa:[1,2] }
+ * 5. 命名空间前缀处理策略为不处理
+ * -- <soap:Body>转换为为soap:body + * + * @return 默认选项 + */ + public static XmlToJsonOptions defaults() { + XmlToJsonOptions options = new XmlToJsonOptions(); + + // 是否使用驼峰命名 + // 如果为true, 则XML中的将会转换为userList + options.setUseCamelNaming(true); + + // 是否使用属性容器: + // 如果为true, 属性都集中放在一个容器中; + // 如果为false则不加容器, 与子元素放在一起; 此时如果属性名与子节点名相同, 子节点会覆盖属性名 + options.setUseAttrContainer(false); + // options.setAttrContainerName("$attrs"); // useAttrContainer=false时无效 + + // 文本内容的字段名称, 如果节点有属性, 则节点中的文本内容需要有字段名称 + // 333 --> { node:{ x:111, y:222, text:333 } } + // 上例, 由于node有属性, 于是node变成了一个map节点, 那么这里的333必须要有字段名, 否则无法保存 + options.setTextContentName("text"); + + // 数组节点名称 + // 1 2 + // 上例: array下全是同名节点, 将会合并为数组 { aa:[1,2] } + // 1 + // 上例: array下只有一个节点, 也会合并为数组 { aa:[1] } + // 1 2 3 444 + // 上例: array下存在不同名的节点, 将会包装为数组 { array:[ {aa:1}, {aa:2}, {bb:3}, 444 ] } + // 1 + // 上例: array下只有一个文本节点, 也会包装为数组 { array:[1] } + options.setArrayNodeName(ARRAY_NAME); + + // NONE: 不处理, 转换为soap:body + // REMOTE: 移除, 转换为body + // NORMALIZING: 标准化处理, 转换为soapBody + // DOLLAR_SEPARATOR: 使用$分隔符, 转换为soap$Body + options.setNamespacePrefixStrategy(NamespacePrefixStrategy.NONE); + + return options; + } + + /** + * 保守选项 (尽量少转换多保留)
+ * 1. 字段不使用驼峰命名
+ * -- <USER_LIST>将会转换为USER_LIST
+ * 2. 属性使用容器, 容器名为'$attrs'
+ * -- 如果属性名与子节点名相同, 子节点会覆盖属性名
+ * 3. 文本内容的字段名称为$text (如果节点有属性, 则节点中的文本内容需要有字段名称)
+ * -- <node x="111" y="222">333</node> --> { node:{ x:111, y:222, $text:333 } }
+ * 4. 数组节点名称为array,list
+ * -- <array> <aa>1</aa> <aa>2</aa> </array> --> { aa:[1,2] }
+ * 5. 命名空间前缀处理策略为不处理
+ * -- <soap:Body>转换为为soap:body + * + * @return 保守选项 + */ + public static XmlToJsonOptions conservative() { + XmlToJsonOptions options = new XmlToJsonOptions(); + + // 是否使用驼峰命名 + // 如果为true, 则XML中的将会转换为userList + options.setUseCamelNaming(false); + + // 是否使用属性容器: + // 如果为true, 属性都集中放在一个容器中; + // 如果为false则不加容器, 与子元素放在一起; 此时如果属性名与子节点名相同, 子节点会覆盖属性名 + options.setUseAttrContainer(true); + options.setAttrContainerName(ATTR_NAME); + + // 文本内容的字段名称, 如果节点有属性, 则节点中的文本内容需要有字段名称 + // 333 --> { node:{ x:111, y:222, text:333 } } + // 上例, 由于node有属性, 于是node变成了一个map节点, 那么这里的333必须要有字段名, 否则无法保存 + options.setTextContentName(TEXT_NAME); + + // 数组节点名称 + // 1 2 + // 上例: array下全是同名节点, 将会合并为数组 { aa:[1,2] } + // 1 + // 上例: array下只有一个节点, 也会合并为数组 { aa:[1] } + // 1 2 3 444 + // 上例: array下存在不同名的节点, 将会包装为数组 { array:[ {aa:1}, {aa:2}, {bb:3}, 444 ] } + // 1 + // 上例: array下只有一个文本节点, 也会包装为数组 { array:[1] } + options.setArrayNodeName(ARRAY_NAME); + + // NONE: 不处理, 转换为soap:body + // REMOTE: 移除, 转换为body + // NORMALIZING: 标准化处理, 转换为soapBody + // DOLLAR_SEPARATOR: 使用$分隔符, 转换为soap$Body + options.setNamespacePrefixStrategy(NamespacePrefixStrategy.NONE); + + return options; + } + /** 是否使用驼峰命名 **/ private boolean useCamelNaming = true; /** 是否使用属性容器: 如果为true, 属性都集中放在一个容器中; 如果为false则不加容器, 与子元素放在一起 **/ @@ -422,6 +539,8 @@ public class XmlTools { private String arrayNodeName = ARRAY_NAME; /** 数组节点匹配接口 **/ private StringMatcher arrayNodeMatcher; + /** 命名空间前缀处理策略 **/ + private NamespacePrefixStrategy namespacePrefixStrategy = NamespacePrefixStrategy.NONE; /** 是否使用驼峰命名 **/ public boolean isUseCamelNaming() { @@ -429,8 +548,9 @@ public class XmlTools { } /** 是否使用驼峰命名 **/ - public void setUseCamelNaming(boolean useCamelNaming) { + public XmlToJsonOptions setUseCamelNaming(boolean useCamelNaming) { this.useCamelNaming = useCamelNaming; + return this; } /** 是否使用属性容器: 如果为true, 属性都集中放在一个容器中; 如果为false则不加容器, 与子元素放在一起 **/ @@ -442,8 +562,9 @@ public class XmlTools { } /** 是否使用属性容器: 如果为true, 属性都集中放在一个容器中; 如果为false则不加容器, 与子元素放在一起 **/ - public void setUseAttrContainer(boolean useAttrContainer) { + public XmlToJsonOptions setUseAttrContainer(boolean useAttrContainer) { this.useAttrContainer = useAttrContainer; + return this; } /** 属性容器名称 **/ @@ -452,8 +573,9 @@ public class XmlTools { } /** 属性容器名称 **/ - public void setAttrContainerName(String attrContainerName) { + public XmlToJsonOptions setAttrContainerName(String attrContainerName) { this.attrContainerName = VerifyTools.nvl(attrContainerName, ATTR_NAME); + return this; } /** 文本内容的字段名称, 如果节点有属性, 则节点中的文本内容需要有字段名称 **/ @@ -464,8 +586,9 @@ public class XmlTools { } /** 文本内容的字段名称, 如果节点有属性, 则节点中的文本内容需要有字段名称 **/ - public void setTextContentName(String textContentName) { + public XmlToJsonOptions setTextContentName(String textContentName) { this.textContentName = VerifyTools.nvl(textContentName, TEXT_NAME); + return this; } /** 数组节点名称 (不区分大小写) **/ @@ -474,8 +597,15 @@ public class XmlTools { } /** 数组节点名称 (不区分大小写) **/ - public void setArrayNodeName(String arrayNodeName) { + public XmlToJsonOptions setArrayNodeName(String arrayNodeName) { this.arrayNodeName = arrayNodeName; + return this; + } + + /** 数组节点名称 (不区分大小写) **/ + public XmlToJsonOptions addArrayNodeName(String arrayNodeName) { + this.arrayNodeName = StringTools.concat(',', this.arrayNodeName, arrayNodeName); + return this; } /** 数组节点匹配接口 **/ @@ -484,8 +614,9 @@ public class XmlTools { } /** 数组节点匹配接口 **/ - public void setArrayNodeMatcher(StringMatcher arrayNodeMatcher) { + public XmlToJsonOptions setArrayNodeMatcher(StringMatcher arrayNodeMatcher) { this.arrayNodeMatcher = arrayNodeMatcher; + return this; } /** 判断是不是数组节点名称 (不区分大小写) **/ @@ -498,6 +629,17 @@ public class XmlTools { } return arrayNodeMatcher != null && arrayNodeMatcher.matches(nodeName); } + + /** 命名空间前缀处理策略 **/ + public NamespacePrefixStrategy getNamespacePrefixStrategy() { + return namespacePrefixStrategy; + } + + /** 命名空间前缀处理策略 **/ + public XmlToJsonOptions setNamespacePrefixStrategy(NamespacePrefixStrategy namespacePrefixStrategy) { + this.namespacePrefixStrategy = namespacePrefixStrategy; + return this; + } } private final static Charset UTF8 = StandardCharsets.UTF_8; @@ -508,4 +650,16 @@ public class XmlTools { /** 静态工具类私有构造方法 **/ private XmlTools() { } + + /** 命名空间前缀处理策略 **/ + public enum NamespacePrefixStrategy { + /** 不处理, 转换为soap:body **/ + NONE, + /** 移除, 转换为body **/ + REMOTE, + /** 标准化处理, 转换为soapBody **/ + NORMALIZING, + /** 使用$分隔符, 转换为soap$Body **/ + DOLLAR_SEPARATOR + } } -- Gitee From abe3e336c03142341f9a851f0b71e9980d0d2090 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:09:18 +0800 Subject: [PATCH 03/82] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B0=86List=E4=BD=9C?= =?UTF-8?q?=E4=B8=BAMap=E5=AF=B9=E8=B1=A1=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/able/beans/LinkedListMap.java | 27 +++++++++++++++++++ .../com/gitee/qdbp/tools/utils/MapTools.java | 23 ++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 able/src/main/java/com/gitee/qdbp/able/beans/LinkedListMap.java diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/LinkedListMap.java b/able/src/main/java/com/gitee/qdbp/able/beans/LinkedListMap.java new file mode 100644 index 0000000..cc08ca3 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/beans/LinkedListMap.java @@ -0,0 +1,27 @@ +package com.gitee.qdbp.able.beans; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import com.gitee.qdbp.tools.utils.MapTools; + +/** + * 用来装List对象的容器 + * + * @author zhaohuihua + * @version 20230315 + */ +public class LinkedListMap extends LinkedHashMap { + + private static final long serialVersionUID = -1985897783368043967L; + + public LinkedListMap(List> list) { + for (int i = 0; i < list.size(); i++) { + this.put(String.valueOf(i), list.get(i)); + } + } + + public List> content() { + return MapTools.toJsonMaps(this.values()); + } +} diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index ade0c17..cdbe93b 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import com.gitee.qdbp.able.beans.DepthMap; +import com.gitee.qdbp.able.beans.LinkedListMap; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.model.reusable.ExpressionMap; import com.gitee.qdbp.able.result.ResultCode; @@ -446,15 +447,27 @@ public class MapTools { return convertValue(value, null, clazz); } + @SuppressWarnings("unchecked") private static T convertValue(Object value, T defaults, Class clazz) { if (value == null && defaults != null) { return defaults; } else { - try { - T result = JsonTools.convert(value, clazz); - return result != null ? result : defaults; - } catch (Exception e) { - return defaults; + if (clazz == Map.class) { + List objects = ConvertTools.parseList(value); + if (objects.size() == 1 && objects.get(0) == value) { + // 如果列表容器只有value一个元素, 说明value不是列表 + return (T) JsonTools.beanToMap(value); + } else { + // 如果结果是数组, 包装成Map返回 + return (T) new LinkedListMap(JsonTools.beanToMaps(objects)); + } + } else { + try { + T result = JsonTools.convert(value, clazz); + return result != null ? result : defaults; + } catch (Exception e) { + return defaults; + } } } } -- Gitee From bb0a66db8f3bc77d67f3b2b76b7b96fe84da332d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:20:13 +0800 Subject: [PATCH 04/82] =?UTF-8?q?XML=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=E5=89=8D=E7=BC=80=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/tools/utils/XmlTools.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java index d7ce192..905967e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java @@ -139,7 +139,7 @@ public class XmlTools { return nodeName; } switch (strategy) { - case REMOTE: + case REMOVE: return StringTools.removePrefixAt(nodeName, ":"); case NORMALIZING: return StringTools.replace(nodeName, ":", "_"); @@ -417,8 +417,8 @@ public class XmlTools { public static XmlToJsonOptions recommend() { XmlToJsonOptions options = defaults(); // REMOTE: 移除, 转换为body - options.setNamespacePrefixStrategy(NamespacePrefixStrategy.REMOTE); - return defaults(); + options.setNamespacePrefixStrategy(NamespacePrefixStrategy.REMOVE); + return options; } /** @@ -656,7 +656,7 @@ public class XmlTools { /** 不处理, 转换为soap:body **/ NONE, /** 移除, 转换为body **/ - REMOTE, + REMOVE, /** 标准化处理, 转换为soapBody **/ NORMALIZING, /** 使用$分隔符, 转换为soap$Body **/ -- Gitee From afb03bd204e3b61413cacadade3cd7430e2d4d4c Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:30:13 +0800 Subject: [PATCH 05/82] =?UTF-8?q?XML=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=E5=89=8D=E7=BC=80=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java index 905967e..e37daac 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/XmlTools.java @@ -413,6 +413,7 @@ public class XmlTools { * 5. 命名空间前缀处理策略为移除
* -- <soap:Body>转换为为body * @return 推荐选项 + * @since 5.5.10 */ public static XmlToJsonOptions recommend() { XmlToJsonOptions options = defaults(); @@ -435,6 +436,7 @@ public class XmlTools { * -- <soap:Body>转换为为soap:body * * @return 默认选项 + * @since 5.5.10 */ public static XmlToJsonOptions defaults() { XmlToJsonOptions options = new XmlToJsonOptions(); @@ -488,6 +490,7 @@ public class XmlTools { * -- <soap:Body>转换为为soap:body * * @return 保守选项 + * @since 5.5.10 */ public static XmlToJsonOptions conservative() { XmlToJsonOptions options = new XmlToJsonOptions(); -- Gitee From 26df01065e8eaf8d94c95b5002f75ad86b29082f Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:31:27 +0800 Subject: [PATCH 06/82] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java | 1 + tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java | 1 + tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java | 1 + tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java b/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java index ea6d58c..3ed4af6 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/file/PathInfo.java @@ -5,6 +5,7 @@ package com.gitee.qdbp.able.model.file; * * @author zhaohuihua * @version 20230312 + * @since 5.5.10 */ public interface PathInfo { diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java index 3996477..9988f1d 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java @@ -31,6 +31,7 @@ import com.jcraft.jsch.SftpException; * * @author zhaohuihua * @version 20230311 + * @since 5.5.10 */ public class SftpChannel implements AutoCloseable { diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java index 7f46513..0982329 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java @@ -15,6 +15,7 @@ import com.jcraft.jsch.Session; * * @author zhaohuihua * @version 20230310 + * @since 5.5.10 */ public class SftpClient { diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java index 372b8e6..edc1409 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java @@ -15,8 +15,9 @@ import com.gitee.qdbp.tools.utils.StringTools; * * @author zhaohuihua * @version 20230311 + * @since 5.5.10 */ -public class SftpPath extends File implements Serializable, PathInfo { +public class SftpPath extends File implements PathInfo, Serializable { private static final long serialVersionUID = 5852748641005853109L; -- Gitee From a38725d6cdc847a46aa206d607e67ecd67e6b7d9 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Mar 2023 22:33:29 +0800 Subject: [PATCH 07/82] 5.5.10 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 10 +++++++++- 10 files changed, 20 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b0523cc..6dec2d1 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.8 + 5.5.10 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.8 + 5.5.10 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 3d2959f..19aeb14 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.8 + 5.5.10 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 0ec7a34..43066ad 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.8 + 5.5.10 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.8 + 5.5.10 diff --git a/test/pom.xml b/test/pom.xml index 29ebfac..094a0af 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.8 + 5.5.10 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index b2ef860..e1be19e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.8 + 5.5.10 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 6ce1ac6..9f31f0e 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.8 + 5.5.10 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 1c392ac..71210ff 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.8 + 5.5.10 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 40b34ff..24fc8e9 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.8 + 5.5.10 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index c96d357..7cb0a52 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.8 + 5.5.10 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index 33ed5ab..4334c55 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.8 + 5.5.10 https://gitee.com/qdbp/qdbp-able/ qdbp tools library @@ -47,6 +47,14 @@ true + + + com.jcraft + jsch + 0.1.55 + true + + ognl ognl -- Gitee From 6180104c45f62d9a19152b7b4856ca25ac0e8065 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 19 Mar 2023 22:53:58 +0800 Subject: [PATCH 08/82] =?UTF-8?q?Debugger=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/able/debug/BaseDebugger.java | 30 +++++++++++++++++-- .../com/gitee/qdbp/able/debug/Debugger.java | 22 +++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java b/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java index f8e2a6a..678b411 100644 --- a/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java +++ b/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java @@ -1,5 +1,7 @@ package com.gitee.qdbp.able.debug; +import java.math.BigDecimal; +import java.text.DecimalFormat; import java.util.Date; import java.util.List; import com.gitee.qdbp.able.matches.StringMatcher; @@ -44,15 +46,39 @@ public abstract class BaseDebugger implements Debugger { log(buffer.toString()); } + @Override + public void debug(Formatted formatted) { + log(formatted.getMessage()); + } + + private static final String DECIMAL_FORMAT = "#.##################"; + protected void makeMessage(StringBuffer buffer, String format, Object... args) { + makeMessage(buffer, new Date(), format, args); + } + + protected void makeMessage(StringBuffer buffer, Date time, String format, Object... args) { if (timePattern != null) { - buffer.append(DateTools.format(new Date(), timePattern)).append(' '); + buffer.append(DateTools.format(time, timePattern)).append(' '); } if (args == null || args.length == 0) { buffer.append(format); } else { String fmt = StringTools.replace(format, "{}", "%s"); - buffer.append(String.format(fmt, args)); + Object[] params = new String[args.length]; + for (int i = 0; i < args.length; i++) { + Object item = args[i]; + if (item instanceof Date) { + params[i] = DateTools.toAutoString((Date) item); + } else if (item instanceof Double) { + params[i] = new DecimalFormat(DECIMAL_FORMAT).format(item); + } else if (item instanceof BigDecimal) { + params[i] = ConvertTools.toPlainString((BigDecimal) item); + } else { + params[i] = item; + } + } + buffer.append(String.format(fmt, params)); // 如果参数比占位符多, 且最后一个参数是异常类, 则输出异常堆栈 Object last = args[args.length - 1]; if (last instanceof Throwable) { diff --git a/able/src/main/java/com/gitee/qdbp/able/debug/Debugger.java b/able/src/main/java/com/gitee/qdbp/able/debug/Debugger.java index 3c4ed0b..376af95 100644 --- a/able/src/main/java/com/gitee/qdbp/able/debug/Debugger.java +++ b/able/src/main/java/com/gitee/qdbp/able/debug/Debugger.java @@ -10,12 +10,32 @@ public interface Debugger { /** * 记录日志 - * + * * @param message 消息内容 * @param args 占位符参数 */ void debug(String message, Object... args); + /** + * 记录日志 + * + * @param formatted 已格式化的消息内容 + */ + void debug(Formatted formatted); + + class Formatted { + + private final String message; + + public Formatted(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + } + interface Aware { void setDebugger(Debugger debugger); -- Gitee From 34d190634da3b540d19b99955cc7b036ab5669c8 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sat, 25 Mar 2023 22:12:20 +0800 Subject: [PATCH 09/82] ExtensionFileMatcher --- .../able/matches/ExtensionFileMatcher.java | 65 +++++++++++++++++++ .../qdbp/able/matches/WrapFileMatcher.java | 6 ++ 2 files changed, 71 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/able/matches/ExtensionFileMatcher.java diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/ExtensionFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/ExtensionFileMatcher.java new file mode 100644 index 0000000..f718f35 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/matches/ExtensionFileMatcher.java @@ -0,0 +1,65 @@ +package com.gitee.qdbp.able.matches; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.gitee.qdbp.able.matches.StringMatcher.Matches; +import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.ConvertTools; +import com.gitee.qdbp.tools.utils.StringTools; + +/** + * 文件后缀匹配规则
+ * new ExtensionFileMatcher("doc,docx,xls,xlsx");
+ * + * @author zhaohuihua + * @version 20230324 + */ +public class ExtensionFileMatcher implements FileMatcher { + + /** 是否反转判断结果 **/ + private final boolean reverse; + private final String pattern; + private final Map extensions = new HashMap<>(); + + public ExtensionFileMatcher(String extensions) { + this(extensions, Matches.Positive); + } + + public ExtensionFileMatcher(String extensions, Matches mode) { + this.reverse = mode == Matches.Negative; + this.pattern = extensions; + List items = StringTools.splits(extensions, ','); + for (String extension : items) { + this.extensions.put(extension.toLowerCase(), null); + } + } + + public ExtensionFileMatcher(List extensions) { + this(extensions, Matches.Positive); + } + + public ExtensionFileMatcher(List extensions, Matches mode) { + this.reverse = mode == Matches.Negative; + this.pattern = ConvertTools.joinToString(extensions); + for (String extension : extensions) { + this.extensions.put(extension.toLowerCase(), null); + } + } + + @Override + public boolean matches(File source) { + String extension = PathTools.getExtension(source.getName(), false).toLowerCase(); + return this.extensions.containsKey(extension) != reverse; + } + + @Override + public String toString() { + if (reverse) { + return "extension!:" + pattern; + } else { + return "extension:" + pattern; + } + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/WrapFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/WrapFileMatcher.java index 9e46629..e32352a 100644 --- a/able/src/main/java/com/gitee/qdbp/able/matches/WrapFileMatcher.java +++ b/able/src/main/java/com/gitee/qdbp/able/matches/WrapFileMatcher.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.gitee.qdbp.able.matches.StringMatcher.LogicType; +import com.gitee.qdbp.able.matches.StringMatcher.Matches; import com.gitee.qdbp.tools.utils.ConvertTools; import com.gitee.qdbp.tools.utils.StringTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -194,6 +195,11 @@ public class WrapFileMatcher implements FileMatcher { */ public static FileMatcher parseMatcher(String pattern, String defaultTarget, String defaultMode) { VerifyTools.requireNotBlank(pattern, "pattern"); + if (pattern.startsWith("extension:")) { + return new ExtensionFileMatcher(pattern.substring("extension:".length())); + } else if (pattern.startsWith("extension!:")) { + return new ExtensionFileMatcher(pattern.substring("extension!:".length()), Matches.Negative); + } Target target; if (pattern.startsWith("name:")) { target = Target.FileName; -- Gitee From be12d50368765b96a8659312b55def27108b136a Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sat, 25 Mar 2023 22:16:02 +0800 Subject: [PATCH 10/82] =?UTF-8?q?FileMatcher=E5=A2=9E=E5=8A=A0of=E7=B3=BB?= =?UTF-8?q?=E5=88=97=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/able/matches/AntFileMatcher.java | 16 ++++++++++++++++ .../gitee/qdbp/able/matches/EndsFileMatcher.java | 15 +++++++++++++++ .../qdbp/able/matches/EqualsFileMatcher.java | 16 ++++++++++++++++ .../qdbp/able/matches/RegexpFileMatcher.java | 16 ++++++++++++++++ .../qdbp/able/matches/StartsFileMatcher.java | 15 +++++++++++++++ 5 files changed, 78 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/AntFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/AntFileMatcher.java index 8362eb9..ad75b91 100644 --- a/able/src/main/java/com/gitee/qdbp/able/matches/AntFileMatcher.java +++ b/able/src/main/java/com/gitee/qdbp/able/matches/AntFileMatcher.java @@ -31,4 +31,20 @@ public class AntFileMatcher extends BaseFileMatcher { public AntFileMatcher(String pattern, Target target, Matches mode) { super(new AntStringMatcher(pattern, true, mode), target); } + + public static AntFileMatcher ofNameMatches(String pattern) { + return new AntFileMatcher(pattern, Target.FileName, Matches.Positive); + } + + public static AntFileMatcher ofPathMatches(String pattern) { + return new AntFileMatcher(pattern, Target.FilePath, Matches.Positive); + } + + public static AntFileMatcher ofNameNotMatches(String pattern) { + return new AntFileMatcher(pattern, Target.FileName, Matches.Negative); + } + + public static AntFileMatcher ofPathNotMatches(String pattern) { + return new AntFileMatcher(pattern, Target.FilePath, Matches.Negative); + } } diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/EndsFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/EndsFileMatcher.java index 7b36215..75ff976 100644 --- a/able/src/main/java/com/gitee/qdbp/able/matches/EndsFileMatcher.java +++ b/able/src/main/java/com/gitee/qdbp/able/matches/EndsFileMatcher.java @@ -32,4 +32,19 @@ public class EndsFileMatcher extends BaseFileMatcher { super(new EndsStringMatcher(pattern, mode), target); } + public static EndsFileMatcher ofNameMatches(String pattern) { + return new EndsFileMatcher(pattern, Target.FileName, Matches.Positive); + } + + public static EndsFileMatcher ofPathMatches(String pattern) { + return new EndsFileMatcher(pattern, Target.FilePath, Matches.Positive); + } + + public static EndsFileMatcher ofNameNotMatches(String pattern) { + return new EndsFileMatcher(pattern, Target.FileName, Matches.Negative); + } + + public static EndsFileMatcher ofPathNotMatches(String pattern) { + return new EndsFileMatcher(pattern, Target.FilePath, Matches.Negative); + } } diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/EqualsFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/EqualsFileMatcher.java index 8a320f8..4a8f3b1 100644 --- a/able/src/main/java/com/gitee/qdbp/able/matches/EqualsFileMatcher.java +++ b/able/src/main/java/com/gitee/qdbp/able/matches/EqualsFileMatcher.java @@ -31,4 +31,20 @@ public class EqualsFileMatcher extends BaseFileMatcher { public EqualsFileMatcher(String pattern, Target target, Matches mode) { super(new EqualsStringMatcher(pattern, mode), target); } + + public static EqualsFileMatcher ofNameMatches(String pattern) { + return new EqualsFileMatcher(pattern, Target.FileName, Matches.Positive); + } + + public static EqualsFileMatcher ofPathMatches(String pattern) { + return new EqualsFileMatcher(pattern, Target.FilePath, Matches.Positive); + } + + public static EqualsFileMatcher ofNameNotMatches(String pattern) { + return new EqualsFileMatcher(pattern, Target.FileName, Matches.Negative); + } + + public static EqualsFileMatcher ofPathNotMatches(String pattern) { + return new EqualsFileMatcher(pattern, Target.FilePath, Matches.Negative); + } } diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/RegexpFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/RegexpFileMatcher.java index 86f3304..4ac65dc 100644 --- a/able/src/main/java/com/gitee/qdbp/able/matches/RegexpFileMatcher.java +++ b/able/src/main/java/com/gitee/qdbp/able/matches/RegexpFileMatcher.java @@ -53,4 +53,20 @@ public class RegexpFileMatcher extends BaseFileMatcher { public RegexpFileMatcher(Pattern pattern, Target target, Matches mode) { super(new RegexpStringMatcher(pattern, mode), target); } + + public static RegexpFileMatcher ofNameMatches(String pattern) { + return new RegexpFileMatcher(pattern, Target.FileName, Matches.Positive); + } + + public static RegexpFileMatcher ofPathMatches(String pattern) { + return new RegexpFileMatcher(pattern, Target.FilePath, Matches.Positive); + } + + public static RegexpFileMatcher ofNameNotMatches(String pattern) { + return new RegexpFileMatcher(pattern, Target.FileName, Matches.Negative); + } + + public static RegexpFileMatcher ofPathNotMatches(String pattern) { + return new RegexpFileMatcher(pattern, Target.FilePath, Matches.Negative); + } } diff --git a/able/src/main/java/com/gitee/qdbp/able/matches/StartsFileMatcher.java b/able/src/main/java/com/gitee/qdbp/able/matches/StartsFileMatcher.java index 52cb3a4..98823d4 100644 --- a/able/src/main/java/com/gitee/qdbp/able/matches/StartsFileMatcher.java +++ b/able/src/main/java/com/gitee/qdbp/able/matches/StartsFileMatcher.java @@ -32,4 +32,19 @@ public class StartsFileMatcher extends BaseFileMatcher { super(new StartsStringMatcher(pattern, mode), target); } + public static StartsFileMatcher ofNameMatches(String pattern) { + return new StartsFileMatcher(pattern, Target.FileName, Matches.Positive); + } + + public static StartsFileMatcher ofPathMatches(String pattern) { + return new StartsFileMatcher(pattern, Target.FilePath, Matches.Positive); + } + + public static StartsFileMatcher ofNameNotMatches(String pattern) { + return new StartsFileMatcher(pattern, Target.FileName, Matches.Negative); + } + + public static StartsFileMatcher ofPathNotMatches(String pattern) { + return new StartsFileMatcher(pattern, Target.FilePath, Matches.Negative); + } } -- Gitee From 5dd3f1aa6a750cdcdc5652535e90254e30198066 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sat, 25 Mar 2023 22:21:18 +0800 Subject: [PATCH 11/82] =?UTF-8?q?beanToMap=E4=BC=98=E5=8C=96,=20=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E7=A9=BA=E5=80=BC=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/tools/utils/MapTools.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index cdbe93b..7124c3e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -132,7 +132,7 @@ public class MapTools { return null; } try { - return JsonTools.beanToMap(item); + return JsonTools.beanToMap(item, true, false); } catch (ServiceException e) { if (!throwOnError) { return null; @@ -456,10 +456,10 @@ public class MapTools { List objects = ConvertTools.parseList(value); if (objects.size() == 1 && objects.get(0) == value) { // 如果列表容器只有value一个元素, 说明value不是列表 - return (T) JsonTools.beanToMap(value); + return (T) toJsonMap((Map) value); } else { // 如果结果是数组, 包装成Map返回 - return (T) new LinkedListMap(JsonTools.beanToMaps(objects)); + return (T) new LinkedListMap(JsonTools.beanToMaps(objects, true, false)); } } else { try { @@ -922,7 +922,7 @@ public class MapTools { Map child = MapTools.toJsonMap((Map) fieldValue); doEachMap(fieldPath, child, interceptor); } else if (!ReflectTools.isPrimitive(fieldValue.getClass(), false)) { - Map child = JsonTools.beanToMap(fieldValue); + Map child = JsonTools.beanToMap(fieldValue, true, false); mapEntry.setValue(child); doEachMap(fieldPath, child, interceptor); } -- Gitee From 823453262bae70e40d0e46218ba1eef2c05a1101 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sat, 25 Mar 2023 22:44:20 +0800 Subject: [PATCH 12/82] =?UTF-8?q?sftp=E7=9A=84downloadSave=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BF=9D=E5=AD=98=E8=B7=AF=E5=BE=84=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java index 9988f1d..4449081 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java @@ -117,11 +117,12 @@ public class SftpChannel implements AutoCloseable { * * @param remotePath 远程文件路径: 既可以是文件名(下载当前目录下的文件), 也可以是全路径+文件名(根据绝对路径下载) * @param clientPath 本地文件路径: 既可以是文件目录(以/结尾,保存为远程文件名), 也可以是全路径+文件名(保存到绝对路径) + * @return 实际保存路径 * @throws ServiceException 下载失败
* FILE_DOWNLOAD_ERROR 文件下载失败
* FILE_SAVE_ERROR 文件保存失败 */ - public void downloadSave(String remotePath, String clientPath) { + public String downloadSave(String remotePath, String clientPath) { try (RemotePath rp = RemotePath.of(channel, remotePath)) { // 拆分远程路径为文件目录和文件名 if (rp.endWithSlash || rp.name == null) { @@ -140,11 +141,13 @@ public class SftpChannel implements AutoCloseable { throw new ServiceException(FileErrorCode.FILE_NOT_FOUND).setDetails("remotePath=" + rp); } // 如果本地目录不存在则创建 - FileTools.mkdirsIfNotExists(cp.fullPathOnRoot()); - try (OutputStream output = new FileOutputStream(cp.fullPathOnRoot())) { + String savePath = cp.fullPathOnRoot(); + FileTools.mkdirsIfNotExists(savePath); + try (OutputStream output = new FileOutputStream(savePath)) { // 下载文件并保存 try { channel.get(rp.effectivePath(), output); + return savePath; } catch (SftpException e) { throw new ServiceException(FileErrorCode.FILE_DOWNLOAD_ERROR, e) .setDetails("remotePath=" + rp); -- Gitee From 080d6a108b07a5cfa1c1204b60a76364180848fe Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sat, 25 Mar 2023 22:45:11 +0800 Subject: [PATCH 13/82] =?UTF-8?q?sftp=E5=A2=9E=E5=8A=A0Getter,=20=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E6=94=B9=E4=B8=BAbyte[]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/sftp/SftpClient.java | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java index 0982329..70187b4 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpClient.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.tools.sftp; +import java.nio.charset.StandardCharsets; import java.util.Properties; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; @@ -22,7 +23,7 @@ public class SftpClient { private final String host; private final int port; private final String account; - private final String password; + private final byte[] password; public static Builder builder() { return new Builder(); @@ -32,7 +33,7 @@ public class SftpClient { this(host, port, null, null); } - private SftpClient(String host, int port, String account, String password) { + private SftpClient(String host, int port, String account, byte[] password) { VerifyTools.requireNotBlank(host, "host"); this.host = host; this.port = port; @@ -50,7 +51,7 @@ public class SftpClient { .setDetails("sftp --> {}:{}", host, port); } - if (VerifyTools.isNotBlank(password)) { + if (password != null) { session.setPassword(password); } @@ -89,12 +90,33 @@ public class SftpClient { return new SftpChannel(session, (ChannelSftp) channel); } + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public String getAccount() { return account; } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + if (VerifyTools.isNotBlank(account)) { + buffer.append(account).append('@'); + } + buffer.append(host); + buffer.append(':').append(port); + return buffer.toString(); + } + public static class Builder { private String host; private int port = 22; private String account; - private String password; + private byte[] password; protected Builder() { } @@ -114,11 +136,20 @@ public class SftpClient { return this; } - public Builder password(String password) { + public Builder password(byte[] password) { this.password = password; return this; } + public Builder password(String password) { + if (VerifyTools.isBlank(password)) { + this.password = null; + } else { + this.password = password.getBytes(StandardCharsets.UTF_8); + } + return this; + } + public SftpClient build() { VerifyTools.requireNotBlank(host, "host"); return new SftpClient(host, port, account, password); -- Gitee From 83754360cd733ffcf3da8cea439d9eadf42bc13f Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sat, 25 Mar 2023 22:47:43 +0800 Subject: [PATCH 14/82] =?UTF-8?q?qdbp=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6dec2d1..e354a10 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.10 + 5.5.12 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.10 + 5.5.12 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 19aeb14..7ec4ef6 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.10 + 5.5.12 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 43066ad..16296ad 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.10 + 5.5.12 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.10 + 5.5.12 diff --git a/test/pom.xml b/test/pom.xml index 094a0af..e09c511 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.10 + 5.5.12 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index e1be19e..97e668c 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.10 + 5.5.12 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 9f31f0e..b901ebc 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.10 + 5.5.12 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 71210ff..24a9865 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.10 + 5.5.12 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 24fc8e9..04b6278 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.10 + 5.5.12 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 7cb0a52..22e4b55 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.10 + 5.5.12 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index 4334c55..c51ae0b 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.10 + 5.5.12 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 28afb5bc88ddb2a9fbf1aa92990a81fc32516041 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Mar 2023 10:33:34 +0800 Subject: [PATCH 15/82] =?UTF-8?q?SftpChannel.info=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E6=94=B9=E4=B8=BAPathInfo=20(SftpPath=E4=BB=85=E4=BE=9B?= =?UTF-8?q?=E5=86=85=E9=83=A8=E4=BD=BF=E7=94=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java index 4449081..a6cc7cc 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpChannel.java @@ -249,7 +249,7 @@ public class SftpChannel implements AutoCloseable { return message.contains("no such") || message.contains("not found") || message.contains("not find"); } - public SftpPath info(String remotePath) { + public PathInfo info(String remotePath) { return getFileInfo(RemotePath.of(channel, remotePath)); } -- Gitee From 95224b4ddfa6ae4dd1f6758cdae26bb1a9b4e9e1 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Mar 2023 10:36:34 +0800 Subject: [PATCH 16/82] =?UTF-8?q?SftpPath=E4=BB=85=E4=BE=9B=E5=86=85?= =?UTF-8?q?=E9=83=A8=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java index edc1409..cad1294 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/sftp/SftpPath.java @@ -17,7 +17,7 @@ import com.gitee.qdbp.tools.utils.StringTools; * @version 20230311 * @since 5.5.10 */ -public class SftpPath extends File implements PathInfo, Serializable { +class SftpPath extends File implements PathInfo, Serializable { private static final long serialVersionUID = 5852748641005853109L; -- Gitee From a0740efedb7d68822274a82cb31a26f6063cfcab Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 27 Mar 2023 20:46:29 +0800 Subject: [PATCH 17/82] =?UTF-8?q?isJsonObjectString()=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/VerifyTools.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java index 92e5964..050b04e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java @@ -267,22 +267,37 @@ public class VerifyTools { /** 是不是JsonObject字符串 **/ public static boolean isJsonObjectString(String value) { - return checkJsonString(value, '{', '}'); + return checkJsonObjectString(value); } /** 是不是JsonObject字符串 **/ public static boolean isJsonObjectString(Object value) { - return value instanceof String && checkJsonString((String) value, '{', '}'); + return value instanceof String && checkJsonObjectString((String) value); + } + + // 以{开头, 以}结尾, 且中间有冒号 + private static boolean checkJsonObjectString(String string) { + boolean passed = checkJsonString(string, '{', '}'); + if (!passed) { + return false; + } else { + String content = StringTools.removeLeftRight(string, 1, 1).trim(); + return content.length() == 0 || content.indexOf(':') > 0; + } } /** 是不是JsonArray字符串 **/ public static boolean isJsonArrayString(String value) { - return checkJsonString(value, '[', ']'); + return checkJsonArrayString(value); } /** 是不是JsonArray字符串 **/ public static boolean isJsonArrayString(Object value) { - return value instanceof String && checkJsonString((String) value, '[', ']'); + return value instanceof String && checkJsonArrayString((String) value); + } + + private static boolean checkJsonArrayString(String string) { + return checkJsonString(string, '[', ']'); } private static boolean checkJsonString(String value, char first, char last) { -- Gitee From 6f088aeec1629ae8c942d6c559120d9e35859d20 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 27 Mar 2023 20:46:44 +0800 Subject: [PATCH 18/82] VerifyToolsTest --- .../qdbp/tools/utils/VerifyToolsTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tools/src/test/java/com/gitee/qdbp/tools/utils/VerifyToolsTest.java diff --git a/tools/src/test/java/com/gitee/qdbp/tools/utils/VerifyToolsTest.java b/tools/src/test/java/com/gitee/qdbp/tools/utils/VerifyToolsTest.java new file mode 100644 index 0000000..0510c5a --- /dev/null +++ b/tools/src/test/java/com/gitee/qdbp/tools/utils/VerifyToolsTest.java @@ -0,0 +1,58 @@ +package com.gitee.qdbp.tools.utils; + +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * VerifyToolsTest + * + * @author zhaohuihua + * @version 20230327 + */ +@Test +public class VerifyToolsTest { + + @Test + public void testJsonObjectString() { + { + boolean result = VerifyTools.isJsonObjectString("{}"); + Assert.assertTrue(result); + } + { + boolean result = VerifyTools.isJsonObjectString("{ }"); + Assert.assertTrue(result); + } + { + boolean result = VerifyTools.isJsonObjectString("{a:'11'}"); + Assert.assertTrue(result); + } + { + boolean result = VerifyTools.isJsonObjectString("{aaa}"); + Assert.assertFalse(result); + } + } + + @Test + public void testJsonArrayString() { + { + boolean result = VerifyTools.isJsonArrayString("{}"); + Assert.assertFalse(result); + } + { + boolean result = VerifyTools.isJsonArrayString("[]"); + Assert.assertTrue(result); + } + { + boolean result = VerifyTools.isJsonArrayString("[ ]"); + Assert.assertTrue(result); + } + { + boolean result = VerifyTools.isJsonArrayString("[1,2,3]"); + Assert.assertTrue(result); + } + { + boolean result = VerifyTools.isJsonArrayString("[ {a:'11'} ]"); + Assert.assertTrue(result); + } + } +} -- Gitee From 4ade99064b0ea0c34a3e569059d0aa73a80bb246 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 2 Apr 2023 21:47:05 +0800 Subject: [PATCH 19/82] FormatTools --- .../gitee/qdbp/tools/utils/VerifyTools.java | 32 ++- .../gitee/qdbp/tools/utils/FormatTools.java | 182 ++++++++++++++++++ 2 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java index 050b04e..3baab94 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java @@ -277,7 +277,7 @@ public class VerifyTools { // 以{开头, 以}结尾, 且中间有冒号 private static boolean checkJsonObjectString(String string) { - boolean passed = checkJsonString(string, '{', '}'); + boolean passed = checkStringFeature(string, '{', '}'); if (!passed) { return false; } else { @@ -297,10 +297,36 @@ public class VerifyTools { } private static boolean checkJsonArrayString(String string) { - return checkJsonString(string, '[', ']'); + return checkStringFeature(string, '[', ']'); } - private static boolean checkJsonString(String value, char first, char last) { + /** + * 是不是XML字符串 (只是简单判断以<开头且以>结尾) + * + * @param value 判断目标 + * @return 判断结果 + * @since 5.5.13 + */ + public static boolean isXmlString(String value) { + return checkXmlString(value); + } + + /** + * 是不是XML字符串 (只是简单判断以<开头且以>结尾) + * + * @param value 判断目标 + * @return 判断结果 + * @since 5.5.13 + */ + public static boolean isXmlString(Object value) { + return value instanceof String && checkXmlString((String) value); + } + + private static boolean checkXmlString(String string) { + return checkStringFeature(string, '<', '>'); + } + + private static boolean checkStringFeature(String value, char first, char last) { if (value == null) { return false; } diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java b/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java new file mode 100644 index 0000000..e4fc417 --- /dev/null +++ b/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java @@ -0,0 +1,182 @@ +package com.gitee.qdbp.tools.utils; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import com.gitee.qdbp.json.JsonFeature; +import com.gitee.qdbp.json.JsonFeature.Serialization; + +/** + * 格式化工具 + * + * @author zhaohuihua + * @version 20230330 + * @since 5.5.13 + */ +public class FormatTools { + + /** 静态工具类私有构造方法 **/ + private FormatTools() { + } + + /** 格式化字符串, 支持json和xml的处理 */ + public static String formatString(String string) { + if (VerifyTools.isXmlString(string)) { + return FormatTools.formatXml(string); + } else if (VerifyTools.isJsonObjectString(string)) { + Object object = JsonTools.parseAsMap(string); + return formatJson(object); + } else if (VerifyTools.isJsonArrayString(string)) { + Object object = JsonTools.parseAsMaps(string); + return formatJson(object); + } else { + return string; + } + } + + /** + * 格式化Json字符串 + * + * @param json 源字符串 + * @return 格式化后的字符串 + */ + public static String formatJson(String json) { + if (VerifyTools.isBlank(json)) { + return json; + } + try { + if (VerifyTools.isJsonObjectString(json)) { + Object object = JsonTools.parseAsMap(json); + return formatJson(object); + } else if (VerifyTools.isJsonArrayString(json)) { + Object object = JsonTools.parseAsMaps(json); + return formatJson(object); + } else { + return json; + } + } catch (Exception ignore) { + return json; + } + } + + /** + * 格式化Json字符串 + * + * @param object 源对象 + * @return 格式化后的字符串 + */ + public static String formatJson(Object object) { + Serialization serialization = JsonFeature.serialization() + .setQuoteFieldNames(false) + .setPrettyFormat(true) + .lockToUnmodifiable(); + return JsonTools.toJsonString(object, serialization); + } + + /** + * 格式化XML字符串 + * + * @param xml 源字符串 + * @return 格式化后的字符串 + */ + public static String formatXml(String xml) { + if (VerifyTools.isBlank(xml) || !VerifyTools.isXmlString(xml)) { + return xml; + } + Reader reader = new StringReader(xml); + try (StringWriter writer = new StringWriter()) { + formatXml(reader, writer); + return writer.getBuffer().toString(); + } catch (IOException e) { + return xml; + } + } + + public static void formatXml(Reader reader, Writer writer) throws IOException { + int indent = 0; + // abcd abcd是xxx标签中间的内容, 这里不能换行 + boolean ignoreIndent = false; + boolean lastIsSpace = false; + StringBuilder buffer = new StringBuilder(); + int index; + while ((index = reader.read()) >= 0) { + char c = (char) index; + if (c == '\r' || c == '\n') { + continue; + } + int bufSize = buffer.length(); + char lastChar = bufSize == 0 ? '\0' : buffer.charAt(bufSize - 1); + if ((lastChar == '<' || lastChar == '>') && (c == ' ' || c == '\t' || c == '\f')) { + continue; + } + if (lastChar == '<') { + if (c == '/') { + // 减少缩进 + indent--; + buffer.setLength(bufSize - 1); // 去掉最后的< + if (!ignoreIndent) { + appendIndent(buffer, indent); // 添加缩进 + } + buffer.append('<').append(c); + } else if (c == '?') { + // + buffer.append(c); + } else { + // 增加缩进 + buffer.setLength(bufSize - 1); // 去掉最后的< + appendIndent(buffer, indent); // 添加缩进 + buffer.append('<').append(c); + indent++; + } + continue; + } + if (c == ' ' || c == '\t' || c == '\f') { + if (!lastIsSpace) { + buffer.append(' '); + } + lastIsSpace = true; + continue; + } + lastIsSpace = false; + if (c == '<') { + if (lastChar == '>') { + ignoreIndent = false; + // 处理掉之前的内容 + buffer.append('\n'); + writer.write(buffer.toString()); + buffer.setLength(0); + } else { + ignoreIndent = true; + } + // 重新开始 + buffer.append(c); + // 下一步要看下一字符是什么 + continue; + } + if (c == '>') { + buffer.append(c); + if (lastChar == '/') { + indent--; + } + } else { + buffer.append(c); + } + } + if (buffer.length() > 0) { + writer.write(buffer.toString()); + buffer.setLength(0); + } + writer.flush(); + } + + private static void appendIndent(StringBuilder buffer, int indent) { + if (indent <= 0) { + return; + } + for (int i = 0; i < indent; i++) { + buffer.append(" "); + } + } +} -- Gitee From ecdb2fd2d9127b1b8af4d9456b89775a98b5d0bb Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 2 Apr 2023 21:49:52 +0800 Subject: [PATCH 20/82] 5.5.13 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e354a10..57ca711 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.12 + 5.5.13 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.12 + 5.5.13 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 7ec4ef6..67cf352 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.12 + 5.5.13 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 16296ad..d5aee24 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.12 + 5.5.13 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.12 + 5.5.13 diff --git a/test/pom.xml b/test/pom.xml index e09c511..c2bcea4 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.12 + 5.5.13 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 97e668c..03bc3bc 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.12 + 5.5.13 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index b901ebc..f12939a 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.12 + 5.5.13 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 24a9865..6216551 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.12 + 5.5.13 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 04b6278..e3012a4 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.12 + 5.5.13 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 22e4b55..471f04e 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.12 + 5.5.13 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index c51ae0b..afd5117 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.12 + 5.5.13 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 42a5fa9dd50df5b6dd962699116ba35cb0a69a50 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 2 Apr 2023 21:50:42 +0800 Subject: [PATCH 21/82] FormatTools --- .../com/gitee/qdbp/tools/utils/FormatTools.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java b/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java index e4fc417..dcef547 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java @@ -21,21 +21,6 @@ public class FormatTools { private FormatTools() { } - /** 格式化字符串, 支持json和xml的处理 */ - public static String formatString(String string) { - if (VerifyTools.isXmlString(string)) { - return FormatTools.formatXml(string); - } else if (VerifyTools.isJsonObjectString(string)) { - Object object = JsonTools.parseAsMap(string); - return formatJson(object); - } else if (VerifyTools.isJsonArrayString(string)) { - Object object = JsonTools.parseAsMaps(string); - return formatJson(object); - } else { - return string; - } - } - /** * 格式化Json字符串 * -- Gitee From 966ca62a94c61dfc69a3ef338d12fa1b766cddbe Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 2 Apr 2023 21:56:58 +0800 Subject: [PATCH 22/82] =?UTF-8?q?FormatTools=E7=A7=BB=E8=87=B3qdbp-able?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/FormatTools.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) rename {tools => able}/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java (85%) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java similarity index 85% rename from tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java rename to able/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java index dcef547..294ab95 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/FormatTools.java @@ -21,11 +21,32 @@ public class FormatTools { private FormatTools() { } + /** + * 格式化字符串, 支持json和xml的处理 + * @param string 源字符串 + * @return 格式化后的字符串 + * @since 5.5.14 + */ + public static String formatString(String string) { + if (VerifyTools.isXmlString(string)) { + return FormatTools.formatXml(string); + } else if (VerifyTools.isJsonObjectString(string)) { + Object object = JsonTools.parseAsMap(string); + return formatJson(object); + } else if (VerifyTools.isJsonArrayString(string)) { + Object object = JsonTools.parseAsMaps(string); + return formatJson(object); + } else { + return string; + } + } + /** * 格式化Json字符串 * * @param json 源字符串 * @return 格式化后的字符串 + * @since 5.5.13 */ public static String formatJson(String json) { if (VerifyTools.isBlank(json)) { @@ -51,6 +72,7 @@ public class FormatTools { * * @param object 源对象 * @return 格式化后的字符串 + * @since 5.5.13 */ public static String formatJson(Object object) { Serialization serialization = JsonFeature.serialization() @@ -65,6 +87,7 @@ public class FormatTools { * * @param xml 源字符串 * @return 格式化后的字符串 + * @since 5.5.13 */ public static String formatXml(String xml) { if (VerifyTools.isBlank(xml) || !VerifyTools.isXmlString(xml)) { @@ -79,6 +102,13 @@ public class FormatTools { } } + /** + * 格式化XML字符串 + * + * @param reader 输入 + * @param writer 输出 + * @since 5.5.13 + */ public static void formatXml(Reader reader, Writer writer) throws IOException { int indent = 0; // abcd abcd是xxx标签中间的内容, 这里不能换行 -- Gitee From 2d6fff195b0254b86e6dbba71b18428e1d7b937e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 2 Apr 2023 21:59:40 +0800 Subject: [PATCH 23/82] qdbp-5.5.14 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 57ca711..ebd181e 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.13 + 5.5.14 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.13 + 5.5.14 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 67cf352..2cd5ffb 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.13 + 5.5.14 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index d5aee24..f64cfa4 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.13 + 5.5.14 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.13 + 5.5.14 diff --git a/test/pom.xml b/test/pom.xml index c2bcea4..8b0b23f 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.13 + 5.5.14 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 03bc3bc..4a54e01 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.13 + 5.5.14 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index f12939a..59fe835 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.13 + 5.5.14 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 6216551..e629a06 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.13 + 5.5.14 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index e3012a4..c860357 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.13 + 5.5.14 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 471f04e..8a94ca3 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.13 + 5.5.14 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index afd5117..ea352b1 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.13 + 5.5.14 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From cd7755f5eafc1dcd4213f0ead4b5a3a79fa1685d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 21 May 2023 11:15:59 +0800 Subject: [PATCH 24/82] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java index bf901c5..a6f2f0d 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java @@ -40,14 +40,17 @@ public abstract class JsonServiceForBase implements JsonService { public String toJsonString(Object object) { return toJsonString(object, serializationFeature); } + @Override public Map parseAsMap(String jsonString) { return parseAsMap(jsonString, deserializationFeature); } + @Override public List parseAsObjects(String jsonString, Class clazz) { return parseAsObjects(jsonString, clazz, deserializationFeature); } + @Override public List> parseAsMaps(String jsonString) { return parseAsMaps(jsonString, deserializationFeature); -- Gitee From 5e75609ce2780e361e7e634e7df93526b62b4871 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 21 May 2023 11:17:00 +0800 Subject: [PATCH 25/82] =?UTF-8?q?=E5=8F=96=E5=80=BC=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E9=94=99=E8=AF=AFBUG=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java index d38be4f..9b3f925 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java @@ -1048,7 +1048,7 @@ public abstract class PathTools { } if (!endsWithSeparator(buffer) && !startsWithSeparator(path)) { buffer.append(SLASH).append(path); - } else if (endsWithSeparator(folder) && startsWithSeparator(path)) { + } else if (endsWithSeparator(buffer) && startsWithSeparator(path)) { buffer.append(path.substring(1)); } else { buffer.append(path); -- Gitee From abc7a5d7459b7a7449ef634dad8bc7886006d7ba Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 21 May 2023 11:57:06 +0800 Subject: [PATCH 26/82] JsonTools.toSimpleString --- .../main/java/com/gitee/qdbp/tools/utils/JsonTools.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java index 69c905c..7c9de2a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java @@ -138,7 +138,13 @@ public class JsonTools extends JsonMaps { private static final JsonFeature.Serialization UNQUOTE_FIELD_NAME_FEATURE = JsonFeature.serialization().setQuoteFieldNames(false).lockToUnmodifiable(); - /** 转换为日志字符串, json的key不会有引号, 可以稍微简化一下结构 **/ + /** 转换为简化的字符串, json的key不会有引号, 可以稍微简化一下结构 **/ + // 目前与toLogString相同, 但以后toLogString有可能会更加简化 (因为log不用考虑反序列化) + public static String toSimpleString(Object object) { + return findDefaultJsonService().toJsonString(object, UNQUOTE_FIELD_NAME_FEATURE); + } + + /** 转换为日志字符串, 有可能无法反序列化, json的key不会有引号, 可以稍微简化一下结构 **/ public static String toLogString(Object object) { return findDefaultJsonService().toJsonString(object, UNQUOTE_FIELD_NAME_FEATURE); } -- Gitee From 446310482463fa5e36014b1dd0148562da7da3d7 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 21 May 2023 23:05:16 +0800 Subject: [PATCH 27/82] =?UTF-8?q?Json=E7=AE=80=E5=8C=96=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/tools/utils/JsonTools.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java index 7c9de2a..ca02ac1 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java @@ -135,18 +135,21 @@ public class JsonTools extends JsonMaps { return findDefaultJsonService().toJsonString(object, feature); } - private static final JsonFeature.Serialization UNQUOTE_FIELD_NAME_FEATURE = - JsonFeature.serialization().setQuoteFieldNames(false).lockToUnmodifiable(); + private static final JsonFeature.Serialization SIMPLIFY_FEATURE = JsonFeature.serialization() + .setQuoteFieldNames(false) + .setWriteFieldNullValue(false) + .setWriteMapNullValue(false) + .lockToUnmodifiable(); /** 转换为简化的字符串, json的key不会有引号, 可以稍微简化一下结构 **/ // 目前与toLogString相同, 但以后toLogString有可能会更加简化 (因为log不用考虑反序列化) public static String toSimpleString(Object object) { - return findDefaultJsonService().toJsonString(object, UNQUOTE_FIELD_NAME_FEATURE); + return findDefaultJsonService().toJsonString(object, SIMPLIFY_FEATURE); } /** 转换为日志字符串, 有可能无法反序列化, json的key不会有引号, 可以稍微简化一下结构 **/ public static String toLogString(Object object) { - return findDefaultJsonService().toJsonString(object, UNQUOTE_FIELD_NAME_FEATURE); + return findDefaultJsonService().toJsonString(object, SIMPLIFY_FEATURE); } /** 解析Json字符串对象 **/ -- Gitee From f3bb55a15551360985dcc8b221681ee6dea60b35 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 21 May 2023 23:10:03 +0800 Subject: [PATCH 28/82] 5.5.15 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index ebd181e..bbd0d0a 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.14 + 5.5.15 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.14 + 5.5.15 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 2cd5ffb..c80e177 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.14 + 5.5.15 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index f64cfa4..6ef795c 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.14 + 5.5.15 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.14 + 5.5.15 diff --git a/test/pom.xml b/test/pom.xml index 8b0b23f..5941e7e 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.14 + 5.5.15 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 4a54e01..7ca5221 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.14 + 5.5.15 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 59fe835..8aa4fcc 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.14 + 5.5.15 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index e629a06..55df0db 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.14 + 5.5.15 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index c860357..3b7215f 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.14 + 5.5.15 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 8a94ca3..ecebe93 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.14 + 5.5.15 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index ea352b1..057e332 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.14 + 5.5.15 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 538c833d8457dd55a0c04df4144311acaa69a1cc Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 25 May 2023 20:54:49 +0800 Subject: [PATCH 29/82] AutoBeanDeserializer --- .../qdbp/json/JsonServiceForFastjson.java | 20 +- .../json/fastjson/AutoBeanDeserializer.java | 349 ++++++++++++++++++ .../json/fastjson/MapFillToBeanHandler.java | 43 +++ 3 files changed, 393 insertions(+), 19 deletions(-) create mode 100644 json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java create mode 100644 json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java index 0473bf0..a178ed5 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java @@ -1,7 +1,6 @@ package com.gitee.qdbp.json; import java.lang.reflect.Array; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -20,7 +19,6 @@ import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.JSONLexer; import com.alibaba.fastjson.parser.JSONToken; import com.alibaba.fastjson.parser.ParserConfig; -import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; import com.alibaba.fastjson.serializer.DoubleSerializer; import com.alibaba.fastjson.serializer.JSONSerializable; import com.alibaba.fastjson.serializer.JSONSerializer; @@ -33,6 +31,7 @@ import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer; import com.alibaba.fastjson.util.TypeUtils; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.json.fastjson.MapFillToBeanHandler; import com.gitee.qdbp.tools.utils.MapTools; import com.gitee.qdbp.tools.utils.ReflectTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -551,21 +550,4 @@ public class JsonServiceForFastjson extends JsonServiceForBase { supportNonStringKeyAsString = existField(Feature.class, "NonStringKeyAsString"); serializerHasGetJsonType = existField(JavaBeanSerializer.class, "getJSONType"); } - - private static class MapFillToBeanHandler extends JavaBeanDeserializer { - private final Object bean; - - public MapFillToBeanHandler(Object bean, ParserConfig config) { - super(config, bean.getClass()); - this.bean = bean; - } - - @Override - public Object createInstance(DefaultJSONParser parser, Type type) { - // 调用此方法时: JavaBeanDeserializer.createInstance(Map map, ParserConfig config) - // 会调用本方法: createInstance(DefaultJSONParser parser, Type type) - // 这里直接返回构造方法中传入的bean, 达到将map赋值给已知对象的目的 - return bean; - } - } } diff --git a/json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java b/json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java new file mode 100644 index 0000000..c0c8833 --- /dev/null +++ b/json/src/main/java/com/gitee/qdbp/json/fastjson/AutoBeanDeserializer.java @@ -0,0 +1,349 @@ +package com.gitee.qdbp.json.fastjson; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONValidator; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.parser.DefaultJSONParser; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.parser.deserializer.FieldDeserializer; +import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; +import com.alibaba.fastjson.parser.deserializer.Jdk8DateCodec; +import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; +import com.alibaba.fastjson.util.FieldInfo; +import com.alibaba.fastjson.util.JavaBeanInfo; +import com.alibaba.fastjson.util.TypeUtils; +import com.gitee.qdbp.tools.utils.MapTools; + +/** + * 反序列化处理类优化, 解决自定义的JavaBeanDeserializer在map转对象时不生效的问题 (V1.2.83)
+ * 重写JavaBeanDeserializer.createInstance(Map, ParserConfig), 增加了deserializeFieldValue处理逻辑 + * + * @author zhaohuihua + * @version 20230521 + */ +public class AutoBeanDeserializer extends JavaBeanDeserializer { + + public AutoBeanDeserializer(ParserConfig config, Class clazz) { + super(config, clazz, clazz); + } + + public AutoBeanDeserializer(ParserConfig config, Class clazz, Type type){ + super(config, clazz, type); + } + + public AutoBeanDeserializer(ParserConfig config, JavaBeanInfo beanInfo){ + super(config, beanInfo); + } + + protected static boolean deserializeFieldValue(Object object, Object fieldValue, FieldDeserializer fieldDeserializer, + ParserConfig config) throws IllegalAccessException, InvocationTargetException { + // 增加判断, 如果值是map, 调用createInstance(Map map, ParserConfig config) + // 从JavaBeanDeserializer.createInstance(Map, ParserConfig), 增加了这一段逻辑 + // 这样自定义的JavaBeanDeserializer在map转对象时才能生效; 如果不加, map会转换为字符串再调DefaultJSONParser处理, 就不会生效 + FieldInfo fieldInfo = fieldDeserializer.fieldInfo; + Field field = fieldDeserializer.fieldInfo.field; + Class fieldType = field.getType(); + if (fieldValue instanceof Map) { + ObjectDeserializer deserializer = config.getDeserializer(fieldInfo); + if (deserializer instanceof JavaBeanDeserializer) { + JavaBeanDeserializer fieldBeanDeserializer = (JavaBeanDeserializer) deserializer; + Map valueMaps = MapTools.toJsonMap((Map) fieldValue); + Object fieldBean = fieldBeanDeserializer.createInstance(valueMaps, config); + fieldDeserializer.setValue(object, fieldBean); + return true; + } + } else if (fieldValue instanceof Collection && Collection.class.isAssignableFrom(fieldType)) { + Collection values = (Collection) fieldValue; + boolean isAllMapItems = true; + for (Object o : values) { + if (o != null && !(o instanceof Map)) { + isAllMapItems = false; + break; + } + } + if (isAllMapItems) { + Class ctualClass = getFirstActualClass(field); + ObjectDeserializer deserializer = config.getDeserializer(ctualClass); + if (deserializer instanceof JavaBeanDeserializer) { + JavaBeanDeserializer fieldBeanDeserializer = (JavaBeanDeserializer) deserializer; + List list = new ArrayList<>(); + for (Object o : values) { + if (o == null) { + list.add(null); + } else { + Map valueMaps = MapTools.toJsonMap((Map) o); + Object fieldBean = fieldBeanDeserializer.createInstance(valueMaps, config); + list.add(fieldBean); + } + } + Object fieldBean = TypeUtils.cast(list, fieldType, config); + fieldDeserializer.setValue(object, fieldBean); + return true; + } + } + } + return false; + } + + private static Class getFirstActualClass(Field field) { + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) genericType; + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + if (actualTypeArguments.length == 1) { + return (Class) actualTypeArguments[0]; + } + } + return null; + } + + @Override + public Object createInstance(Map map, ParserConfig config) + throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Object object = null; + + if (beanInfo.creatorConstructor == null && beanInfo.factoryMethod == null) { + object = createInstance(null, clazz); + + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + + FieldDeserializer fieldDeser = smartMatch(key); + if (fieldDeser == null) { + continue; + } + + final FieldInfo fieldInfo = fieldDeser.fieldInfo; + Field field = fieldDeser.fieldInfo.field; + Type paramType = fieldInfo.fieldType; + + // 增加判断, 如果值是Map或List, 调用createInstance(Map map, ParserConfig config) + if (deserializeFieldValue(object, value, fieldDeser, config)) { + continue; + } + + Class fieldClass = fieldInfo.fieldClass; + JSONField fieldAnnotation = fieldInfo.getAnnotation(); + + if (fieldInfo.declaringClass != null + && ((!fieldClass.isInstance(value)) + || (fieldAnnotation != null && fieldAnnotation.deserializeUsing() != Void.class)) + ) { + String input; + if (value instanceof String && JSONValidator.from(((String) value)).validate()) { + input = (String) value; + } else { + input = JSON.toJSONString(value); + } + + DefaultJSONParser parser = new DefaultJSONParser(input); + fieldDeser.parseField(parser, object, paramType, null); + continue; + } + + if (field != null && fieldInfo.method == null) { + Class fieldType = field.getType(); + if (fieldType == boolean.class) { + if (value == Boolean.FALSE) { + field.setBoolean(object, false); + continue; + } + + if (value == Boolean.TRUE) { + field.setBoolean(object, true); + continue; + } + } else if (fieldType == int.class) { + if (value instanceof Number) { + field.setInt(object, ((Number) value).intValue()); + continue; + } + } else if (fieldType == long.class) { + if (value instanceof Number) { + field.setLong(object, ((Number) value).longValue()); + continue; + } + } else if (fieldType == float.class) { + if (value instanceof Number) { + field.setFloat(object, ((Number) value).floatValue()); + continue; + } else if (value instanceof String) { + String strVal = (String) value; + float floatValue; + if (strVal.length() <= 10) { + floatValue = TypeUtils.parseFloat(strVal); + } else { + floatValue = Float.parseFloat(strVal); + } + + field.setFloat(object, floatValue); + continue; + } + } else if (fieldType == double.class) { + if (value instanceof Number) { + field.setDouble(object, ((Number) value).doubleValue()); + continue; + } else if (value instanceof String) { + String strVal = (String) value; + double doubleValue; + if (strVal.length() <= 10) { + doubleValue = TypeUtils.parseDouble(strVal); + } else { + doubleValue = Double.parseDouble(strVal); + } + + field.setDouble(object, doubleValue); + continue; + } + } else if (value != null && paramType == value.getClass()) { + field.set(object, value); + continue; + } + } + + String format = fieldInfo.format; + if (format != null && paramType == Date.class) { + value = TypeUtils.castToDate(value, format); + } else if (format != null && (paramType instanceof Class) + && (((Class) paramType).getName().equals("java.time.LocalDateTime"))) { + value = Jdk8DateCodec.castToLocalDateTime(value, format); + } else { + if (paramType instanceof ParameterizedType) { + value = TypeUtils.cast(value, (ParameterizedType) paramType, config); + } else { + value = TypeUtils.cast(value, paramType, config); + } + } + + fieldDeser.setValue(object, value); + } + + if (beanInfo.buildMethod != null) { + Object builtObj; + try { + builtObj = beanInfo.buildMethod.invoke(object); + } catch (Exception e) { + throw new JSONException("build object error", e); + } + + return builtObj; + } + + return object; + } + + + FieldInfo[] fieldInfoList = beanInfo.fields; + int size = fieldInfoList.length; + Object[] params = new Object[size]; + Map missFields = null; + for (int i = 0; i < size; ++i) { + FieldInfo fieldInfo = fieldInfoList[i]; + Object param = map.get(fieldInfo.name); + + if (param == null) { + Class fieldClass = fieldInfo.fieldClass; + if (fieldClass == int.class) { + param = 0; + } else if (fieldClass == long.class) { + param = 0L; + } else if (fieldClass == short.class) { + param = (short) 0; + } else if (fieldClass == byte.class) { + param = (byte) 0; + } else if (fieldClass == float.class) { + param = (float) 0; + } else if (fieldClass == double.class) { + param = (double) 0; + } else if (fieldClass == char.class) { + param = '0'; + } else if (fieldClass == boolean.class) { + param = false; + } + if (missFields == null) { + missFields = new HashMap(); + } + missFields.put(fieldInfo.name, i); + } + params[i] = param; + } + + if (missFields != null) { + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + + FieldDeserializer fieldDeser = smartMatch(key); + if (fieldDeser != null) { + Integer index = missFields.get(fieldDeser.fieldInfo.name); + if (index != null) { + params[index] = value; + } + } + } + } + + if (beanInfo.creatorConstructor != null) { + boolean hasNull = false; + if (beanInfo.kotlin) { + for (int i = 0; i < params.length; i++) { + Object param = params[i]; + if (param == null) { + if (i < beanInfo.fields.length) { + FieldInfo fieldInfo = beanInfo.fields[i]; + if (fieldInfo.fieldClass == String.class) { + hasNull = true; + } + } + } else if (param.getClass() != beanInfo.fields[i].fieldClass){ + params[i] = TypeUtils.cast(param, beanInfo.fields[i].fieldClass, config); + } + } + } + + if (hasNull && beanInfo.kotlinDefaultConstructor != null) { + try { + object = beanInfo.kotlinDefaultConstructor.newInstance(); + + for (int i = 0; i < params.length; i++) { + final Object param = params[i]; + if (param != null && i < beanInfo.fields.length) { + FieldInfo fieldInfo = beanInfo.fields[i]; + fieldInfo.set(object, param); + } + } + } catch (Exception e) { + throw new JSONException("create instance error, " + + beanInfo.creatorConstructor.toGenericString(), e); + } + } else { + try { + object = beanInfo.creatorConstructor.newInstance(params); + } catch (Exception e) { + throw new JSONException("create instance error, " + + beanInfo.creatorConstructor.toGenericString(), e); + } + } + } else if (beanInfo.factoryMethod != null) { + try { + object = beanInfo.factoryMethod.invoke(null, params); + } catch (Exception e) { + throw new JSONException("create factory method error, " + beanInfo.factoryMethod.toString(), e); + } + } + + return object; + } +} diff --git a/json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java b/json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java new file mode 100644 index 0000000..b29d651 --- /dev/null +++ b/json/src/main/java/com/gitee/qdbp/json/fastjson/MapFillToBeanHandler.java @@ -0,0 +1,43 @@ +package com.gitee.qdbp.json.fastjson; + +import java.lang.reflect.Type; +import java.util.Map; +import com.alibaba.fastjson.parser.DefaultJSONParser; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer; + +/** + * 将Map填充至实体类的处理器 + * + * @author zhaohuihua + * @version 20211207 + */ +public class MapFillToBeanHandler extends JavaBeanDeserializer { + private final Object bean; + + private final ParserConfig config; + + public MapFillToBeanHandler(Object bean, ParserConfig config) { + super(config, bean.getClass()); + this.bean = bean; + this.config = config; + } + + @Override + public Object createInstance(DefaultJSONParser parser, Type type) { + // 调用此方法时: JavaBeanDeserializer.createInstance(Map map, ParserConfig config) + // 会调用本方法: createInstance(DefaultJSONParser parser, Type type) + // 这里直接返回构造方法中传入的bean, 达到将map赋值给已知对象的目的 + return bean; + } + + public Object createInstance(Map map) { + try { + return createInstance(map, config); + } catch (IllegalArgumentException e) { + throw e; + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } +} \ No newline at end of file -- Gitee From 61fe6ab375dfd10e23d5cae2801d528f713c870b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:23:58 +0800 Subject: [PATCH 30/82] =?UTF-8?q?test=E5=B7=A5=E7=A8=8B=E8=B7=B3=E8=BF=87?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E9=98=B6=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/pom.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/pom.xml b/test/pom.xml index 5941e7e..e0c3828 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -26,4 +26,25 @@ qdbp-json-test-jackson qdbp-tools-test-jdk7 + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + + true + + + + -- Gitee From 1fef026d7da5b3e887b2519dcbf0c8e04e8851c4 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:25:52 +0800 Subject: [PATCH 31/82] =?UTF-8?q?=E9=87=8D=E6=9E=84MapTools.each/ReflectTo?= =?UTF-8?q?ols.findDepthValues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/DepthMap.java | 1 - .../qdbp/able/model/entry/BaseEntryItem.java | 60 ++++ .../qdbp/able/model/entry/EachEntry.java | 38 +++ .../qdbp/able/model/entry/EntryItem.java | 35 +++ .../qdbp/able/model/entry/ListEachEntry.java | 54 ++++ .../qdbp/able/model/entry/ListEntryItem.java | 44 +++ .../qdbp/able/model/entry/MapEachEntry.java | 54 ++++ .../qdbp/able/model/entry/MapEntryItem.java | 33 ++ .../able/model/entry/ObjectEntryItem.java | 38 +++ .../able/model/entry/ObjectsEntryItem.java | 33 ++ .../able/model/entry/ReadonlyEntryItem.java | 33 ++ .../gitee/qdbp/able/result/ResultCode.java | 2 +- .../gitee/qdbp/tools/parse/StringParser.java | 19 +- .../com/gitee/qdbp/tools/utils/MapTools.java | 279 +++++------------ .../gitee/qdbp/tools/utils/ReflectTools.java | 294 ++++++++++-------- 15 files changed, 688 insertions(+), 329 deletions(-) create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java b/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java index 42f9509..1682db5 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/DepthMap.java @@ -50,7 +50,6 @@ public class DepthMap implements Copyable, Serializable { this.map = map; } - @SuppressWarnings("unchecked") public DepthMap put(String key, Object value) { MapTools.putValue(map, key, value); return this; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java new file mode 100644 index 0000000..603c4f8 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java @@ -0,0 +1,60 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.regex.Pattern; + +/** + * 基础字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +abstract class BaseEntryItem implements EntryItem, EntryItem.Resetable { + + private static final Pattern CLEAR_NUMBER_INDEX = Pattern.compile("(^\\[[+-]?\\d+]\\.|\\[[+-]?\\d+])"); + + protected String key; + protected String name; + protected Object value; + protected boolean handled; + + protected BaseEntryItem init(String key, String name, Object value) { + this.key = key; + this.name = name; + this.value = value; + this.handled = false; + return this; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getFields() { + return key == null ? null : CLEAR_NUMBER_INDEX.matcher(key).replaceAll(""); + } + + @Override + public String getName() { + return name; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public void setValue(Object value) { + this.resetValue(value); + this.handled = true; + } + + @Override + public boolean handled() { + return this.handled; + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java new file mode 100644 index 0000000..9948c8a --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/EachEntry.java @@ -0,0 +1,38 @@ +package com.gitee.qdbp.able.model.entry; + +/** + * 用于遍历的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public interface EachEntry extends EntryItem { + + /** 跳过所有, 立即停止 **/ + void skipAll(); + + /** 跳过后续节点 **/ + void skipAfter(); + + /** 跳过进入容器 (只在值为容器时有效) **/ + void skipEnter(); + + /** + * 可中断的遍历字段项变量 + * + * @author zhaohuihua + * @version 20230527 + */ + interface Breakable { + + /** 是否跳过所有, 立即停止 **/ + boolean isSkipAll(); + + /** 是否跳过后续节点 **/ + boolean isSkipAfter(); + + /** 是否跳过进入容器 (只在值为容器时有效) **/ + boolean isSkipEnter(); + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java new file mode 100644 index 0000000..ae742bb --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java @@ -0,0 +1,35 @@ +package com.gitee.qdbp.able.model.entry; + +/** + * 字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public interface EntryItem { + + /** KEY, 如 xxx.yyy[0].zzz[1] **/ + String getKey(); + + /** 字段路径, 如 xxx.yyy.zzz **/ + String getFields(); + + /** 名称, path的最后一段, 如 [1] **/ + String getName(); + + /** 值 **/ + Object getValue(); + + /** 修改值 **/ + void setValue(Object value); + + /** 是否已处理 (是否调用了setValue方法, 用于遍历后判断有没有被处理过) **/ + boolean handled(); + + interface Resetable { + + /** 修改值, 但不改变handled **/ + void resetValue(Object value); + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java new file mode 100644 index 0000000..90ed1fd --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java @@ -0,0 +1,54 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Collection; + +/** + * 父容器为List的遍历字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ListEachEntry extends ListEntryItem implements EachEntry, EachEntry.Breakable { + + private boolean skipAll; + private boolean skipAfter; + private boolean skipEnter; + + public ListEachEntry(Collection list) { + super(list); + } + + @Override + public ListEachEntry init(String path, String name, int index, Object value) { + super.init(path, name, index, value); + this.skipAll = false; + this.skipAfter = false; + this.skipEnter = false; + return this; + } + + public void skipAll() { + this.skipAll = true; + } + + public void skipAfter() { + this.skipAfter = true; + } + + public void skipEnter() { + this.skipEnter = true; + } + + public boolean isSkipAll() { + return skipAll; + } + + public boolean isSkipAfter() { + return skipAfter; + } + + public boolean isSkipEnter() { + return skipEnter; + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java new file mode 100644 index 0000000..64f9cd8 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java @@ -0,0 +1,44 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Collection; +import java.util.List; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 父容器为List的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ListEntryItem extends BaseEntryItem { + + private final Collection list; + private int index; + + public ListEntryItem(Collection list) { + this.list = list; + } + + public ListEntryItem init(String path, String name, int index, Object value) { + super.init(path, name, value); + this.index = index; + return this; + } + + @Override + public void resetValue(Object value) { + if (this.list instanceof List) { + int i = this.index >= 0 ? this.index : this.list.size() + this.index; + @SuppressWarnings("unchecked") + List objects = (List) this.list; + objects.set(i, value); + this.value = value; + } else { + throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) + .setDetails("Cannot set value, collection real type is " + list.getClass() + ", --> " + key); + } + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java new file mode 100644 index 0000000..8857ae9 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java @@ -0,0 +1,54 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Map; + +/** + * 父容器为Map的遍历字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class MapEachEntry extends MapEntryItem implements EachEntry, EachEntry.Breakable { + + private boolean skipAll; + private boolean skipAfter; + private boolean skipEnter; + + public MapEachEntry(Map map) { + super(map); + } + + @Override + public MapEachEntry init(String key, String name, Object value) { + super.init(key, name, value); + this.skipAll = false; + this.skipAfter = false; + this.skipEnter = false; + return this; + } + + public void skipAll() { + this.skipAll = true; + } + + public void skipAfter() { + this.skipAfter = true; + } + + public void skipEnter() { + this.skipEnter = true; + } + + public boolean isSkipAll() { + return skipAll; + } + + public boolean isSkipAfter() { + return skipAfter; + } + + public boolean isSkipEnter() { + return skipEnter; + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java new file mode 100644 index 0000000..05df397 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java @@ -0,0 +1,33 @@ +package com.gitee.qdbp.able.model.entry; + +import java.util.Map; + +/** + * 父容器为Map的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class MapEntryItem extends BaseEntryItem { + + private final Map map; + + public MapEntryItem(Map map) { + this.map = map; + } + + public MapEntryItem init(String key, String name, Object value) { + super.init(key, name, value); + return this; + } + + @Override + public void resetValue(Object value) { + @SuppressWarnings("unchecked") + Map map = (Map) this.map; + map.put(this.name, value); + this.value = value; + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java new file mode 100644 index 0000000..f495dee --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java @@ -0,0 +1,38 @@ +package com.gitee.qdbp.able.model.entry; + +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.utils.ReflectTools; + +/** + * 父容器为Object的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ObjectEntryItem extends BaseEntryItem { + + private final Object object; + + public ObjectEntryItem(Object object) { + this.object = object; + } + + public ObjectEntryItem init(String key, String name, Object value) { + super.init(key, name, value); + return this; + } + + @Override + public void resetValue(Object value) { + if (object != null) { + ReflectTools.setFieldValue(object, name, value); + this.value = value; + } else { + throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) + .setDetails("Cannot set field value for null, --> " + key); + } + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java new file mode 100644 index 0000000..32fe937 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java @@ -0,0 +1,33 @@ +package com.gitee.qdbp.able.model.entry; + +import java.lang.reflect.Array; + +/** + * 父容器为Object[]的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ObjectsEntryItem extends BaseEntryItem { + + private final Object object; + private int index; + + public ObjectsEntryItem(Object object) { + this.object = object; + } + + public ObjectsEntryItem init(String path, String name, int index, Object value) { + super.init(path, name, value); + this.index = index; + return this; + } + + @Override + public void resetValue(Object value) { + int i = index >= 0 ? index : Array.getLength(object) + index; + Array.set(object, i, value); + this.value = value; + } +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java new file mode 100644 index 0000000..232e158 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java @@ -0,0 +1,33 @@ +package com.gitee.qdbp.able.model.entry; + +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 父容器不可修改的字段项变量 + * + * @author zhaohuihua + * @version 20230527 + * @since 5.6.0 + */ +public class ReadonlyEntryItem extends BaseEntryItem { + + private final Object object; + + public ReadonlyEntryItem(Object object) { + this.object = object; + } + + public ReadonlyEntryItem init(String key, String name, Object value) { + super.init(key, name, value); + return this; + } + + @Override + public void resetValue(Object value) { + String className = (object == null ? null : object.getClass().getSimpleName()); + throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) + .setDetails("Cannot set field value for " + className + ", --> " + key); + } + +} \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java index a1bf697..d9e6dbb 100644 --- a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java @@ -70,7 +70,7 @@ public enum ResultCode implements IResultMessage { /** 系统配置错误 **/ SYSTEM_CONFIG_ERROR, - /** 暂不支持该操作 **/ + /** 不支持该操作 **/ UNSUPPORTED_OPERATION; /** {@inheritDoc} **/ diff --git a/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java b/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java index a51f137..d260aa9 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java +++ b/able/src/main/java/com/gitee/qdbp/tools/parse/StringParser.java @@ -1,6 +1,8 @@ package com.gitee.qdbp.tools.parse; +import java.util.Iterator; import java.util.List; +import com.gitee.qdbp.tools.utils.VerifyTools; /** * 字符串解析 @@ -73,7 +75,22 @@ public class StringParser { * @return 字段名数组 */ public static List splitsFields(String fields) { - return SplitFields.split(fields); + List fieldNames = SplitFields.split(fields); + // 清除空值和this + clearFieldNames(fieldNames); + return fieldNames; + } + + @SuppressWarnings("all") + private static void clearFieldNames(List fieldNames) { + // 清除空值和this + Iterator iterator = fieldNames.iterator(); + while (iterator.hasNext()) { + String next = iterator.next(); + if (VerifyTools.isBlank(next) || next.equals("this")) { + iterator.remove(); + } + } } /** diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index 7124c3e..2a9d216 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -14,9 +14,12 @@ import java.util.Set; import com.gitee.qdbp.able.beans.DepthMap; import com.gitee.qdbp.able.beans.LinkedListMap; import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.model.entry.EachEntry; +import com.gitee.qdbp.able.model.entry.EntryItem; +import com.gitee.qdbp.able.model.entry.ListEachEntry; +import com.gitee.qdbp.able.model.entry.MapEachEntry; import com.gitee.qdbp.able.model.reusable.ExpressionMap; import com.gitee.qdbp.able.result.ResultCode; -import com.gitee.qdbp.tools.beans.MapPlus; /** * Map工具类
@@ -877,25 +880,12 @@ public class MapTools { * @param list 根Map对象数组 * @param interceptor 拦截处理器 */ - @SuppressWarnings("all") - public static void each(List> list, EachInterceptor interceptor) { - // new ListEntry(list) jdk7语法检查报错 - List objects = new ArrayList<>(); - objects.addAll(list); - ListEntry listEntry = new ListEntry(objects); - for (int i = 0; i < list.size(); i++) { - String childName = "[" + i + "]"; - Object childValue = list.get(i); - listEntry.init(childName, childName, i, childValue); - interceptor.intercept(listEntry); - if (listEntry.enter && listEntry.fieldValue != null) { - doEachHandleEntry(listEntry, interceptor); - } - } + public static void each(List list, EachInterceptor interceptor) { + doEachList(null, list, interceptor); } - private static void doEachMap(String parentPath, Map map, EachInterceptor interceptor) { - MapEntry mapEntry = new MapEntry(map); + private static boolean doEachMap(String parentPath, Map map, EachInterceptor interceptor) { + MapEachEntry mapEntry = new MapEachEntry(map); for (Map.Entry item : map.entrySet()) { if (item.getKey() == null || item.getKey().trim().length() == 0) { continue; @@ -904,43 +894,91 @@ public class MapTools { String fieldPath = StringTools.concat('.', parentPath, fieldName); Object fieldValue = item.getValue(); mapEntry.init(fieldPath, fieldName, fieldValue); + // 调用拦截函数 interceptor.intercept(mapEntry); - if (mapEntry.enter && mapEntry.fieldValue != null) { - doEachHandleEntry(mapEntry, interceptor); + if (mapEntry.isSkipAll()) { + // 跳过全部 + return false; + } + if (mapEntry.isSkipAfter()) { + // 跳过当前容器中的后续字段 + break; + } + if (!mapEntry.isSkipEnter() && mapEntry.getValue() != null) { + // 递归进入字段内部 + boolean isContinue = doEnterEntryValue(mapEntry, interceptor); + if (!isContinue) { + return false; + } + } + } + return true; + } + + private static boolean doEachList(String parentPath, List list, EachInterceptor interceptor) { + ListEachEntry listEntry = new ListEachEntry(list); + for (int i = 0; i < list.size(); i++) { + String childName = "[" + i + "]"; + String childPath = ReflectTools.concatFieldPaths(parentPath, childName); + Object childValue = list.get(i); + listEntry.init(childPath, childName, i, childValue); + // 调用拦截函数 + interceptor.intercept(listEntry); + if (listEntry.isSkipAll()) { + // 跳过全部 + return false; + } + if (listEntry.isSkipAfter()) { + // 跳过当前容器中的后续字段 + break; + } + if (!listEntry.isSkipEnter() && listEntry.getValue() != null) { + boolean isContinue = doEnterEntryValue(listEntry, interceptor); + if (!isContinue) { + return false; + } } } + return true; } - private static void doEachHandleEntry(FieldEntry mapEntry, EachInterceptor interceptor) { - String fieldPath = mapEntry.getFieldPath(); - String fieldName = mapEntry.getFieldName(); - Object fieldValue = mapEntry.getFieldValue(); + private static boolean doEnterEntryValue(EachEntry entry, EachInterceptor interceptor) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); List list = ConvertTools.parseList(fieldValue); if (list.size() == 1 && list.get(0) == fieldValue) { // 不是数组 if (fieldValue instanceof Map) { Map child = MapTools.toJsonMap((Map) fieldValue); - doEachMap(fieldPath, child, interceptor); + boolean isContinue = doEachMap(fieldPath, child, interceptor); + if (!isContinue) { + return false; + } } else if (!ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + // 将Java对象转换为Map对象, 需要覆盖设置到容器中去 Map child = JsonTools.beanToMap(fieldValue, true, false); - mapEntry.setValue(child); - doEachMap(fieldPath, child, interceptor); + if (entry instanceof EntryItem.Resetable) { + ((EntryItem.Resetable) entry).resetValue(child); + } + boolean isContinue = doEachMap(fieldPath, child, interceptor); + if (!isContinue) { + return false; + } } } else { - mapEntry.setValue(list); - ListEntry listEntry = new ListEntry(list); - for (int i = 0; i < list.size(); i++) { - String suffix = "[" + i + "]"; - String childName = fieldName + suffix; - String childPath = fieldPath + suffix; - Object childValue = list.get(i); - listEntry.init(childPath, childName, i, childValue); - interceptor.intercept(listEntry); - if (listEntry.enter && listEntry.fieldValue != null) { - doEachHandleEntry(listEntry, interceptor); - } + // 遍历过程中ConvertTools.parseList改变了fieldValue结构 + // 例如Collection对象会转换为List对象 + // 需要覆盖设置到容器中去, 否则对List内容的修改无法变量入参对象 + if (entry instanceof EntryItem.Resetable) { + ((EntryItem.Resetable) entry).resetValue(list); + } + // 遍历list内容 + boolean isContinue = doEachList(fieldPath, list, interceptor); + if (!isContinue) { + return false; } } + return true; } /** 遍历Map的拦截处理器 **/ @@ -951,168 +989,7 @@ public class MapTools { * * @param entry 当前值 */ - void intercept(FieldEntry entry); + void intercept(EachEntry entry); } - /** 遍历Map的字段项变量 **/ - public interface FieldEntry { - - String getFieldPath(); - - String getFieldName(); - - Object getFieldValue(); - - void setValue(Object value); - - /** 设置额外的参数 (如果父对象是数组, 则该操作无效) **/ - void putExtraValue(String key, Object value); - - /** 获取额外的参数 **/ - MapPlus getExtraValues(); - - /** 是否已处理 (只要调用了setValue/putExtraValue就是已处理) **/ - boolean isHandled(); - - /** 是否进入容器, 如果设置为false则不继续处理容器内容 (只在容器值时有效) **/ - void setEnter(boolean enter); - } - - private static class MapEntry implements FieldEntry { - - private final Map map; - private String fieldPath; - private String fieldName; - private Object fieldValue; - private final MapPlus extras = new MapPlus(); - /** 是否已处理 (只要调用了setValue/putExtraValue就是已处理) **/ - private boolean handled; - /** 是否进入容器, 如果设置为false则不继续处理容器内容 (只在容器值时有效) **/ - private boolean enter; - - private MapEntry(Map map) { - this.map = map; - } - - public void init(String fieldPath, String fieldName, Object fieldValue) { - this.fieldPath = fieldPath; - this.fieldName = fieldName; - this.fieldValue = fieldValue; - this.extras.clear(); - this.handled = false; - this.enter = true; - } - - @Override - public String getFieldPath() { - return fieldPath; - } - - @Override - public String getFieldName() { - return fieldName; - } - - @Override - public Object getFieldValue() { - return fieldValue; - } - - @Override - public void setValue(Object value) { - this.map.put(this.fieldName, value); - this.fieldValue = value; - this.handled = true; - } - - @Override - public void putExtraValue(String key, Object value) { - this.map.put(key, value); - this.extras.put(key, value); - this.handled = true; - } - - @Override - public MapPlus getExtraValues() { - return new MapPlus(this.extras); - } - - @Override - public boolean isHandled() { - return this.handled; - } - - @Override - public void setEnter(boolean enter) { - this.enter = enter; - } - } - - private static class ListEntry implements FieldEntry { - - private final List list; - private String fieldPath; - private String fieldName; - private int index; - private Object fieldValue; - /** 是否已处理 (只要调用了setValue/putExtraValue就是已处理) **/ - private boolean handled; - /** 是否进入容器, 如果设置为false则不继续处理容器内容 (只在容器值时有效) **/ - private boolean enter; - - private ListEntry(List list) { - this.list = list; - } - - public void init(String fieldPath, String fieldName, int index, Object fieldValue) { - this.fieldPath = fieldPath; - this.fieldName = fieldName; - this.index = index; - this.fieldValue = fieldValue; - this.handled = false; - this.enter = true; - } - - @Override - public String getFieldPath() { - return fieldPath; - } - - @Override - public String getFieldName() { - return fieldName; - } - - @Override - public Object getFieldValue() { - return fieldValue; - } - - @Override - public void setValue(Object value) { - this.list.set(this.index, value); - this.fieldValue = value; - this.handled = true; - } - - @Override - public void putExtraValue(String key, Object value) { - // 父对象是数组, 则该操作无效 - } - - @Override - public MapPlus getExtraValues() { - return null; - } - - @Override - public boolean isHandled() { - return this.handled; - } - - @Override - public void setEnter(boolean enter) { - this.enter = enter; - } - } } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 7e6dca7..a22f2d9 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -15,7 +15,12 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import com.gitee.qdbp.able.beans.KeyValue; +import com.gitee.qdbp.able.model.entry.EntryItem; +import com.gitee.qdbp.able.model.entry.ListEntryItem; +import com.gitee.qdbp.able.model.entry.MapEntryItem; +import com.gitee.qdbp.able.model.entry.ObjectEntryItem; +import com.gitee.qdbp.able.model.entry.ObjectsEntryItem; +import com.gitee.qdbp.able.model.entry.ReadonlyEntryItem; import com.gitee.qdbp.able.model.reusable.ExpressionMap; import com.gitee.qdbp.tools.parse.StringParser; @@ -69,8 +74,6 @@ public abstract class ReflectTools { private static Object doGetDepthValue(Object target, String fields) { // 将表达式以.或[]拆分为数组 List fieldNames = StringParser.splitsFields(fields); - // 清除空值和this - clearFieldNames(fieldNames); // 逐层取值 Object value = target; for (int i = 0, z = fieldNames.size(); value != null && i < z; i++) { @@ -103,41 +106,38 @@ public abstract class ReflectTools { } private static Object getArrayFieldValue(Object array, String fieldName) { + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getArrayFieldValue(array, index); + } + + private static Object getArrayFieldValue(Object array, int index) { int size = Array.getLength(array); - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } else { - int index = number; - if (number < 0) { - index = size + number; - } - return index < 0 || index >= size ? null : Array.get(array, index); - } + int i = index >= 0 ? index : size + index; + return i < 0 || i >= size ? null : Array.get(array, i); } private static Object getListFieldValue(List list, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - int index = number; - if (number < 0) { - index = list.size() + number; - } - return index < 0 || index >= list.size() ? null : list.get(index); + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getListFieldValue(list, index); + } + + private static Object getListFieldValue(List list, int index) { + int size = list.size(); + int i = index >= 0 ? index : size + index; + return i < 0 || i >= size ? null : list.get(i); } private static Object getIterableFieldValue(Iterable iterable, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - if (number >= 0) { - int index = number; + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getIterableFieldValue(iterable, index); + } + + private static Object getIterableFieldValue(Iterable iterable, int index) { + if (index >= 0) { + int number = index; int i = 0; for (Object value : iterable) { - if (i++ == index) { + if (i++ == number) { return value; } } @@ -150,8 +150,8 @@ public abstract class ReflectTools { size++; } } - int index = size + number; - if (index < 0 || index >= size) { + int number = size + index; + if (number < 0 || number >= size) { return null; } { // 再次循环, 获取对象 @@ -159,7 +159,7 @@ public abstract class ReflectTools { int i = 0; while (iterator.hasNext()) { Object value = iterator.next(); - if (i++ == index) { + if (i++ == i) { return value; } } @@ -169,12 +169,12 @@ public abstract class ReflectTools { } private static Object getIteratorFieldValue(Iterator iterator, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - if (number >= 0) { - int index = number; + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getIteratorFieldValue(iterator, index); + } + + private static Object getIteratorFieldValue(Iterator iterator, int index) { + if (index >= 0) { int i = 0; while (iterator.hasNext()) { Object value = iterator.next(); @@ -191,18 +191,18 @@ public abstract class ReflectTools { size++; temp.add(iterator.next()); } - int index = size + number; - return index < 0 || index >= size ? null : temp.get(index); + int i = size + index; + return i < 0 || i >= size ? null : temp.get(i); } } private static Object getEnumerationFieldValue(Enumeration enumeration, String fieldName) { - Integer number = ConvertTools.toInteger(fieldName, null); - if (number == null) { - return null; - } - if (number >= 0) { - int index = number; + Integer index = ConvertTools.toInteger(fieldName, null); + return index == null ? null : getEnumerationFieldValue(enumeration, index); + } + + private static Object getEnumerationFieldValue(Enumeration enumeration, int index) { + if (index >= 0) { int i = 0; while (enumeration.hasMoreElements()) { Object value = enumeration.nextElement(); @@ -219,8 +219,8 @@ public abstract class ReflectTools { size++; temp.add(enumeration.nextElement()); } - int index = size + number; - return index < 0 || index >= size ? null : temp.get(index); + int i = size + index; + return i < 0 || i >= size ? null : temp.get(i); } } @@ -251,9 +251,9 @@ public abstract class ReflectTools { * * @param target 目标对象, 支持数组/List/Map/Bean * @param fieldNames 字段名, 支持带点的多级字段名/数组下标/负数下标 - * @return 字段值 + * @return EntryItem字段对象 (支持修改字段值) */ - public static List> findDepthValues(Object target, String fieldNames) { + public static List findDepthValues(Object target, String fieldNames) { VerifyTools.requireNotBlank(fieldNames, "field"); if (target == null) { return new ArrayList<>(); @@ -261,14 +261,14 @@ public abstract class ReflectTools { String[] orFields = StringTools.split(fieldNames, "||"); for (int i = 0, z = orFields.length - 1; i <= z; i++) { String fields = orFields[i]; - List> result = doFindDepthValues(target, fields); + List result = doFindDepthValues(target, fields); if (i == z) { // 最后一个OR字段, 直接返回 return result; } else { // 不是最后一个OR字段, 判断是否存在非空的值 boolean existValue = false; - for (KeyValue item : result) { + for (EntryItem item : result) { if (VerifyTools.isNotBlank(item.getValue())) { existValue = true; } @@ -281,21 +281,22 @@ public abstract class ReflectTools { return new ArrayList<>(); } - private static List> doFindDepthValues(Object target, String fields) { + private static List doFindDepthValues(Object target, String fields) { + VerifyTools.requireNotBlank(fields, "fields"); // 将表达式以.或[]拆分为数组 List fieldNames = StringParser.splitsFields(fields); - // 清除空值和this - clearFieldNames(fieldNames); + // 如果target是对象, 将target装入list, 此时entry中的容器对象为null + // 如果target是数组或列表, 转换为list返回, 此时entry中的容器对象为target + List items = parseRootValues(target, needExpandList(fieldNames, 0)); // 逐层取值 - List> items = parseListValues(null, target, needExpandList(fieldNames, 0)); for (int i = 0, z = fieldNames.size() - 1; i <= z; i++) { String field = fieldNames.get(i); // 是否需要展开 (有下一层且下一层是数字时,不需要展开) boolean expand = needExpandList(fieldNames, i + 1); - List> temp = new ArrayList<>(); - for (KeyValue item : items) { - // 上级字段名 - String parentFields = item.getKey(); + List temp = new ArrayList<>(); + for (EntryItem item : items) { + // 本级字段路径 + String currPath = item.getKey(); // 本级字段值 Object currValue = item.getValue(); // 下级字段值 @@ -305,6 +306,9 @@ public abstract class ReflectTools { if (currValue == null) { nextValue = null; currList = false; + } else if (currValue instanceof Map) { + nextValue = getMapFieldValue((Map) currValue, field); + currList = false; } else if (currValue instanceof List) { nextValue = getListFieldValue((List) currValue, field); currList = true; @@ -320,23 +324,14 @@ public abstract class ReflectTools { } else if (currValue instanceof Enumeration) { nextValue = getEnumerationFieldValue((Enumeration) currValue, field); currList = true; - } else if (currValue instanceof Map) { - nextValue = getMapFieldValue((Map) currValue, field); - currList = false; } else { nextValue = getFieldValue(currValue, field, false); currList = false; } - String nextField; - if (currList) { - nextField = StringTools.concat(parentFields, "[" + field + "]"); - } else { - nextField = StringTools.concat('.', parentFields, field); - } // 最末级即使值为空也要加入结果集, 不是最末级则只要值为空就不再继续 boolean isLastField = i >= z; if (isLastField || nextValue != null) { - temp.addAll(parseListValues(nextField, nextValue, expand)); + temp.addAll(parseListValues(currValue, currPath, currList, field, nextValue, expand)); } } items = temp; @@ -344,75 +339,123 @@ public abstract class ReflectTools { return items; } - @SuppressWarnings("all") - private static void clearFieldNames(List fieldNames) { - // 清除空值和this - Iterator iterator = fieldNames.iterator(); - while (iterator.hasNext()) { - String next = iterator.next(); - if (VerifyTools.isBlank(next) || next.equals("this")) { - iterator.remove(); - } - } - } - - // 根据字段名判断是否需要展开 (有下一层且下一层是数字时,说明是取数组的其中一项,不需要展开) + // 根据字段名判断是否需要展开 + // 没有下一层,说明已经是最末级字段了,不需要展开 + // 有下一层且下一层是数字时,说明是取数组的其中一项,不需要展开 private static boolean needExpandList(List fields, int index) { if (index >= fields.size()) { - return true; + return false; } else { String field = fields.get(index); return !StringTools.isNumber(field) || field.indexOf('.') >= 0; } } - private static List> parseListValues(String field, Object value, boolean expand) { - List> results = new ArrayList<>(); + private static List parseRootValues(Object fieldValue, boolean expand) { + return parseListValues(null, null, false, null, fieldValue, expand); + } + + // 为了简化处理, 单个对象也转换为list + // 如果parent是对象, 返回的list只有一个元素: EntryItem的容器是parent, 值是fieldValue + // 如果parent是列表, 返回的list是列表的每个元素: EntryItem的容器是fieldValue, 值是fieldValue[i] + private static List parseListValues(Object parent, String parentPath, boolean parentList, + String fieldName, Object fieldValue, boolean expand) { + List results = new ArrayList<>(); if (!expand) { - results.add(new KeyValue<>(field, value)); + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); } else { - if (value == null) { - results.add(new KeyValue<>(field, null)); - } else if (value instanceof List) { - List values = (List) value; - for (int i = 0; i < values.size(); i++) { - String key = StringTools.concat(field, "[" + i + "]"); - results.add(new KeyValue<>(key, values.get(i))); - } - } else if (value.getClass().isArray()) { - Object[] values = (Object[]) value; - for (int i = 0; i < values.length; i++) { - String key = StringTools.concat(field, "[" + i + "]"); - results.add(new KeyValue<>(key, values[i])); - } - } else if (value instanceof Iterable) { - Iterable iterable = (Iterable) value; - int i = 0; - for (Object item : iterable) { - String key = StringTools.concat(field, "[" + (i++) + "]"); - results.add(new KeyValue<>(key, item)); - } - } else if (value instanceof Iterator) { - Iterator iterator = (Iterator) value; - int i = 0; - while (iterator.hasNext()) { - String key = StringTools.concat(field, "[" + (i++) + "]"); - results.add(new KeyValue<>(key, iterator.next())); - } - } else if (value instanceof Enumeration) { - Enumeration enumeration = (Enumeration) value; - int i = 0; - while (enumeration.hasMoreElements()) { - String key = StringTools.concat(field, "[" + (i++) + "]"); - results.add(new KeyValue<>(key, enumeration.nextElement())); - } + if (fieldValue == null) { + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, null)); + } else if (fieldValue instanceof Map) { + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); } else { - results.add(new KeyValue<>(field, value)); + String realFieldName = parentList ? "[" + fieldName + "]" : fieldName; + if (fieldValue instanceof List) { + List values = (List) fieldValue; + for (int i = 0; i < values.size(); i++) { + String name = "[" + i + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ListEntryItem(values).init(path, name, i, values.get(i))); + } + } else if (fieldValue.getClass().isArray()) { + Object[] values = (Object[]) fieldValue; + for (int i = 0; i < values.length; i++) { + String name = "[" + i + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ObjectsEntryItem(values).init(path, name, i, values[i])); + } + } else if (fieldValue instanceof Iterable) { + Iterable iterable = (Iterable) fieldValue; + int i = 0; + for (Object item : iterable) { + String name = "[" + (i++) + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ReadonlyEntryItem(iterable).init(path, name, item)); + } + } else if (fieldValue instanceof Iterator) { + Iterator iterator = (Iterator) fieldValue; + int i = 0; + while (iterator.hasNext()) { + String name = "[" + (i++) + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ReadonlyEntryItem(iterator).init(path, name, iterator.next())); + } + } else if (fieldValue instanceof Enumeration) { + Enumeration enumeration = (Enumeration) fieldValue; + int i = 0; + while (enumeration.hasMoreElements()) { + String name = "[" + (i++) + "]"; + String path = concatFieldPaths(parentPath, realFieldName, name); + results.add(new ReadonlyEntryItem(enumeration).init(path, name, enumeration.nextElement())); + } + } else { + results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); + } } } return results; } + private static EntryItem newObjectEntryItem(Object parent, String parentPath, boolean parentList, + String fieldName, Object fieldValue) { + if (!parentList) { + String path = concatFieldPaths(parentPath, fieldName); + if (parent instanceof Map) { + return new MapEntryItem((Map) parent).init(path, fieldName, fieldValue); + } else { + return new ObjectEntryItem(parent).init(path, fieldName, fieldValue); + } + } else { + Integer index = ConvertTools.toInteger(fieldName, null); + String name = "[" + fieldName + "]"; + String path = concatFieldPaths(parentPath, name); + if (index != null && parent instanceof List) { + return new ListEntryItem((List) parent).init(path, name, index, fieldValue); + } else if (index != null && parent.getClass().isArray()) { + return new ObjectsEntryItem(parent).init(path, name, index, fieldValue); + } else { + return new ReadonlyEntryItem(parent).init(path, name, fieldValue); + } + } + } + + static String concatFieldPaths(String... parts) { + StringBuilder buffer = new StringBuilder(); + for (String part : parts) { + if (part == null || part.length() == 0) { + continue; + } + if (buffer.length() == 0) { + buffer.append(part); + } else if (StringTools.startsWithChar(part, '[')) { + buffer.append(part); + } else { + buffer.append('.').append(part); + } + } + return buffer.length() == 0 ? null : buffer.toString(); + } + /** * 深度判断对象中是否存在指定的字段, 支持多级字段名 * @@ -441,7 +484,7 @@ public abstract class ReflectTools { // 逐层取值 for (int j = 0, z = list == null ? 0 : list.length; value != null && j < z; j++) { String field = list[j]; - if (VerifyTools.isNotBlank(field) && !field.equals("this")) { + if (VerifyTools.isNotBlank(field)) { if (value instanceof List) { if (containsListIndex((List) value, field)) { value = getListFieldValue((List) value, field); @@ -606,7 +649,8 @@ public abstract class ReflectTools { } if (throwOnNotFound) { - throw new IllegalArgumentException(clazz.getSimpleName() + "." + fieldName + " not found."); + String fieldPath = concatFieldPaths(clazz.getSimpleName(), fieldName); + throw new IllegalArgumentException(fieldPath + " not found."); } else { return null; } -- Gitee From 1fa6bc98b7955fa7c0f43680882e41c7dbf2d502 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:26:10 +0800 Subject: [PATCH 32/82] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/test/EachMapTest.java | 33 +- .../qdbp/tools/utils/ReflectToolsTest.java | 452 ++++++++++++++++-- 2 files changed, 451 insertions(+), 34 deletions(-) diff --git a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java index 92506e2..775c159 100644 --- a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java +++ b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import org.testng.Assert; import org.testng.annotations.Test; +import com.gitee.qdbp.able.model.entry.EachEntry; import com.gitee.qdbp.tools.beans.MapPlus; import com.gitee.qdbp.tools.utils.JsonTools; import com.gitee.qdbp.tools.utils.MapTools; @@ -47,12 +48,14 @@ public class EachMapTest { Assert.assertEquals(address1.getClass(), MapPlus.class); Assert.assertSame(address1, address); + System.out.println("-------------------------------"); + final Map result = new LinkedHashMap<>(); MapTools.each(root, new MapTools.EachInterceptor() { @Override - public void intercept(MapTools.FieldEntry entry) { - String fieldPath = entry.getFieldPath(); - Object fieldValue = entry.getFieldValue(); + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); if (fieldValue == null) { result.put(fieldPath, null); } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { @@ -70,5 +73,29 @@ public class EachMapTest { Assert.assertEquals(result.get("entity.user.address[0].city"), "nanjing"); Assert.assertEquals(result.get("entity.user.address[0].phones[0]"), "1301112222"); Assert.assertEquals(result.get("entity.user.address[0].phones[1]"), "13044445555"); + + System.out.println("-------------------------------"); + + final Map aResult = new LinkedHashMap<>(); + MapTools.each(addresses, new MapTools.EachInterceptor() { + @Override + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); + if (fieldValue == null) { + aResult.put(fieldPath, null); + } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + aResult.put(fieldPath, fieldValue); + } + } + }); + System.out.println(JsonTools.toLogString(aResult)); + Assert.assertTrue(aResult.containsKey("[0].city")); + Assert.assertTrue(aResult.containsKey("[0].phones[0]")); + Assert.assertTrue(aResult.containsKey("[0].phones[1]")); + + Assert.assertEquals(aResult.get("[0].city"), "nanjing"); + Assert.assertEquals(aResult.get("[0].phones[0]"), "1301112222"); + Assert.assertEquals(aResult.get("[0].phones[1]"), "13044445555"); } } diff --git a/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java b/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java index 05eaa84..c6aa830 100644 --- a/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java +++ b/tools/src/test/java/com/gitee/qdbp/tools/utils/ReflectToolsTest.java @@ -1,10 +1,11 @@ package com.gitee.qdbp.tools.utils; +import java.util.HashMap; import java.util.List; import java.util.Map; -import com.gitee.qdbp.able.beans.KeyValue; import org.testng.Assert; import org.testng.annotations.Test; +import com.gitee.qdbp.able.model.entry.EntryItem; @Test public class ReflectToolsTest { @@ -260,30 +261,50 @@ public class ReflectToolsTest { public void testFindDepthValue11() { String json = "{domain:{text:'baidu',url:'https://baidu.com'}}"; System.out.println(json); - Object object = JsonTools.parseAsMap(json); { + Object object = JsonTools.parseAsMap(json); String key = "domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); + // 设置值 + values.get(0).setValue("baidu2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu2", key); } { + Object object = JsonTools.parseAsMap(json); String key = "domain.name"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "domain.name", key); + Assert.assertEquals(values.get(0).getFields(), "domain.name", key); + Assert.assertEquals(values.get(0).getName(), "name", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("baidu22"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu22", key); } { + Object object = JsonTools.parseAsMap(json); String key = "domain.name || domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); + // 设置值 + values.get(0).setValue("baidu222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu222", key); } } @@ -292,36 +313,57 @@ public class ReflectToolsTest { String json = "[{domain:{text:'baidu',url:'https://baidu.com'}},{domain:{text:'bing',url:'https://cn.bing.com'}}]"; System.out.println(json); - Object object = JsonTools.parseAsMaps(json); { + Object object = JsonTools.parseAsMaps(json); String key = "[1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing2", key); } { + Object object = JsonTools.parseAsMaps(json); String key = "[2].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 0, key + ".size"); } { + Object object = JsonTools.parseAsMaps(json); String key = "[-1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[-1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing22"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing22", key); } { + Object object = JsonTools.parseAsMaps(json); String key = "[-2].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[-2].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); + // 设置值 + values.get(0).setValue("baidu222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu222", key); } } @@ -332,13 +374,23 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMaps(json); String key = "domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 2, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "[0].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "baidu", key); Assert.assertEquals(values.get(1).getKey(), "[1].domain.text", key); + Assert.assertEquals(values.get(1).getFields(), "domain.text", key); + Assert.assertEquals(values.get(1).getName(), "text", key); Assert.assertEquals(values.get(1).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("baidu2"); + values.get(1).setValue("bing2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu2", key); + Assert.assertEquals(values2.get(1).getValue(), "bing2", key); } @Test @@ -349,10 +401,12 @@ public class ReflectToolsTest { Object object = JsonTools.parseAsMap(json); { String key = "data[1].domain"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); Object value = values.get(0).getValue(); System.out.println(key + " = " + JsonTools.toLogString(value)); Assert.assertEquals(values.get(0).getKey(), "data[1].domain", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain", key); + Assert.assertEquals(values.get(0).getName(), "domain", key); Assert.assertNotNull(value); Assert.assertTrue(Map.class.isAssignableFrom(value.getClass())); Map domain = (Map) value; @@ -361,7 +415,7 @@ public class ReflectToolsTest { } { String key = "data[2].domain"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + JsonTools.toLogString(values)); Assert.assertEquals(values.size(), 0, key); } @@ -374,13 +428,15 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); Assert.assertEquals(values.size(), 2, key + ".size"); String key1 = values.get(0).getKey(); Object value1 = values.get(0).getValue(); System.out.println(key1 + " = " + JsonTools.toLogString(value1)); Assert.assertEquals(key1, "data[0].domain", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain", key); + Assert.assertEquals(values.get(0).getName(), "domain", key); Assert.assertNotNull(value1); Assert.assertTrue(Map.class.isAssignableFrom(value1.getClass())); Map domain1 = (Map) value1; @@ -391,6 +447,8 @@ public class ReflectToolsTest { Object value2 = values.get(1).getValue(); System.out.println(key2 + " = " + JsonTools.toLogString(value2)); Assert.assertEquals(key2, "data[1].domain", key); + Assert.assertEquals(values.get(1).getFields(), "data.domain", key); + Assert.assertEquals(values.get(1).getName(), "domain", key); Assert.assertNotNull(value2); Assert.assertTrue(Map.class.isAssignableFrom(value2.getClass())); Map domain2 = (Map) value2; @@ -403,38 +461,65 @@ public class ReflectToolsTest { String json = "{data:[{domain:{text:'baidu',url:'https://baidu.com'}}," + "{domain:{text:'bing',url:'https://cn.bing.com'}}]}"; System.out.println(json); - Object object = JsonTools.parseAsMap(json); { + Object object = JsonTools.parseAsMap(json); String key = "data[1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing2", key); } { + Object object = JsonTools.parseAsMap(json); String key = "data[1].domain.name"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.name", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.name", key); + Assert.assertEquals(values.get(0).getName(), "name", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("bing22"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing22", key); } { + Object object = JsonTools.parseAsMap(json); String key = "data[1].domain.name || data[1].domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertEquals(values.get(0).getValue(), "bing", key); + // 设置值 + values.get(0).setValue("bing222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing222", key); } { + Object object = JsonTools.parseAsMap(json); String key = ".data[1].domain.name"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[1].domain.name", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.name", key); + Assert.assertEquals(values.get(0).getName(), "name", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("bing2222"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "bing2222", key); } } @@ -445,19 +530,41 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain.address.city"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 5, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[0].domain.address[0].city", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(0).getName(), "city", key); Assert.assertEquals(values.get(0).getValue(), "Guangzhou", key); Assert.assertEquals(values.get(1).getKey(), "data[0].domain.address[1].city", key); + Assert.assertEquals(values.get(1).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(1).getName(), "city", key); Assert.assertEquals(values.get(1).getValue(), "Nanjing", key); Assert.assertEquals(values.get(2).getKey(), "data[1].domain.address[0].city", key); + Assert.assertEquals(values.get(2).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(2).getName(), "city", key); Assert.assertEquals(values.get(2).getValue(), "Beijing", key); Assert.assertEquals(values.get(3).getKey(), "data[1].domain.address[1].city", key); + Assert.assertEquals(values.get(3).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(3).getName(), "city", key); Assert.assertEquals(values.get(3).getValue(), "Shanghai", key); Assert.assertEquals(values.get(4).getKey(), "data[1].domain.address[2].city", key); + Assert.assertEquals(values.get(4).getFields(), "data.domain.address.city", key); + Assert.assertEquals(values.get(4).getName(), "city", key); Assert.assertEquals(values.get(4).getValue(), "Shenzhen", key); + // 设置值 + values.get(0).setValue("Guangzhou2"); + values.get(1).setValue("Nanjing2"); + values.get(2).setValue("Beijing2"); + values.get(3).setValue("Shanghai2"); + values.get(4).setValue("Shenzhen2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "Guangzhou2", key); + Assert.assertEquals(values2.get(1).getValue(), "Nanjing2", key); + Assert.assertEquals(values2.get(2).getValue(), "Beijing2", key); + Assert.assertEquals(values2.get(3).getValue(), "Shanghai2", key); + Assert.assertEquals(values2.get(4).getValue(), "Shenzhen2", key); } @Test @@ -466,11 +573,17 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), "data[0].domain.text", key); + Assert.assertEquals(values.get(0).getFields(), "data.domain.text", key); + Assert.assertEquals(values.get(0).getName(), "text", key); Assert.assertNull(values.get(0).getValue(), key); + // 设置值 + values.get(0).setValue("baidu2"); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), "baidu2", key); } @Test @@ -479,70 +592,347 @@ public class ReflectToolsTest { System.out.println(json); Object object = JsonTools.parseAsMap(json); String key = "data.domain.text"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 0, key + ".size"); } @Test - public void testFindLastListIndex() { + public void testFindLastListIndex11() { String json = "{data:[1,2,3,4,5,6]}"; System.out.println(json); - Object object = JsonTools.parseAsMap(json); { + Object object = JsonTools.parseAsMap(json); + String key = "data[0]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[5]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[5]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-1]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-1]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-2]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-2]", key); + Assert.assertEquals(values.get(0).getValue(), 5, key); + // 设置值 + values.get(0).setValue(55); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 55, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-6]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-6]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[+7]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[+7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[-7]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + } + + @Test + public void testFindLastListIndex12() { + { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[0]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[5]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[5]", key); Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-1]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-1]", key); Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-2]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-2]", key); Assert.assertEquals(values.get(0).getValue(), 5, key); + // 设置值 + values.get(0).setValue(55); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 55, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-6]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-6]", key); Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[+7]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[+7]", key); Assert.assertNull(values.get(0).getValue(), key); } { + Map object = new HashMap<>(); + object.put("data", new int[] { 1,2,3,4,5,6 }); String key = "data[-7]"; - List> values = ReflectTools.findDepthValues(object, key); + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + } + + @Test + public void testFindLastListIndex21() { + String json = "{data:[[1,2,3,4,5,6],[7,8,9,0]]}"; + System.out.println(json); + { + Object object = JsonTools.parseAsMap(json); + String key = "data"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "data", key); + Object value = values.get(0).getValue(); + Assert.assertTrue(value instanceof List, key); + Assert.assertEquals(((List)value).size(), 2, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); + Object value = values.get(0).getValue(); + Assert.assertTrue(value instanceof List, key); + Assert.assertEquals(((List)value).size(), 6, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][0]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[0]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][5]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[5]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-1]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-1]", key); + Assert.assertEquals(values.get(0).getValue(), 6, key); + // 设置值 + values.get(0).setValue(66); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 66, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-2]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-2]", key); + Assert.assertEquals(values.get(0).getValue(), 5, key); + // 设置值 + values.get(0).setValue(55); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 55, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-6]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-6]", key); + Assert.assertEquals(values.get(0).getValue(), 1, key); + // 设置值 + values.get(0).setValue(11); + List values2 = ReflectTools.findDepthValues(object, key); + Assert.assertEquals(values2.get(0).getValue(), 11, key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][+7]"; + List values = ReflectTools.findDepthValues(object, key); + System.out.println(key + " = " + values); + Assert.assertEquals(values.size(), 1, key + ".size"); + Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[+7]", key); + Assert.assertNull(values.get(0).getValue(), key); + } + { + Object object = JsonTools.parseAsMap(json); + String key = "data[0][-7]"; + List values = ReflectTools.findDepthValues(object, key); System.out.println(key + " = " + values); Assert.assertEquals(values.size(), 1, key + ".size"); Assert.assertEquals(values.get(0).getKey(), key, key); + Assert.assertEquals(values.get(0).getFields(), "data", key); + Assert.assertEquals(values.get(0).getName(), "[-7]", key); Assert.assertNull(values.get(0).getValue(), key); } } -- Gitee From f5fecea57c29d67fe43145c2c3f0e138ff0497bd Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:26:22 +0800 Subject: [PATCH 33/82] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/settings/i18n/ResultCode_zh_CN.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties index ce93a70..8ccb692 100644 --- a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties @@ -19,4 +19,4 @@ FORBIDDEN = 没有权限 ACCESS_DENIED = 访问被拒绝 OPERATE_TIMEOUT = 操作已超时 SYSTEM_CONFIG_ERROR = 系统配置错误 -UNSUPPORTED_OPERATION = 暂不支持该操作 +UNSUPPORTED_OPERATION = 不支持该操作 -- Gitee From 5f4ddf73f1be2b9601cb28f1f8b4a63ed109fd87 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 28 May 2023 23:31:35 +0800 Subject: [PATCH 34/82] =?UTF-8?q?5.6.0,=20=E7=89=88=E6=9C=AC=E5=8D=87?= =?UTF-8?q?=E7=BA=A7,=20MapTools.each/ReflectTools.findDepthValues?= =?UTF-8?q?=E4=B8=8D=E5=85=BC=E5=AE=B9=E6=97=A7=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index bbd0d0a..607f591 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.5.15 + 5.6.0 ``` ```xml com.gitee.qdbp qdbp-tools - 5.5.15 + 5.6.0 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index c80e177..40c3dcd 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.5.15 + 5.6.0 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 6ef795c..551c81c 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.5.15 + 5.6.0 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.5.15 + 5.6.0 diff --git a/test/pom.xml b/test/pom.xml index e0c3828..01b64b0 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.5.15 + 5.6.0 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 7ca5221..336526e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 8aa4fcc..e60ff7c 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 55df0db..073d4f4 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 3b7215f..582ae0b 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index ecebe93..d526484 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.5.15 + 5.6.0 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index 057e332..8b849d1 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.5.15 + 5.6.0 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 69159819267cc11721f661b1ce009d774ff5ed10 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 31 May 2023 22:46:50 +0800 Subject: [PATCH 35/82] =?UTF-8?q?=E4=BF=AE=E6=94=B9idea=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/tools/utils/ConvertTools.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index a6e6af2..433a81e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -3,6 +3,7 @@ package com.gitee.qdbp.tools.utils; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; +import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.time.Instant; @@ -482,7 +483,7 @@ public class ConvertTools { } BigDecimal value = clearTrailingZeros(number); if (value.scale() > maxScale) { - value = value.setScale(maxScale, BigDecimal.ROUND_HALF_UP); + value = value.setScale(maxScale, RoundingMode.HALF_UP); value = clearTrailingZeros(value); } if (expect == BigDecimal.class) { @@ -573,7 +574,7 @@ public class ConvertTools { // new BigDecimal(20000).stripTrailingZeros(); = 2E+4 (科学计数法) // 此时precision=1,scale=-4; 需要将scale设置为0 if (number.scale() < 0) { - number = number.setScale(0, BigDecimal.ROUND_HALF_UP); + number = number.setScale(0, RoundingMode.HALF_UP); } return number; } -- Gitee From f23d6798f6812e1a3980830886451bdc77bead42 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:06:36 +0800 Subject: [PATCH 36/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E4=B8=BA=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E7=9A=84=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNodes.java | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java index 7252722..53ee1e4 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import com.gitee.qdbp.able.function.BaseFunction; +import com.gitee.qdbp.able.function.BinaryConsumer; import com.gitee.qdbp.tools.utils.VerifyTools; /** @@ -32,7 +33,8 @@ public class TreeNodes { this(list, false, keyGetter, parentGetter); } - public TreeNodes(List list, boolean upgrade, BaseFunction keyGetter, BaseFunction parentGetter) { + public TreeNodes(List list, boolean upgrade, BaseFunction keyGetter, + BaseFunction parentGetter) { Node container = new Node<>(null); String rootCode = "0"; List> all = new ArrayList<>(); @@ -172,6 +174,24 @@ public class TreeNodes { return this.keysOfWithoutParent; } + /** + * 转换为树形数据, 即从code+parent形式的平行列表转换为element+children形式的树形层级结构
+ * 使用方式:
+ * TreeNodes<TreeNode> tree = new TreeNodes<>(beans, TreeNode::getCode, TreeNode::getParent);
+ * List<TreeNode> list = tree.toTreeList(TreeNode::setChildren);
+ * + * @param childSetter 子节点设置方法 + * @return 树形数据的根节点 + */ + public List toTreeList(BinaryConsumer> childSetter) { + List list = new ArrayList<>(); + for (Node child : container.children) { + child.fillAllChildren(childSetter); + list.add(child.element); + } + return list; + } + /** 广度优先遍历 **/ public Iterator breadthFirstIterator() { return container.breadthFirstElementIterator(); @@ -182,6 +202,30 @@ public class TreeNodes { return container.depthFirstElementIterator(); } + /** + * 转换为树形数据, 即从code+parent形式的平行列表转换为element+children形式的树形层级结构
+ * 使用方式:
+ * List<TreeNode> list = TreeNodes.toTreeList(beans,
+ *         TreeNode::getCode, TreeNode::getParent, TreeNode::setChildren);
+ * + * @param list 原始列表 + * @param keyGetter KEY的获取方法 + * @param parentGetter 上级的获取方法 + * @param childSetter 子级的设置方法 + * @return 树形数据列表 + * @param 数据类型 + */ + public static List toTreeList(List list, BaseFunction keyGetter, + BaseFunction parentGetter, BinaryConsumer> childSetter) { + return toTreeList(list, false, keyGetter, parentGetter, childSetter); + } + + public static List toTreeList(List list, boolean upgrade, BaseFunction keyGetter, + BaseFunction parentGetter, BinaryConsumer> childSetter) { + TreeNodes tree = new TreeNodes<>(list, upgrade, keyGetter, parentGetter); + return tree.toTreeList(childSetter); + } + public static class Node { /** 本级 **/ @@ -300,6 +344,26 @@ public class TreeNodes { return new DepthFirstNodeIterator<>(this); } + /** 设置所有后代元素的Children属性 **/ + public void fillAllChildren(BinaryConsumer> childSetter) { + Iterator> iterator = this.depthFirstNodeIterator(); + List myChildren = new ArrayList<>(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (node.parent == this) { + myChildren.add(node.element); + } else { + List> children = node.children; + List temp = new ArrayList<>(); + for (Node child : children) { + temp.add(child.element); + } + childSetter.accept(node.element, temp); + } + } + childSetter.accept(this.element, myChildren); + } + @Override public String toString() { return element == null ? "{root}" : element.toString(); -- Gitee From ac292d46ec74387a09897157736c23876bd619b5 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:07:14 +0800 Subject: [PATCH 37/82] =?UTF-8?q?=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNode.java | 55 +++++++ .../gitee/qdbp/able/beans/TreeNodesTest.java | 135 ++++++++++++++++-- 2 files changed, 180 insertions(+), 10 deletions(-) create mode 100644 tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java new file mode 100644 index 0000000..79490ac --- /dev/null +++ b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java @@ -0,0 +1,55 @@ +package com.gitee.qdbp.able.beans; + +import java.util.List; +import java.util.Objects; +import com.gitee.qdbp.tools.utils.VerifyTools; + +class TreeNode { + + private String code; + + private List children; + + public TreeNode() { + } + + public TreeNode(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getParent() { + return TreeNodesTest.codeTools.parent(code); + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + @Override + public boolean equals(Object other) { + return other instanceof TreeNode && VerifyTools.equals(this.code, ((TreeNode) other).code); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.code); + } + + @Override + public String toString() { + return this.code; + } + +} diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java index 30ed780..244ba30 100644 --- a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java +++ b/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java @@ -20,33 +20,33 @@ import com.gitee.qdbp.tools.utils.StringTools; @Test public class TreeNodesTest { - private static final CodeTools codeTools = new CodeTools(1, 2); + static final CodeTools codeTools = new CodeTools(1, 2); - public void test() { + public void test1() { List list = generateTestData(); - TreeNodes container = new TreeNodes<>(list, true, new KeyGetter(), new ParentGetter()); + TreeNodes tree = new TreeNodes<>(list, new KeyGetter(), new ParentGetter()); - List rootElements = container.getRootElements(); + List rootElements = tree.getRootElements(); AssertTools.assertDeepEquals(rootElements, Arrays.asList("T01", "T02", "T03")); - List t01Children = container.findChildElements("T02"); + List t01Children = tree.findChildElements("T02"); AssertTools.assertDeepEquals(t01Children, Arrays.asList("T0201", "T0202", "T0203")); - List t020304Children = container.findChildElements("T020304"); + List t020304Children = tree.findChildElements("T020304"); Assert.assertEquals(t020304Children.size(), 0); - List t020304Ancestors = container.findAllAncestorElements("T020304"); + List t020304Ancestors = tree.findAllAncestorElements("T020304"); AssertTools.assertDeepEquals(t020304Ancestors, Arrays.asList("T02", "T0203")); - List t02Descendants = container.findAllDescendantElements("T02"); + List t02Descendants = tree.findAllDescendantElements("T02"); AssertTools.assertDeepEquals(t02Descendants, Arrays.asList( "T0201", "T020101", "T020102", "T020103", "T020104", "T0202", "T020201", "T020202", "T020203", "T020204", "T0203", "T020301", "T020302", "T020303", "T020304")); { // 深度优先遍历 - TreeNodes.Node t01Node = container.findNode("T01"); + TreeNodes.Node t01Node = tree.findNode("T01"); Iterator> t01NodeIterator = t01Node.depthFirstNodeIterator(); while (t01NodeIterator.hasNext()) { TreeNodes.Node next = t01NodeIterator.next(); @@ -76,7 +76,7 @@ public class TreeNodesTest { } { // 广度优先遍历 - TreeNodes.Node t03Node = container.findNode("T03"); + TreeNodes.Node t03Node = tree.findNode("T03"); Iterator> t03NodeIterator = t03Node.depthFirstNodeIterator(); while (t03NodeIterator.hasNext()) { TreeNodes.Node next = t03NodeIterator.next(); @@ -106,6 +106,121 @@ public class TreeNodesTest { } } + public void test2() { + List beans = generateNodeData(); + TreeNodes tree = new TreeNodes<>(beans, true, + TreeNode::getCode, TreeNode::getParent); + + List rootElements = tree.getRootElements(); + AssertTools.assertDeepEquals(rootElements, asTreeNodeList("T01", "T02", "T03")); + + List t01Children = tree.findChildElements("T02"); + AssertTools.assertDeepEquals(t01Children, asTreeNodeList("T0201", "T0202", "T0203")); + + List t020304Children = tree.findChildElements("T020304"); + Assert.assertEquals(t020304Children.size(), 0); + + List t020304Ancestors = tree.findAllAncestorElements("T020304"); + AssertTools.assertDeepEquals(t020304Ancestors, asTreeNodeList("T02", "T0203")); + + List t02Descendants = tree.findAllDescendantElements("T02"); + AssertTools.assertDeepEquals(t02Descendants, asTreeNodeList( + "T0201", "T020101", "T020102", "T020103", "T020104", + "T0202", "T020201", "T020202", "T020203", "T020204", + "T0203", "T020301", "T020302", "T020303", "T020304")); + + { // 深度优先遍历 + TreeNodes.Node t01Node = tree.findNode("T01"); + Iterator> t01NodeIterator = t01Node.depthFirstNodeIterator(); + while (t01NodeIterator.hasNext()) { + TreeNodes.Node next = t01NodeIterator.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.endsWith("04")) { + String newCode = StringTools.replaceSuffix(nodeCode, "05"); + next.getParentNode().addChildElement(new TreeNode(newCode)); + } + } + List t01Descendants = t01Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t01Descendants, asTreeNodeList( + "T0101", "T010101", "T010102", "T010103", "T010104", "T010105", + "T0102", "T010201", "T010202", "T010203", "T010204", "T010205", + "T0103", "T010301", "T010302", "T010303", "T010304", "T010305")); + + Iterator> t01NodeIterator2 = t01Node.depthFirstNodeIterator(); + while (t01NodeIterator2.hasNext()) { + TreeNodes.Node next = t01NodeIterator2.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.contains("02")) { + t01NodeIterator2.remove(); + } + } + List t01Descendants2 = t01Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t01Descendants2, asTreeNodeList( + "T0101", "T010101", "T010103", "T010104", "T010105", + "T0103", "T010301", "T010303", "T010304", "T010305")); + } + + { // 广度优先遍历 + TreeNodes.Node t03Node = tree.findNode("T03"); + Iterator> t03NodeIterator = t03Node.depthFirstNodeIterator(); + while (t03NodeIterator.hasNext()) { + TreeNodes.Node next = t03NodeIterator.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.endsWith("04")) { + String newCode = StringTools.replaceSuffix(nodeCode, "05"); + next.getParentNode().addChildElement(new TreeNode(newCode)); + } + } + List t03Descendants = t03Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t03Descendants, asTreeNodeList( + "T0301", "T030101", "T030102", "T030103", "T030104", "T030105", + "T0302", "T030201", "T030202", "T030203", "T030204", "T030205", + "T0303", "T030301", "T030302", "T030303", "T030304", "T030305")); + + Iterator> t03NodeIterator2 = t03Node.depthFirstNodeIterator(); + while (t03NodeIterator2.hasNext()) { + TreeNodes.Node next = t03NodeIterator2.next(); + TreeNode element = next.getElement(); + String nodeCode = element.getCode(); + if (nodeCode.contains("02")) { + t03NodeIterator2.remove(); + } + } + List t03Descendants2 = t03Node.getAllDescendantElements(); + AssertTools.assertDeepEquals(t03Descendants2, asTreeNodeList( + "T0301", "T030101", "T030103", "T030104", "T030105", + "T0303", "T030301", "T030303", "T030304", "T030305")); + } + } + + + public void test3() { + List beans = generateNodeData(); + TreeNodes tree = new TreeNodes<>(beans, TreeNode::getCode, TreeNode::getParent); + List treeList = tree.toTreeList(TreeNode::setChildren); + AssertTools.assertDeepEquals(treeList, asTreeNodeList("T01", "T02", "T03")); + } + + private List generateNodeData() { + List list = generateTestData(); + List beans = new ArrayList<>(); + for (String item : list) { + beans.add(new TreeNode(item)); + } + return beans; + } + + private List asTreeNodeList(String ... codes) { + List beans = new ArrayList<>(); + for (String item : codes) { + beans.add(new TreeNode(item)); + } + return beans; + } + private List generateTestData() { List list = new ArrayList<>(); for (int i = 1; i <= 3; i++) { -- Gitee From 2ad3a3afda9ce8ef0a708bc1c87f58c11deeb47e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:16:51 +0800 Subject: [PATCH 38/82] ConvertTools.copyObject --- .../gitee/qdbp/tools/utils/ConvertTools.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 433a81e..05a4177 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -22,11 +22,15 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.TreeSet; +import com.gitee.qdbp.able.beans.Copyable; +import com.gitee.qdbp.tools.beans.MapPlus; /** * 格式转换工具 @@ -1669,4 +1673,82 @@ public class ConvertTools { LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone); return localDateTime.toLocalTime(); } + + /** + * 复制对象
+ * 调用Copyable的copy()方法进行复制
+ * List/Set/Map容器将会循环递归复制其中的内容
+ * + * @param value 原对象 + * @return 复制后的对象 + * @throws IllegalArgumentException 如果value既不是原生对象也不是容器对象, 又没有实现Copyable接口, 将会抛出异常 + * @param 对象类型 + */ + public static T copyObject(T value) { + T result = doCopyObject(value); + if (result != null && result == value) { + if (value instanceof Copyable || ReflectTools.isPrimitive(value.getClass(), false)) { + return result; + } else { + // 如果不是原生对象又没有实现Copyable接口, 就抛出异常 + throw new IllegalArgumentException("Cannot copy object that do not implement the 'Copyable' interface"); + } + } + return result; + } + + @SuppressWarnings("unchecked") + private static T doCopyObject(T value) { + if (value == null) { + return null; + } + if (value instanceof Copyable) { + return (T) ((Copyable) value).copy(); + } + if (value instanceof List) { + List older = (List) value; + List newer = new ArrayList<>(); + for (Object o : older) { + newer.add(doCopyObject(o)); + } + return (T) newer; + } + if (value instanceof Set) { + Set newer; + if (value instanceof TreeSet) { + newer = new TreeSet<>(); + } else if (value instanceof LinkedHashSet) { + newer = new LinkedHashSet<>(); + } else { + newer = new HashSet<>(); + } + Set older = (Set) value; + for (Object o : older) { + newer.add(doCopyObject(o)); + } + return (T) newer; + } + if (value instanceof MapPlus) { + MapPlus newer = new MapPlus(); + MapPlus older = (MapPlus) value; + for (Map.Entry entry : older.entrySet()) { + newer.put(entry.getKey(), doCopyObject(entry.getValue())); + } + return (T) newer; + } + if (value instanceof Map) { + Map newer; + if (value instanceof LinkedHashMap) { + newer = new LinkedHashMap<>(); + } else { + newer = new HashMap<>(); + } + Map older = (Map) value; + for (Map.Entry entry : older.entrySet()) { + newer.put(entry.getKey(), doCopyObject(entry.getValue())); + } + return (T) newer; + } + return value; + } } -- Gitee From 0c578294f3dc424723af695afe58343c794a0f58 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 1 Jun 2023 00:19:58 +0800 Subject: [PATCH 39/82] 5.6.230531 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- tools/pom.xml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 607f591..8617ca2 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.0 + 5.6.230531 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.0 + 5.6.230531 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 40c3dcd..e54323f 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.0 + 5.6.230531 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 551c81c..f9e6e39 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.0 + 5.6.230531 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.0 + 5.6.230531 diff --git a/test/pom.xml b/test/pom.xml index 01b64b0..a12e98c 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.0 + 5.6.230531 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 336526e..96c8631 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index e60ff7c..935654e 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 073d4f4..33e7325 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 582ae0b..0b110e3 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index d526484..4271084 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.0 + 5.6.230531 qdbp-tools-test-jdk7 diff --git a/tools/pom.xml b/tools/pom.xml index 8b849d1..e20e132 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.0 + 5.6.230531 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 47159a6be53d849e90eaa6496200b7c017cf0807 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:42:40 +0800 Subject: [PATCH 40/82] =?UTF-8?q?eachMap=E5=A2=9E=E5=8A=A0isCollection?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/model/entry/EntryItem.java | 3 +++ .../gitee/qdbp/able/model/entry/ListEntryItem.java | 5 +++++ .../com/gitee/qdbp/able/model/entry/MapEntryItem.java | 5 +++++ .../gitee/qdbp/able/model/entry/ObjectEntryItem.java | 5 +++++ .../gitee/qdbp/able/model/entry/ObjectsEntryItem.java | 5 +++++ .../qdbp/able/model/entry/ReadonlyEntryItem.java | 11 +++++++++-- tools/pom.xml | 2 +- 7 files changed, 33 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java index ae742bb..f8751fe 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/EntryItem.java @@ -18,6 +18,9 @@ public interface EntryItem { /** 名称, path的最后一段, 如 [1] **/ String getName(); + /** 是不是集合对象 **/ + boolean isCollection(); + /** 值 **/ Object getValue(); diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java index 64f9cd8..fd74a73 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java @@ -21,6 +21,11 @@ public class ListEntryItem extends BaseEntryItem { this.list = list; } + @Override + public boolean isCollection() { + return true; + } + public ListEntryItem init(String path, String name, int index, Object value) { super.init(path, name, value); this.index = index; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java index 05df397..9a243fb 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java @@ -17,6 +17,11 @@ public class MapEntryItem extends BaseEntryItem { this.map = map; } + @Override + public boolean isCollection() { + return false; + } + public MapEntryItem init(String key, String name, Object value) { super.init(key, name, value); return this; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java index f495dee..c7b7c68 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java @@ -19,6 +19,11 @@ public class ObjectEntryItem extends BaseEntryItem { this.object = object; } + @Override + public boolean isCollection() { + return false; + } + public ObjectEntryItem init(String key, String name, Object value) { super.init(key, name, value); return this; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java index 32fe937..d2ad533 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java @@ -18,6 +18,11 @@ public class ObjectsEntryItem extends BaseEntryItem { this.object = object; } + @Override + public boolean isCollection() { + return true; + } + public ObjectsEntryItem init(String path, String name, int index, Object value) { super.init(path, name, value); this.index = index; diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java index 232e158..d06902b 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java @@ -14,8 +14,16 @@ public class ReadonlyEntryItem extends BaseEntryItem { private final Object object; - public ReadonlyEntryItem(Object object) { + private final boolean isCollection; + + public ReadonlyEntryItem(Object object, boolean isCollection) { this.object = object; + this.isCollection = isCollection; + } + + @Override + public boolean isCollection() { + return isCollection; } public ReadonlyEntryItem init(String key, String name, Object value) { @@ -29,5 +37,4 @@ public class ReadonlyEntryItem extends BaseEntryItem { throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION) .setDetails("Cannot set field value for " + className + ", --> " + key); } - } \ No newline at end of file diff --git a/tools/pom.xml b/tools/pom.xml index e20e132..4da9f84 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230531 + 5.6.230618 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 52c5680ece887beb8c5f00733984c9fec426ae0f Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:43:15 +0800 Subject: [PATCH 41/82] =?UTF-8?q?eachMap=E5=A2=9E=E5=8A=A0isCollection?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/utils/ReflectTools.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index a22f2d9..69ce971 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -390,7 +390,7 @@ public abstract class ReflectTools { for (Object item : iterable) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(iterable).init(path, name, item)); + results.add(new ReadonlyEntryItem(iterable, true).init(path, name, item)); } } else if (fieldValue instanceof Iterator) { Iterator iterator = (Iterator) fieldValue; @@ -398,7 +398,8 @@ public abstract class ReflectTools { while (iterator.hasNext()) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(iterator).init(path, name, iterator.next())); + Object next = iterator.next(); + results.add(new ReadonlyEntryItem(iterator, true).init(path, name, next)); } } else if (fieldValue instanceof Enumeration) { Enumeration enumeration = (Enumeration) fieldValue; @@ -406,7 +407,8 @@ public abstract class ReflectTools { while (enumeration.hasMoreElements()) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(enumeration).init(path, name, enumeration.nextElement())); + Object next = enumeration.nextElement(); + results.add(new ReadonlyEntryItem(enumeration, true).init(path, name, next)); } } else { results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); @@ -419,6 +421,7 @@ public abstract class ReflectTools { private static EntryItem newObjectEntryItem(Object parent, String parentPath, boolean parentList, String fieldName, Object fieldValue) { if (!parentList) { + // 上级不是list String path = concatFieldPaths(parentPath, fieldName); if (parent instanceof Map) { return new MapEntryItem((Map) parent).init(path, fieldName, fieldValue); @@ -426,6 +429,7 @@ public abstract class ReflectTools { return new ObjectEntryItem(parent).init(path, fieldName, fieldValue); } } else { + // 上级是list, fieldName就应该是序号, 可以解析为数字 Integer index = ConvertTools.toInteger(fieldName, null); String name = "[" + fieldName + "]"; String path = concatFieldPaths(parentPath, name); @@ -434,7 +438,7 @@ public abstract class ReflectTools { } else if (index != null && parent.getClass().isArray()) { return new ObjectsEntryItem(parent).init(path, name, index, fieldValue); } else { - return new ReadonlyEntryItem(parent).init(path, name, fieldValue); + return new ReadonlyEntryItem(parent, true).init(path, name, fieldValue); } } } -- Gitee From 251b1942de1aa358bb79700e9dced7b330d244ed Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:43:51 +0800 Subject: [PATCH 42/82] =?UTF-8?q?ReflectTools=E5=A2=9E=E5=8A=A0findMethods?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ReflectTools.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 69ce971..07851a8 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -1102,6 +1102,56 @@ public abstract class ReflectTools { return buffer.toString(); } + /** + * 查找类的所有方法 + * + * @param clazz 类 + * @return 方法列表 + */ + public static List findAllMethods(Class clazz) { + return doFindMethods(clazz, null); + } + + /** + * 按方法名查找方法对象 + * + * @param clazz 类 + * @param methodName 方法名 + * @return 方法列表 + */ + public static List findMethods(Class clazz, String methodName) { + return doFindMethods(clazz, methodName); + } + + private static List doFindMethods(Class clazz, String methodName) { + List result = new ArrayList<>(); + Class temp = clazz; + while (temp != null && temp != Object.class) { + Method[] declaredMethods = temp.getDeclaredMethods(); + List methods = new ArrayList<>(); + for (Method method : declaredMethods) { + if (Modifier.isStatic(method.getModifiers())) { + continue; // 去掉静态方法 + } + if (Modifier.isAbstract(method.getModifiers())) { + continue; // 去掉抽象方法 + } + if (!Modifier.isPublic(method.getModifiers())) { + continue; // 去掉非公开的方法 + } + if (methodName == null || methodName.equals(method.getName())) { + methods.add(method); + } + } + if (!methods.isEmpty()) { + // 父类字段放在前面 + result.addAll(0, methods); + } + temp = temp.getSuperclass(); + } + return result; + } + /** * 查找无参数的方法 * -- Gitee From 983ebfa8158c79347ace8dde5a92308051c58fdf Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:46:27 +0800 Subject: [PATCH 43/82] =?UTF-8?q?ConvertTools=E7=9A=84toList=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20/=20copyObject=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BAd?= =?UTF-8?q?eepCopyObject?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ConvertTools.java | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 05a4177..27510b5 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -216,13 +216,15 @@ public class ConvertTools { * @return 转换后的List, 如果array=null将返回空List */ @SafeVarargs + @SuppressWarnings("all") public static List toList(C... array) { if (array == null) { return new ArrayList<>(); } else { - // JDK1.7必须强转, JDK1.8不需要 - @SuppressWarnings("all") - List temp = (List) new ArrayList<>(Arrays.asList(array)); + List temp = new ArrayList<>(); + for (C item : array) { + temp.add(item); + } return temp; } } @@ -251,14 +253,16 @@ public class ConvertTools { * @return 转换后的Set, 如果array=null将返回空Set */ @SafeVarargs - @SuppressWarnings("unchecked") + @SuppressWarnings("all") public static Set toSet(C... array) { if (array == null) { return new HashSet<>(); } else { - Set list = new HashSet<>(Arrays.asList(array)); - // JDK1.7必须强转, JDK1.8不需要 - return (Set) list; + Set temp = new LinkedHashSet<>(); + for (C item : array) { + temp.add(item); + } + return temp; } } @@ -285,7 +289,7 @@ public class ConvertTools { * @return Map */ public static Map toKeyMaps(String... keys) { - Map map = new HashMap<>(); + Map map = new LinkedHashMap<>(); if (keys != null) { for (String item : keys) { String[] array = StringTools.split(item, ','); @@ -304,8 +308,9 @@ public class ConvertTools { * @param strings KEY * @return Map */ + @SuppressWarnings("all") public static Map toCharMaps(String... strings) { - Map map = new HashMap<>(); + Map map = new LinkedHashMap<>(); if (strings != null) { for (String string : strings) { char[] chars = string.toCharArray(); @@ -347,9 +352,9 @@ public class ConvertTools { @SuppressWarnings("unchecked") public static Map toMap(Collection array, V value) { if (array == null) { - return new HashMap<>(); + return new LinkedHashMap<>(); } else { - Map map = new HashMap<>(); + Map map = new LinkedHashMap<>(); for (C field : array) { map.put(field, value); } @@ -1675,7 +1680,17 @@ public class ConvertTools { } /** - * 复制对象
+ * 深度复制对象 + * + * @deprecated 修改方法名, 此方法名不能描述功能, 改为 {@linkplain #deepCopyObject(Object)} + */ + @Deprecated + public static T copyObject(T value) { + return deepCopyObject(value); + } + + /** + * 深度复制对象
* 调用Copyable的copy()方法进行复制
* List/Set/Map容器将会循环递归复制其中的内容
* @@ -1684,8 +1699,8 @@ public class ConvertTools { * @throws IllegalArgumentException 如果value既不是原生对象也不是容器对象, 又没有实现Copyable接口, 将会抛出异常 * @param 对象类型 */ - public static T copyObject(T value) { - T result = doCopyObject(value); + public static T deepCopyObject(T value) { + T result = doDeepCopyObject(value); if (result != null && result == value) { if (value instanceof Copyable || ReflectTools.isPrimitive(value.getClass(), false)) { return result; @@ -1698,7 +1713,7 @@ public class ConvertTools { } @SuppressWarnings("unchecked") - private static T doCopyObject(T value) { + private static T doDeepCopyObject(T value) { if (value == null) { return null; } @@ -1709,7 +1724,7 @@ public class ConvertTools { List older = (List) value; List newer = new ArrayList<>(); for (Object o : older) { - newer.add(doCopyObject(o)); + newer.add(doDeepCopyObject(o)); } return (T) newer; } @@ -1724,7 +1739,7 @@ public class ConvertTools { } Set older = (Set) value; for (Object o : older) { - newer.add(doCopyObject(o)); + newer.add(doDeepCopyObject(o)); } return (T) newer; } @@ -1732,7 +1747,7 @@ public class ConvertTools { MapPlus newer = new MapPlus(); MapPlus older = (MapPlus) value; for (Map.Entry entry : older.entrySet()) { - newer.put(entry.getKey(), doCopyObject(entry.getValue())); + newer.put(entry.getKey(), doDeepCopyObject(entry.getValue())); } return (T) newer; } @@ -1745,7 +1760,7 @@ public class ConvertTools { } Map older = (Map) value; for (Map.Entry entry : older.entrySet()) { - newer.put(entry.getKey(), doCopyObject(entry.getValue())); + newer.put(entry.getKey(), doDeepCopyObject(entry.getValue())); } return (T) newer; } -- Gitee From 3a922aea56efea1cf013892acd5db4475eeadf93 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:47:24 +0800 Subject: [PATCH 44/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0isCollection/isPlainObj?= =?UTF-8?q?ect=E5=88=A4=E6=96=AD=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/VerifyTools.java | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java index 3baab94..d233f8a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java @@ -3,6 +3,7 @@ package com.gitee.qdbp.tools.utils; import java.lang.reflect.Array; import java.util.Collection; import java.util.Enumeration; +import java.util.Iterator; import java.util.Map; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; @@ -165,7 +166,7 @@ public class VerifyTools { * @return 是否全都为空 */ public static boolean isAllBlank(Object... objects) { - if (objects == null || objects.length == 0) { + if (objects == null) { return true; } @@ -188,6 +189,47 @@ public class VerifyTools { return !isAnyBlank(objects); } + /** + * 判断是不是集合对象, 能转换为list就是集合对象 + * + * @param object 目标对象 + * @return 是否集合对象 + * @see ConvertTools#parseList(Object) + */ + public static boolean isCollection(Object object) { + if (object == null) { + return false; + } else if (object.getClass().isArray()) { + return true; + } else if (object instanceof Collection) { + return true; + } else if (object instanceof Iterator) { + return true; + } else if (object instanceof Iterable) { + return true; + } else if (object instanceof Enumeration) { + return true; + } else { + return false; + } + } + + /** + * 判断是不是普通对象, 能转换为map就是普通对象, 不能是原始类型也不能是列表 + * + * @param object 目标对象 + * @return 是否普通对象 + */ + public static boolean isPlainObject(Object object) { + if (object == null) { + return false; + } else if (ReflectTools.isPrimitive(object.getClass(), false)) { + return false; + } else { + return !isCollection(object); + } + } + /** * 判断对象是否存在于列表中 * @@ -197,7 +239,7 @@ public class VerifyTools { */ @SafeVarargs public static boolean isExists(T object, T... objects) { - if (objects == null || objects.length == 0) { + if (objects == null) { return false; } for (Object i : objects) { -- Gitee From 4ba067aba26079870bd34478bde60f9dadab0b3d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:48:51 +0800 Subject: [PATCH 45/82] =?UTF-8?q?YamlTools=E5=A4=A7=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ConvertTools.java | 26 --- .../com/gitee/qdbp/tools/utils/YamlTools.java | 183 ++++++++++++++++-- 2 files changed, 168 insertions(+), 41 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 27510b5..8ba11a7 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -111,8 +111,6 @@ public class ConvertTools { return list; } else if (object.getClass().isArray()) { return new ArrayList<>(Arrays.asList((Object[]) object)); - } else if (object instanceof Map && isListLikeness((Map) object)) { - return new ArrayList<>(((Map) object).values()); } else if (object instanceof Iterable) { List values = new ArrayList<>(); Iterable iterable = (Iterable) object; @@ -139,30 +137,6 @@ public class ConvertTools { } } - // 所有key是从0开始的连续整数, 就判定为类似数组 - // Yaml的数组有时会解析为key为序号的map, 因此加一个特殊处理 - private static boolean isListLikeness(Map map) { - if (map.isEmpty() || !(map instanceof LinkedHashMap)) { - return false; - } - int index = 0; - for (Map.Entry entry : map.entrySet()) { - Object key = entry.getKey(); - if (key instanceof Integer) { - if (key.equals(index++)) { - continue; - } - } else if (key instanceof String && StringTools.isDigit((String) key)) { - if (Integer.parseInt((String) key) == index++) { - continue; - } - } - return false; - } - // 所有key是从0开始的连续整数 - return true; - } - /** * 将对象解析为列表 * diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java index e86d559..2ca6582 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java @@ -1,10 +1,14 @@ package com.gitee.qdbp.tools.utils; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.model.entry.EachEntry; +import com.gitee.qdbp.able.result.ResultCode; /** * Yaml工具类 @@ -20,41 +24,78 @@ public class YamlTools { /** 将Java对象转换为Yaml字符串 **/ public static String toYamlString(Object object) { - Yaml yaml = createYaml(); - return yaml.dump(object); + if (object == null) { + return null; + } else { + Yaml yaml = createYaml(); + return yaml.dump(object); + } } /** 将Yaml字符串解析为Map对象 **/ public static Map parseAsMap(String string) { + Map map = doParseAsMap(string); + return map != null ? map : new LinkedHashMap<>(); + } + + private static Map doParseAsMap(String string) { + if (string == null) { + return null; + } Yaml yaml = createYaml(); Object result = yaml.load(string); - return JsonTools.beanToMap(result, false, false); + if (result == null) { + return null; + } else if (result instanceof Map) { + Map map = MapTools.toJsonMap((Map) result); + normalizeMap(map); + return map; + } else { + String msg = "Expected format is map yaml, actual result type is {}: {}"; + throw new ServiceException(ResultCode.PARAMETER_VALUE_ERROR) + .setDetails(msg, result.getClass().getSimpleName(), string); + } } /** 将Yaml字符串解析为Map数组 **/ public static List> parseAsMaps(String string) { + List> maps = doParseAsMaps(string); + return maps != null ? maps : new ArrayList<>(); + } + + public static List> doParseAsMaps(String string) { + if (string == null) { + return null; + } Yaml yaml = createYaml(); Object object = yaml.load(string); - List list = ConvertTools.parseList(object); - return JsonTools.beanToMaps(list, false, false); + + if (object == null) { + return null; + } else if (object instanceof Map) { + Map map = MapTools.toJsonMap((Map) object); + normalizeMap(map); + List> list = new ArrayList<>(); + list.add(map); + return list; + } else { + List list = ConvertTools.parseList(object); + List> maps = MapTools.toJsonMaps(list); + normalizeMaps(maps); + return maps; + } } /** 将Yaml字符串解析为Java对象 **/ public static T parseAsObject(String string, Class clazz) { - Yaml yaml = createYaml(); - return yaml.loadAs(string, clazz); + Map map = doParseAsMap(string); + return map == null ? null : JsonTools.mapToBean(map, clazz); } /** 将Yaml字符串解析为Java对象列表 **/ public static List parseAsObjects(String string, Class clazz) { - Yaml yaml = createYaml(); - Object object = yaml.load(string); - List list = ConvertTools.parseList(object); - List results = new ArrayList<>(); - for (Object item : list) { - results.add(JsonTools.convert(item, clazz)); - } - return results; + List> maps = doParseAsMaps(string); + return maps == null ? null : JsonTools.mapToBeans(maps, clazz); } private static Yaml createYaml() { @@ -65,4 +106,116 @@ public class YamlTools { options.setMaxAliasesForCollections(Integer.MAX_VALUE); return new Yaml(options); } + + /** + * 规范化处理
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param map Map对象 + */ + public static void normalizeMap(Map map) { + MapTools.each(map, LIST_LIKENESS_CLEANER); + } + + /** + * 规范化处理
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param maps Map列表 + */ + public static void normalizeMaps(List> maps) { + MapTools.each(maps, LIST_LIKENESS_CLEANER); + } + + /** + * 规范化成为一个新副本
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param map Map对象 + * @return 返回Map对象的副本 + */ + public static Map normalizeAsCopy(Map map) { + Map newer = ConvertTools.deepCopyObject(map); + MapTools.each(newer, LIST_LIKENESS_CLEANER); + return newer; + } + + /** + * 规范化成为一个新副本
+ * Yaml中的数组有时会解析成以数字序号为key的map, 因此加一个规范化处理
+ * { "0": "string1", "1": "string2", "2": "string3" }
+ * 处理成: [ "string1", "string2", "string3" ]
+ * + * @param maps Map列表 + * @return 返回Map列表的副本 + */ + public static List> normalizeAsCopy(List> maps) { + List> newer = ConvertTools.deepCopyObject(maps); + MapTools.each(newer, LIST_LIKENESS_CLEANER); + return newer; + } + + /** + * 将对象解析为列表
+ * 如果是以连续数字序号为key的map, 将返回map.values() + * + * @param object 待解析的对象 + * @return 解析后的列表, 如果object=null将返回空列表 + * @since 5.6.230618 + */ + public static List parseList(Object object) { + if (object instanceof Map) { + Map map = (Map) object; + if (isListLikeness(map)) { + return new ArrayList<>(map.values()); + } + } + return ConvertTools.parseList(object); + } + + // 所有key是从0开始的连续整数, 就判定为类似数组 + // Yaml的数组有时会解析成以key为序号的map, 因此加一个特殊处理 + private static boolean isListLikeness(Map map) { + if (map.isEmpty() || !(map instanceof LinkedHashMap)) { + return false; + } + int index = 0; + for (Map.Entry entry : map.entrySet()) { + Object key = entry.getKey(); + if (key instanceof Integer) { + if (key.equals(index++)) { + continue; + } + } else if (key instanceof String && StringTools.isDigit((String) key)) { + if (Integer.parseInt((String) key) == index++) { + continue; + } + } + return false; + } + // 所有key是从0开始的连续整数 + return true; + } + + private static final ListLikenessCleaner LIST_LIKENESS_CLEANER = new ListLikenessCleaner(); + + /** Yaml的数组有时会解析成以key为序号的map, 因此加一个特殊处理 **/ + private static class ListLikenessCleaner implements MapTools.EachInterceptor { + @Override + public void intercept(EachEntry entry) { + if (entry.getValue() instanceof Map) { + Map map = (Map) entry.getValue(); + if (isListLikeness(map)) { + ArrayList list = new ArrayList<>((map).values()); + entry.setValue(list); + } + } + } + } } -- Gitee From 27b28104a0832ee9b9d230fc52b95a45851bf93a Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:50:45 +0800 Subject: [PATCH 46/82] =?UTF-8?q?YamlTools=E4=BC=98=E5=8C=96=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/tools/test/ConvertToolsTest.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java index 9beb3da..e958b45 100644 --- a/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java +++ b/test/qdbp-tools-test-jdk7/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java @@ -7,6 +7,7 @@ import java.util.Map; import org.testng.Assert; import org.testng.annotations.Test; import com.gitee.qdbp.tools.utils.ConvertTools; +import com.gitee.qdbp.tools.utils.YamlTools; /** * 数据转换工具类 @@ -66,10 +67,18 @@ public class ConvertToolsTest { map.put(0, "A"); map.put(1, "B"); map.put(2, "C"); - List objects = ConvertTools.parseList(map); - Assert.assertEquals(objects.size(), 3); - Assert.assertEquals(objects.get(0), "A"); - System.out.println(objects); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } } @Test @@ -78,10 +87,18 @@ public class ConvertToolsTest { map.put("0", "A"); map.put("1", "B"); map.put("2", "C"); - List objects = ConvertTools.parseList(map); - Assert.assertEquals(objects.size(), 3); - Assert.assertEquals(objects.get(0), "A"); - System.out.println(objects); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } } @Test -- Gitee From 89988de75b1477454852121813b2f86ed8d8699b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 18 Jun 2023 23:51:09 +0800 Subject: [PATCH 47/82] qdbp-5.6.230618 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8617ca2..8057150 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230531 + 5.6.230618 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230531 + 5.6.230618 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index e54323f..6d25ce4 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230531 + 5.6.230618 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index f9e6e39..203373d 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230531 + 5.6.230618 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230531 + 5.6.230618 diff --git a/test/pom.xml b/test/pom.xml index a12e98c..2557c87 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230531 + 5.6.230618 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 96c8631..61d7525 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 935654e..8f4e52a 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 33e7325..ca03bb9 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 0b110e3..d6fc2cc 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 4271084..334a45c 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230531 + 5.6.230618 qdbp-tools-test-jdk7 -- Gitee From a317746a1c61b8963d2773625fca24672a042386 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:43:56 +0800 Subject: [PATCH 48/82] explicit type argument string on jdk7 --- .../src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java index 2ca6582..b643dfb 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/utils/YamlTools.java @@ -35,7 +35,8 @@ public class YamlTools { /** 将Yaml字符串解析为Map对象 **/ public static Map parseAsMap(String string) { Map map = doParseAsMap(string); - return map != null ? map : new LinkedHashMap<>(); + // explicit type argument string on jdk7 + return map != null ? map : new LinkedHashMap(); } private static Map doParseAsMap(String string) { @@ -60,7 +61,8 @@ public class YamlTools { /** 将Yaml字符串解析为Map数组 **/ public static List> parseAsMaps(String string) { List> maps = doParseAsMaps(string); - return maps != null ? maps : new ArrayList<>(); + // explicit type argument string on jdk7 + return maps != null ? maps : new ArrayList>(); } public static List> doParseAsMaps(String string) { -- Gitee From 25e71315bb9f20850a9cadbbbbbe8c7c3481e7c5 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:45:22 +0800 Subject: [PATCH 49/82] test-jdk8 --- test/pom.xml | 1 + test/qdbp-tools-test-jdk8/pom.xml | 104 ++++++++++++++++ .../com/gitee/qdbp/able/beans/TreeNode.java | 0 .../gitee/qdbp/able/beans/TreeNodesTest.java | 0 .../qdbp/tools/test/ConvertToolsTest.java | 116 ++++++++++++++++++ .../gitee/qdbp/tools/test/EachMapTest.java | 101 +++++++++++++++ .../src/test/resources/logback.xml | 51 ++++++++ .../src/test/resources/testng.xml | 9 ++ 8 files changed, 382 insertions(+) create mode 100644 test/qdbp-tools-test-jdk8/pom.xml rename {tools => test/qdbp-tools-test-jdk8}/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java (100%) rename {tools => test/qdbp-tools-test-jdk8}/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java (100%) create mode 100644 test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java create mode 100644 test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java create mode 100644 test/qdbp-tools-test-jdk8/src/test/resources/logback.xml create mode 100644 test/qdbp-tools-test-jdk8/src/test/resources/testng.xml diff --git a/test/pom.xml b/test/pom.xml index 2557c87..be34dd9 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -25,6 +25,7 @@ qdbp-json-test-gson qdbp-json-test-jackson qdbp-tools-test-jdk7 + qdbp-tools-test-jdk8 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml new file mode 100644 index 0000000..d652967 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -0,0 +1,104 @@ + + + 4.0.0 + + + com.gitee.qdbp + qdbp-json-test + 5.6.230618 + + + qdbp-tools-test-jdk8 + jar + https://gitee.com/qdbp/qdbp-able/ + qdbp tools test + + + 8 + 8 + + + + + + com.gitee.qdbp + qdbp-able + ${project.version} + + + com.gitee.qdbp + qdbp-json + ${project.version} + + + com.gitee.qdbp + qdbp-tools + ${project.version} + + + + com.alibaba + fastjson + 1.2.16 + + + + org.slf4j + slf4j-api + 1.7.25 + + + + org.slf4j + jcl-over-slf4j + 1.7.25 + + + org.slf4j + log4j-over-slf4j + 1.7.25 + + + ch.qos.logback + logback-core + 1.2.3 + + + ch.qos.logback + logback-classic + 1.2.3 + + + + org.testng + testng + 6.14.3 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + ${maven.compiler.source} + ${maven.compiler.source} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + + src/test/resources/testng.xml + + + + + + diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java similarity index 100% rename from tools/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java rename to test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNode.java diff --git a/tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java similarity index 100% rename from tools/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java rename to test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java diff --git a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java new file mode 100644 index 0000000..e958b45 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/ConvertToolsTest.java @@ -0,0 +1,116 @@ +package com.gitee.qdbp.tools.test; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.testng.Assert; +import org.testng.annotations.Test; +import com.gitee.qdbp.tools.utils.ConvertTools; +import com.gitee.qdbp.tools.utils.YamlTools; + +/** + * 数据转换工具类 + * + * @author zhaohuihua + * @version 20230129 + */ +@Test +public class ConvertToolsTest { + + @Test + public void test1() { + long value = ConvertTools.toLong("1024 * 1024"); + Assert.assertEquals(value, 1024 * 1024); + } + + @Test + public void test2() { + long value = ConvertTools.toLong("10:20:30.456"); + Assert.assertEquals(value, 10*60*60*1000+20*60*1000+30*1000+456); + } + + @Test + public void test3() { + long value = ConvertTools.toLong("16KB"); + Assert.assertEquals(value, 16*1024); + } + + @Test + public void test4() { + long value = ConvertTools.toLong("1024"); + Assert.assertEquals(value, 1024); + } + + @Test + public void test5() { + long value = ConvertTools.toLong("-1024"); + Assert.assertEquals(value, -1024); + } + + @Test + public void test6() { + try { + // Duration since jdk8 + Class.forName("java.time.Duration"); + + long value = ConvertTools.toLong("PT15H"); + Assert.assertEquals(value, 15*60*60*1000); + } catch (ClassNotFoundException ignore) { + System.out.println("test6 skipped on jdk7 ......"); + } + } + + @Test + public void test7() { + Map map = new LinkedHashMap<>(); + map.put(0, "A"); + map.put(1, "B"); + map.put(2, "C"); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } + } + + @Test + public void test8() { + Map map = new LinkedHashMap<>(); + map.put("0", "A"); + map.put("1", "B"); + map.put("2", "C"); + { + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertEquals(objects.get(0), map); + System.out.println(objects); + } + { + List objects = YamlTools.parseList(map); + Assert.assertEquals(objects.size(), 3); + Assert.assertEquals(objects.get(0), "A"); + System.out.println(objects); + } + } + + @Test + public void test9() { + Map map = new HashMap<>(); + map.put(0, "A"); + map.put(1, "B"); + map.put(2, "C"); + List objects = ConvertTools.parseList(map); + Assert.assertEquals(objects.size(), 1); + Assert.assertSame(objects.get(0), map); + Assert.assertEquals(objects.get(0).getClass(), HashMap.class); + System.out.println(objects); + } +} diff --git a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java new file mode 100644 index 0000000..775c159 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/tools/test/EachMapTest.java @@ -0,0 +1,101 @@ +package com.gitee.qdbp.tools.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.testng.Assert; +import org.testng.annotations.Test; +import com.gitee.qdbp.able.model.entry.EachEntry; +import com.gitee.qdbp.tools.beans.MapPlus; +import com.gitee.qdbp.tools.utils.JsonTools; +import com.gitee.qdbp.tools.utils.MapTools; +import com.gitee.qdbp.tools.utils.ReflectTools; + +/** + * 深度遍历Map测试 + * + * @author zhaohuihua + * @version 20230215 + */ +@Test +public class EachMapTest { + + @Test + public void test() { + List> addresses = new ArrayList<>(); + MapPlus address = new MapPlus(); + address.put("city", "nanjing"); + address.put("phones", Arrays.asList("1301112222", "13044445555")); + addresses.add(address); + + MapPlus root = new MapPlus(); + root.put("entity.user.userName", "test1"); + root.put("entity.user.address", addresses); + System.out.println(JsonTools.toLogString(root)); + Assert.assertEquals(root.size(), 1); + Map entity = root.getSubMap("entity"); + System.out.println(entity.getClass()); + Assert.assertEquals(entity.getClass(), MapPlus.class); + + List> list = root.getSubMaps("entity.user.address"); + System.out.println(list.getClass()); + Assert.assertEquals(list.size(), 1); + Assert.assertSame(list, addresses); + Map address1 = list.get(0); + System.out.println(address1.getClass()); + Assert.assertEquals(address1.getClass(), MapPlus.class); + Assert.assertSame(address1, address); + + System.out.println("-------------------------------"); + + final Map result = new LinkedHashMap<>(); + MapTools.each(root, new MapTools.EachInterceptor() { + @Override + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); + if (fieldValue == null) { + result.put(fieldPath, null); + } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + result.put(fieldPath, fieldValue); + } + } + }); + System.out.println(JsonTools.toLogString(result)); + Assert.assertTrue(result.containsKey("entity.user.userName")); + Assert.assertTrue(result.containsKey("entity.user.address[0].city")); + Assert.assertTrue(result.containsKey("entity.user.address[0].phones[0]")); + Assert.assertTrue(result.containsKey("entity.user.address[0].phones[1]")); + + Assert.assertEquals(result.get("entity.user.userName"), "test1"); + Assert.assertEquals(result.get("entity.user.address[0].city"), "nanjing"); + Assert.assertEquals(result.get("entity.user.address[0].phones[0]"), "1301112222"); + Assert.assertEquals(result.get("entity.user.address[0].phones[1]"), "13044445555"); + + System.out.println("-------------------------------"); + + final Map aResult = new LinkedHashMap<>(); + MapTools.each(addresses, new MapTools.EachInterceptor() { + @Override + public void intercept(EachEntry entry) { + String fieldPath = entry.getKey(); + Object fieldValue = entry.getValue(); + if (fieldValue == null) { + aResult.put(fieldPath, null); + } else if (ReflectTools.isPrimitive(fieldValue.getClass(), false)) { + aResult.put(fieldPath, fieldValue); + } + } + }); + System.out.println(JsonTools.toLogString(aResult)); + Assert.assertTrue(aResult.containsKey("[0].city")); + Assert.assertTrue(aResult.containsKey("[0].phones[0]")); + Assert.assertTrue(aResult.containsKey("[0].phones[1]")); + + Assert.assertEquals(aResult.get("[0].city"), "nanjing"); + Assert.assertEquals(aResult.get("[0].phones[0]"), "1301112222"); + Assert.assertEquals(aResult.get("[0].phones[1]"), "13044445555"); + } +} diff --git a/test/qdbp-tools-test-jdk8/src/test/resources/logback.xml b/test/qdbp-tools-test-jdk8/src/test/resources/logback.xml new file mode 100644 index 0000000..acff406 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/resources/logback.xml @@ -0,0 +1,51 @@ + + + + + + + + ${pattern.stdout} + + + + ../logs/qdbp-json-test-jackson.log + + + ../logs/qdbp-json-test-jackson-%d{yyyyMMdd}-%i.log + 30 + + + 50MB + + + + ${pattern.normal} + + + + + 0 + + 1024 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/qdbp-tools-test-jdk8/src/test/resources/testng.xml b/test/qdbp-tools-test-jdk8/src/test/resources/testng.xml new file mode 100644 index 0000000..3f55d76 --- /dev/null +++ b/test/qdbp-tools-test-jdk8/src/test/resources/testng.xml @@ -0,0 +1,9 @@ + + + + + + + + + -- Gitee From 9468cb70443fc98fadce8228babe17c55be2fc6d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:47:26 +0800 Subject: [PATCH 50/82] =?UTF-8?q?EachEntry=E5=8E=BB=E6=8E=89init=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F,=E6=94=B9=E4=B8=BA=E5=AF=B9=E6=AF=8F=E4=B8=80?= =?UTF-8?q?=E9=A1=B9=E8=BF=9B=E8=A1=8C=E5=AE=9E=E4=BE=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/able/model/entry/BaseEntryItem.java | 19 ++++++++++---- .../qdbp/able/model/entry/ListEachEntry.java | 10 ++----- .../qdbp/able/model/entry/ListEntryItem.java | 15 +++-------- .../qdbp/able/model/entry/MapEachEntry.java | 10 ++----- .../qdbp/able/model/entry/MapEntryItem.java | 13 ++-------- .../able/model/entry/ObjectEntryItem.java | 13 ++-------- .../able/model/entry/ObjectsEntryItem.java | 15 +++-------- .../able/model/entry/ReadonlyEntryItem.java | 16 ++---------- .../com/gitee/qdbp/tools/utils/MapTools.java | 26 +++++++++---------- .../gitee/qdbp/tools/utils/ReflectTools.java | 20 +++++++------- 10 files changed, 52 insertions(+), 105 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java index 603c4f8..1c4496c 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/BaseEntryItem.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.able.model.entry; import java.util.regex.Pattern; +import com.gitee.qdbp.tools.utils.VerifyTools; /** * 基础字段项变量 @@ -13,17 +14,17 @@ abstract class BaseEntryItem implements EntryItem, EntryItem.Resetable { private static final Pattern CLEAR_NUMBER_INDEX = Pattern.compile("(^\\[[+-]?\\d+]\\.|\\[[+-]?\\d+])"); - protected String key; - protected String name; + protected final String key; + protected final String name; + protected String fields; protected Object value; protected boolean handled; - protected BaseEntryItem init(String key, String name, Object value) { + BaseEntryItem(String key, String name, Object value) { this.key = key; this.name = name; this.value = value; this.handled = false; - return this; } @Override @@ -33,7 +34,15 @@ abstract class BaseEntryItem implements EntryItem, EntryItem.Resetable { @Override public String getFields() { - return key == null ? null : CLEAR_NUMBER_INDEX.matcher(key).replaceAll(""); + if (this.fields == null) { + this.fields = key == null ? null : CLEAR_NUMBER_INDEX.matcher(key).replaceAll(""); + } + return this.fields; + } + + @Override + public final boolean isCollection() { + return VerifyTools.isCollection(this.value); } @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java index 90ed1fd..cb6d831 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEachEntry.java @@ -15,17 +15,11 @@ public class ListEachEntry extends ListEntryItem implements EachEntry, EachEntry private boolean skipAfter; private boolean skipEnter; - public ListEachEntry(Collection list) { - super(list); - } - - @Override - public ListEachEntry init(String path, String name, int index, Object value) { - super.init(path, name, index, value); + public ListEachEntry(Collection list, String path, String name, int index, Object value) { + super(list, path, name, index, value); this.skipAll = false; this.skipAfter = false; this.skipEnter = false; - return this; } public void skipAll() { diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java index fd74a73..74c86e5 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ListEntryItem.java @@ -15,21 +15,12 @@ import com.gitee.qdbp.able.result.ResultCode; public class ListEntryItem extends BaseEntryItem { private final Collection list; - private int index; + private final int index; - public ListEntryItem(Collection list) { + public ListEntryItem(Collection list, String path, String name, int index, Object value) { + super(path, name, value); this.list = list; - } - - @Override - public boolean isCollection() { - return true; - } - - public ListEntryItem init(String path, String name, int index, Object value) { - super.init(path, name, value); this.index = index; - return this; } @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java index 8857ae9..f5e0ed7 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEachEntry.java @@ -15,17 +15,11 @@ public class MapEachEntry extends MapEntryItem implements EachEntry, EachEntry.B private boolean skipAfter; private boolean skipEnter; - public MapEachEntry(Map map) { - super(map); - } - - @Override - public MapEachEntry init(String key, String name, Object value) { - super.init(key, name, value); + public MapEachEntry(Map map, String key, String name, Object value) { + super(map, key, name, value); this.skipAll = false; this.skipAfter = false; this.skipEnter = false; - return this; } public void skipAll() { diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java index 9a243fb..acdaa1e 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/MapEntryItem.java @@ -13,20 +13,11 @@ public class MapEntryItem extends BaseEntryItem { private final Map map; - public MapEntryItem(Map map) { + public MapEntryItem(Map map, String key, String name, Object value) { + super(key, name, value); this.map = map; } - @Override - public boolean isCollection() { - return false; - } - - public MapEntryItem init(String key, String name, Object value) { - super.init(key, name, value); - return this; - } - @Override public void resetValue(Object value) { @SuppressWarnings("unchecked") diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java index c7b7c68..32d2f04 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectEntryItem.java @@ -15,20 +15,11 @@ public class ObjectEntryItem extends BaseEntryItem { private final Object object; - public ObjectEntryItem(Object object) { + public ObjectEntryItem(Object object, String key, String name, Object value) { + super(key, name, value); this.object = object; } - @Override - public boolean isCollection() { - return false; - } - - public ObjectEntryItem init(String key, String name, Object value) { - super.init(key, name, value); - return this; - } - @Override public void resetValue(Object value) { if (object != null) { diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java index d2ad533..ccd33dc 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ObjectsEntryItem.java @@ -12,21 +12,12 @@ import java.lang.reflect.Array; public class ObjectsEntryItem extends BaseEntryItem { private final Object object; - private int index; + private final int index; - public ObjectsEntryItem(Object object) { + public ObjectsEntryItem(Object object, String key, String name, int index, Object value) { + super(key, name, value); this.object = object; - } - - @Override - public boolean isCollection() { - return true; - } - - public ObjectsEntryItem init(String path, String name, int index, Object value) { - super.init(path, name, value); this.index = index; - return this; } @Override diff --git a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java index d06902b..81d912d 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/entry/ReadonlyEntryItem.java @@ -14,21 +14,9 @@ public class ReadonlyEntryItem extends BaseEntryItem { private final Object object; - private final boolean isCollection; - - public ReadonlyEntryItem(Object object, boolean isCollection) { + public ReadonlyEntryItem(Object object, String key, String name, Object value) { + super(key, name, value); this.object = object; - this.isCollection = isCollection; - } - - @Override - public boolean isCollection() { - return isCollection; - } - - public ReadonlyEntryItem init(String key, String name, Object value) { - super.init(key, name, value); - return this; } @Override diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index 2a9d216..faa9042 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -885,7 +885,6 @@ public class MapTools { } private static boolean doEachMap(String parentPath, Map map, EachInterceptor interceptor) { - MapEachEntry mapEntry = new MapEachEntry(map); for (Map.Entry item : map.entrySet()) { if (item.getKey() == null || item.getKey().trim().length() == 0) { continue; @@ -893,20 +892,20 @@ public class MapTools { String fieldName = item.getKey(); String fieldPath = StringTools.concat('.', parentPath, fieldName); Object fieldValue = item.getValue(); - mapEntry.init(fieldPath, fieldName, fieldValue); + MapEachEntry entry = new MapEachEntry(map, fieldPath, fieldName, fieldValue); // 调用拦截函数 - interceptor.intercept(mapEntry); - if (mapEntry.isSkipAll()) { + interceptor.intercept(entry); + if (entry.isSkipAll()) { // 跳过全部 return false; } - if (mapEntry.isSkipAfter()) { + if (entry.isSkipAfter()) { // 跳过当前容器中的后续字段 break; } - if (!mapEntry.isSkipEnter() && mapEntry.getValue() != null) { + if (!entry.isSkipEnter() && entry.getValue() != null) { // 递归进入字段内部 - boolean isContinue = doEnterEntryValue(mapEntry, interceptor); + boolean isContinue = doEnterEntryValue(entry, interceptor); if (!isContinue) { return false; } @@ -916,24 +915,23 @@ public class MapTools { } private static boolean doEachList(String parentPath, List list, EachInterceptor interceptor) { - ListEachEntry listEntry = new ListEachEntry(list); for (int i = 0; i < list.size(); i++) { String childName = "[" + i + "]"; String childPath = ReflectTools.concatFieldPaths(parentPath, childName); Object childValue = list.get(i); - listEntry.init(childPath, childName, i, childValue); + ListEachEntry entry = new ListEachEntry(list, childPath, childName, i, childValue); // 调用拦截函数 - interceptor.intercept(listEntry); - if (listEntry.isSkipAll()) { + interceptor.intercept(entry); + if (entry.isSkipAll()) { // 跳过全部 return false; } - if (listEntry.isSkipAfter()) { + if (entry.isSkipAfter()) { // 跳过当前容器中的后续字段 break; } - if (!listEntry.isSkipEnter() && listEntry.getValue() != null) { - boolean isContinue = doEnterEntryValue(listEntry, interceptor); + if (!entry.isSkipEnter() && entry.getValue() != null) { + boolean isContinue = doEnterEntryValue(entry, interceptor); if (!isContinue) { return false; } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 07851a8..4aebb58 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -375,14 +375,14 @@ public abstract class ReflectTools { for (int i = 0; i < values.size(); i++) { String name = "[" + i + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ListEntryItem(values).init(path, name, i, values.get(i))); + results.add(new ListEntryItem(values, path, name, i, values.get(i))); } } else if (fieldValue.getClass().isArray()) { Object[] values = (Object[]) fieldValue; for (int i = 0; i < values.length; i++) { String name = "[" + i + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ObjectsEntryItem(values).init(path, name, i, values[i])); + results.add(new ObjectsEntryItem(values, path, name, i, values[i])); } } else if (fieldValue instanceof Iterable) { Iterable iterable = (Iterable) fieldValue; @@ -390,7 +390,7 @@ public abstract class ReflectTools { for (Object item : iterable) { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); - results.add(new ReadonlyEntryItem(iterable, true).init(path, name, item)); + results.add(new ReadonlyEntryItem(iterable, path, name, item)); } } else if (fieldValue instanceof Iterator) { Iterator iterator = (Iterator) fieldValue; @@ -399,7 +399,7 @@ public abstract class ReflectTools { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); Object next = iterator.next(); - results.add(new ReadonlyEntryItem(iterator, true).init(path, name, next)); + results.add(new ReadonlyEntryItem(iterator, path, name, next)); } } else if (fieldValue instanceof Enumeration) { Enumeration enumeration = (Enumeration) fieldValue; @@ -408,7 +408,7 @@ public abstract class ReflectTools { String name = "[" + (i++) + "]"; String path = concatFieldPaths(parentPath, realFieldName, name); Object next = enumeration.nextElement(); - results.add(new ReadonlyEntryItem(enumeration, true).init(path, name, next)); + results.add(new ReadonlyEntryItem(enumeration, path, name, next)); } } else { results.add(newObjectEntryItem(parent, parentPath, parentList, fieldName, fieldValue)); @@ -424,9 +424,9 @@ public abstract class ReflectTools { // 上级不是list String path = concatFieldPaths(parentPath, fieldName); if (parent instanceof Map) { - return new MapEntryItem((Map) parent).init(path, fieldName, fieldValue); + return new MapEntryItem((Map) parent, path, fieldName, fieldValue); } else { - return new ObjectEntryItem(parent).init(path, fieldName, fieldValue); + return new ObjectEntryItem(parent, path, fieldName, fieldValue); } } else { // 上级是list, fieldName就应该是序号, 可以解析为数字 @@ -434,11 +434,11 @@ public abstract class ReflectTools { String name = "[" + fieldName + "]"; String path = concatFieldPaths(parentPath, name); if (index != null && parent instanceof List) { - return new ListEntryItem((List) parent).init(path, name, index, fieldValue); + return new ListEntryItem((List) parent, path, name, index, fieldValue); } else if (index != null && parent.getClass().isArray()) { - return new ObjectsEntryItem(parent).init(path, name, index, fieldValue); + return new ObjectsEntryItem(parent, path, name, index, fieldValue); } else { - return new ReadonlyEntryItem(parent, true).init(path, name, fieldValue); + return new ReadonlyEntryItem(parent, path, name, fieldValue); } } } -- Gitee From 36927c05705f8d7bf6d2854c49e192af80028634 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 12 Jul 2023 07:50:29 +0800 Subject: [PATCH 51/82] 5.6.230712 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8057150..460a794 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230618 + 5.6.230712 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230618 + 5.6.230712 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 6d25ce4..71da000 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230618 + 5.6.230712 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 203373d..76d9dee 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230618 + 5.6.230712 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230618 + 5.6.230712 diff --git a/test/pom.xml b/test/pom.xml index be34dd9..6c9da77 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230618 + 5.6.230712 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 61d7525..4ffec8e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 8f4e52a..ad9851a 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index ca03bb9..7a5a008 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index d6fc2cc..4c461cc 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 334a45c..5e117a0 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index d652967..e1669bc 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230618 + 5.6.230712 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 4da9f84..5ece174 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230618 + 5.6.230712 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 27397c6b75670ae17970c289dc3320ddf8aac84d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:52:12 +0800 Subject: [PATCH 52/82] =?UTF-8?q?=E4=BF=AE=E6=AD=A3Debugger=E7=B1=BB?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=BD=AC=E6=8D=A2=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java b/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java index 678b411..9e730c2 100644 --- a/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java +++ b/able/src/main/java/com/gitee/qdbp/able/debug/BaseDebugger.java @@ -65,7 +65,7 @@ public abstract class BaseDebugger implements Debugger { buffer.append(format); } else { String fmt = StringTools.replace(format, "{}", "%s"); - Object[] params = new String[args.length]; + Object[] params = new Object[args.length]; for (int i = 0; i < args.length; i++) { Object item = args[i]; if (item instanceof Date) { -- Gitee From 5ddd298962e7c2fe43abf7e1a9880479c470ee0e Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:53:20 +0800 Subject: [PATCH 53/82] =?UTF-8?q?Byte=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/codec/BitConverter.java | 386 ++++++++++++++++++ .../com/gitee/qdbp/tools/codec/BitTools.java | 149 +++++++ 2 files changed, 535 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java diff --git a/able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java b/able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java new file mode 100644 index 0000000..1e07042 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/tools/codec/BitConverter.java @@ -0,0 +1,386 @@ +package com.gitee.qdbp.tools.codec; + +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 数字转字节数组工具类
+ * 来源: 数字转字节数组工具类
+ * + * author: zhuzhongxing + */ +class BitConverter { + + /** + * 以字节数组的形式返回指定的布尔值 + * @param data 一个布尔值 + * @return 长度为 1 的字节数组 + */ + public static byte[] getBytes(boolean data) { + byte[] bytes = new byte[1]; + bytes[0] = (byte) (data ? 1 : 0); + return bytes; + } + + /** + * 以字节数组的形式返回指定的 16 位有符号整数值 + * @param data 要转换的数字 + * @return 长度为 2 的字节数组 + */ + public static byte[] getBytes(short data) { + byte[] bytes = new byte[2]; + if (isLittleEndian()) { + bytes[0] = (byte) (data & 0xff); + bytes[1] = (byte) ((data & 0xff00) >> 8); + } else { + bytes[1] = (byte) (data & 0xff); + bytes[0] = (byte) ((data & 0xff00) >> 8); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的 Unicode 字符值 + * @param data 要转换的字符 + * @return 长度为 2 的字节数组 + */ + public static byte[] getBytes(char data) { + byte[] bytes = new byte[2]; + if (isLittleEndian()) { + bytes[0] = (byte) (data); + bytes[1] = (byte) (data >> 8); + } else { + bytes[1] = (byte) (data); + bytes[0] = (byte) (data >> 8); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的 32 位有符号整数值 + * @param data 要转换的数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] getBytes(int data) { + byte[] bytes = new byte[4]; + if (isLittleEndian()) { + bytes[0] = (byte) (data & 0xff); + bytes[1] = (byte) ((data & 0xff00) >> 8); + bytes[2] = (byte) ((data & 0xff0000) >> 16); + bytes[3] = (byte) ((data & 0xff000000) >> 24); + } else { + bytes[3] = (byte) (data & 0xff); + bytes[2] = (byte) ((data & 0xff00) >> 8); + bytes[1] = (byte) ((data & 0xff0000) >> 16); + bytes[0] = (byte) ((data & 0xff000000) >> 24); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的 64 位有符号整数值 + * @param data 要转换的数字 + * @return 长度为 8 的字节数组 + */ + public static byte[] getBytes(long data) { + byte[] bytes = new byte[8]; + if (isLittleEndian()) { + bytes[0] = (byte) (data & 0xff); + bytes[1] = (byte) ((data >> 8) & 0xff); + bytes[2] = (byte) ((data >> 16) & 0xff); + bytes[3] = (byte) ((data >> 24) & 0xff); + bytes[4] = (byte) ((data >> 32) & 0xff); + bytes[5] = (byte) ((data >> 40) & 0xff); + bytes[6] = (byte) ((data >> 48) & 0xff); + bytes[7] = (byte) ((data >> 56) & 0xff); + } else { + bytes[7] = (byte) (data & 0xff); + bytes[6] = (byte) ((data >> 8) & 0xff); + bytes[5] = (byte) ((data >> 16) & 0xff); + bytes[4] = (byte) ((data >> 24) & 0xff); + bytes[3] = (byte) ((data >> 32) & 0xff); + bytes[2] = (byte) ((data >> 40) & 0xff); + bytes[1] = (byte) ((data >> 48) & 0xff); + bytes[0] = (byte) ((data >> 56) & 0xff); + } + return bytes; + } + + /** + * 以字节数组的形式返回指定的单精度浮点值 + * @param data 要转换的数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] getBytes(float data) { + return getBytes(Float.floatToIntBits(data)); + } + + /** + * 以字节数组的形式返回指定的双精度浮点值 + * @param data 要转换的数字 + * @return 长度为 8 的字节数组 + */ + public static byte[] getBytes(double data) { + return getBytes(Double.doubleToLongBits(data)); + } + + /** + * 将指定字符串中的所有字符编码为一个字节序列 + * @param data 包含要编码的字符的字符串 + * @return 一个字节数组,包含对指定的字符集进行编码的结果 + */ + public static byte[] getBytes(String data) { + return data.getBytes(StandardCharsets.UTF_8); + } + + /** + * 将指定字符串中的所有字符编码为一个字节序列 + * @param data 包含要编码的字符的字符串 + * @param charsetName 字符集编码 + * @return 一个字节数组,包含对指定的字符集进行编码的结果 + */ + public static byte[] getBytes(String data, String charsetName) { + return data.getBytes(Charset.forName(charsetName)); + } + + /** + * 返回由字节数组转换来的布尔值 + * @param bytes 字节数组 + * @return 布尔值 + */ + public static boolean toBoolean(byte[] bytes) { + return bytes[0] != 0; + } + + /** + * 返回由字节数组中的指定的一个字节转换来的布尔值 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 布尔值 + */ + public static boolean toBoolean(byte[] bytes, int startIndex) { + return toBoolean(copyFrom(bytes, startIndex, 1)); + } + + /** + * 返回由字节数组转换来的 16 位有符号整数 + * @param bytes 字节数组 + * @return 由两个字节构成的 16 位有符号整数 + */ + public static short toShort(byte[] bytes) { + if (isLittleEndian()) { + return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8))); + } else { + return (short) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8))); + } + } + + /** + * 返回由字节数组中的指定的两个字节转换来的 16 位有符号整数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由两个字节构成的 16 位有符号整数 + */ + public static short toShort(byte[] bytes, int startIndex) { + return toShort(copyFrom(bytes, startIndex, 2)); + } + + /** + * 返回由字节数组转换来的 Unicode 字符 + * @param bytes 字节数组 + * @return 由两个字节构成的字符 + */ + public static char toChar(byte[] bytes) { + if (isLittleEndian()) { + return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8))); + } else { + return (char) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8))); + } + } + + /** + * 返回由字节数组中的指定的两个字节转换来的 Unicode 字符 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由两个字节构成的字符 + */ + public static char toChar(byte[] bytes, int startIndex) { + return toChar(copyFrom(bytes, startIndex, 2)); + } + + /** + * 返回由字节数组转换来的 32 位有符号整数 + * @param bytes 字节数组 + * @return 由四个字节构成的 32 位有符号整数 + */ + public static int toInt(byte[] bytes) { + if (isLittleEndian()) { + return (0xff & bytes[0]) + | (0xff00 & (bytes[1] << 8)) + | (0xff0000 & (bytes[2] << 16)) + | (0xff000000 & (bytes[3] << 24)); + } else { + return (0xff & bytes[3]) + | (0xff00 & (bytes[2] << 8)) + | (0xff0000 & (bytes[1] << 16)) + | (0xff000000 & (bytes[0] << 24)); + } + } + + /** + * 返回由字节数组中的指定的四个字节转换来的 32 位有符号整数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由四个字节构成的 32 位有符号整数 + */ + public static int toInt(byte[] bytes, int startIndex) { + return toInt(copyFrom(bytes, startIndex, 4)); + } + + /** + * 返回由字节数组转换来的 64 位有符号整数 + * @param bytes 字节数组 + * @return 由八个字节构成的 64 位有符号整数 + */ + public static long toLong(byte[] bytes) { + if (isLittleEndian()) { + return (0xffL & (long) bytes[0]) + | (0xff00L & ((long) bytes[1] << 8)) + | (0xff0000L & ((long) bytes[2] << 16)) + | (0xff000000L & ((long) bytes[3] << 24)) + | (0xff00000000L & ((long) bytes[4] << 32)) + | (0xff0000000000L & ((long) bytes[5] << 40)) + | (0xff000000000000L & ((long) bytes[6] << 48)) + | (0xff00000000000000L & ((long) bytes[7] << 56)); + } else { + return (0xffL & (long) bytes[7]) + | (0xff00L & ((long) bytes[6] << 8)) + | (0xff0000L & ((long) bytes[5] << 16)) + | (0xff000000L & ((long) bytes[4] << 24)) + | (0xff00000000L & ((long) bytes[3] << 32)) + | (0xff0000000000L & ((long) bytes[2] << 40)) + | (0xff000000000000L & ((long) bytes[1] << 48)) + | (0xff00000000000000L & ((long) bytes[0] << 56)); + } + } + + /** + * 返回由字节数组中的指定的八个字节转换来的 64 位有符号整数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由八个字节构成的 64 位有符号整数 + */ + public static long toLong(byte[] bytes, int startIndex) { + return toLong(copyFrom(bytes, startIndex, 8)); + } + + /** + * 返回由字节数组转换来的单精度浮点数 + * @param bytes 字节数组 + * @return 由四个字节构成的单精度浮点数 + */ + public static float toFloat(byte[] bytes) { + return Float.intBitsToFloat(toInt(bytes)); + } + + /** + * 返回由字节数组中的指定的四个字节转换来的单精度浮点数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由四个字节构成的单精度浮点数 + */ + public static float toFloat(byte[] bytes, int startIndex) { + return Float.intBitsToFloat(toInt(copyFrom(bytes, startIndex, 4))); + } + + /** + * 返回由字节数组转换来的双精度浮点数 + * @param bytes 字节数组 + * @return 由八个字节构成的双精度浮点数 + */ + public static double toDouble(byte[] bytes) { + return Double.longBitsToDouble(toLong(bytes)); + } + + /** + * 返回由字节数组中的指定的八个字节转换来的双精度浮点数 + * @param bytes 字节数组 + * @param startIndex 起始下标 + * @return 由八个字节构成的双精度浮点数 + */ + public static double toDouble(byte[] bytes, int startIndex) { + return Double.longBitsToDouble(toLong(copyFrom(bytes, startIndex, 8))); + } + + /** + * 返回由字节数组转换来的字符串 + * @param bytes 字节数组 + * @return 字符串 + */ + public static String toString(byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8); + } + + /** + * 返回由字节数组转换来的字符串 + * @param bytes 字节数组 + * @param charsetName 字符集编码 + * @return 字符串 + */ + public static String toString(byte[] bytes, String charsetName) { + return new String(bytes, Charset.forName(charsetName)); + } + + /** + * 以字符串表示形式返回字节数组的内容 + * @param bytes 字节数组 + * @return 字符串形式的 bytes + */ + public static String toHexString(byte[] bytes) { + if (bytes == null) { + return "null"; + } + int iMax = bytes.length - 1; + if (iMax == -1) { + return "[]"; + } + String digits = "0123456789abcdef"; + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(digits.charAt((0xF0 & bytes[i]) >>> 4)); + b.append(digits.charAt(0x0F & bytes[i])); + if (i == iMax) { + return b.append(']').toString(); + } + b.append(',').append(' '); + } + } + + + // -------------------------------------------------------------------------------------------- + + + /** + * 数组拷贝。 + * @param src 字节数组。 + * @param off 起始下标。 + * @param len 拷贝长度。 + * @return 指定长度的字节数组。 + */ + private static byte[] copyFrom(byte[] src, int off, int len) { + // return Arrays.copyOfRange(src, off, off + len); + byte[] copy = new byte[len]; + System.arraycopy(src, off, copy, 0, Math.min(src.length - off, len)); + return copy; + } + + /** + * 判断 CPU Endian 是否为 Little + * @return 判断结果 + */ + private static boolean isLittleEndian() { + return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + } +} diff --git a/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java b/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java index fa20cfa..e88769a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/codec/BitTools.java @@ -87,4 +87,153 @@ public abstract class BitTools { public static boolean state(byte b, int p) { return get(b, p) == 1; } + + /** + * 布尔值转换为字节数组 + * + * @param data 一个布尔值 + * @return 长度为 1 的字节数组 + */ + public static byte[] toBytes(boolean data) { + return BitConverter.getBytes(data); + } + + /** + * short型数字转换为字节数组 + * + * @param data short型数字 + * @return 长度为 2 的字节数组 + */ + public static byte[] toBytes(short data) { + return BitConverter.getBytes(data); + } + + /** + * char型字符转换为字节数组 + * + * @param data 字符 + * @return 长度为 2 的字节数组 + */ + public static byte[] toBytes(char data) { + return BitConverter.getBytes(data); + } + + /** + * 整形数字转换为字节数组 + * + * @param data 整形数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] toBytes(int data) { + return BitConverter.getBytes(data); + } + + /** + * long形数字转换为字节数组 + * + * @param data long形数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] toBytes(long data) { + return BitConverter.getBytes(data); + } + + /** + * float形数字转换为字节数组 + * + * @param data float形数字 + * @return 长度为 4 的字节数组 + */ + public static byte[] toBytes(float data) { + return BitConverter.getBytes(data); + } + + /** + * double形数字转换为字节数组 + * + * @param data double形数字 + * @return 长度为 8 的字节数组 + */ + public static byte[] toBytes(double data) { + return BitConverter.getBytes(data); + } + + /** + * 字节数组转换为布尔值 + * + * @param bytes 字节数组 (只会取前1位) + * @return 布尔值 + */ + public static boolean toBoolean(byte[] bytes) { + return BitConverter.toBoolean(bytes); + } + + /** + * 字节数组转换为short型数字 + * + * @param bytes 字节数组 (只会取前2位) + * @return short型数字 + */ + public static short toShort(byte[] bytes) { + return BitConverter.toShort(bytes); + } + + /** + * 字节数组转换为整形数字 + * + * @param bytes 字节数组 (只会取前4位) + * @return 整形数字 + */ + public static int toInteger(byte[] bytes) { + return BitConverter.toInt(bytes); + } + + /** + * 字节数组转换为long形数字 + * + * @param bytes 字节数组 (只会取前8位) + * @return long形数字 + */ + public static long toLong(byte[] bytes) { + if (bytes.length == 4) { + return BitConverter.toInt(bytes); + } else { + return BitConverter.toLong(bytes); + } + } + + /** + * 字节数组转换为float形数字 + * + * @param bytes 字节数组 (只会取前4位) + * @return float形数字 + */ + public static float toFloat(byte[] bytes) { + return BitConverter.toFloat(bytes); + } + + /** + * 字节数组转换为double形数字 + * + * @param bytes 字节数组 (只会取前8位) + * @return double形数字 + */ + public static double toDouble(byte[] bytes) { + if (bytes.length == 4) { + return BitConverter.toFloat(bytes); + } else { + return BitConverter.toDouble(bytes); + } + } + + + /** + * 字节数组转换为char字符 + * + * @param bytes 字节数组 (只会取前2位) + * @return char字符 + */ + public static char toCharacter(byte[] bytes) { + return BitConverter.toChar(bytes); + } } -- Gitee From 438574eb6c71bd1ff283a4c67084e552f0c03a90 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:54:46 +0800 Subject: [PATCH 54/82] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/files/FileTools.java | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java index 75ade1d..f3bdcef 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/FileTools.java @@ -88,16 +88,105 @@ public abstract class FileTools { if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath()); } + try (FileInputStream fis = new FileInputStream(file)) { + return readTextContent(fis, maxSize); + } + } + + /** + * 读取文件的文本内容 + * + * @param input 待读取的文件流 + * @return 文本内容 + */ + public static String readTextContent(InputStream input) throws IOException { + return readTextContent(input, 0); + } + + /** + * 读取文件的文本内容 + * + * @param input 待读取的文件流 + * @param maxSize 允许读取的最大字节数, 0表示无限制 + * @return 文本内容 + */ + public static String readTextContent(InputStream input, long maxSize) throws IOException { byte[] bytes; - try (FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream()) { - copy(fis, bos, maxSize); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + copy(input, bos, maxSize); bytes = bos.toByteArray(); } return bytesToString(bytes, CHARSET); } + /** + * 读取文件的二进制内容 + * + * @param file 待读取的文件 + * @return 二进制内容 + */ + public static byte[] readByteContent(String file) throws IOException { + return readByteContent(new File(file)); + } + + /** + * 读取文件的二进制内容 + * + * @param file 待读取的文件 + * @return 二进制内容 + */ + public static byte[] readByteContent(File file) throws IOException { + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); + } + try (FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + copy(fis, bos); + return bos.toByteArray(); + } + } + + /** + * 读取文件的二进制内容 + * + * @param file 待读取的文件 + * @param maxSize 允许读取的最大字节数, 0表示无限制 + * @return 二进制内容 + */ + public static byte[] readByteContent(File file, long maxSize) throws IOException { + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); + } + try (FileInputStream fis = new FileInputStream(file)) { + return readByteContent(fis, maxSize); + } + } + + /** + * 读取文件的二进制内容 + * + * @param input 待读取的文件流 + * @return 二进制内容 + */ + public static byte[] readByteContent(InputStream input) throws IOException { + return readByteContent(input, 0); + } + + /** + * 读取文件的二进制内容 + * + * @param input 待读取的文件流 + * @param maxSize 允许读取的最大字节数, 0表示无限制 + * @return 二进制内容 + */ + public static byte[] readByteContent(InputStream input, long maxSize) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + copy(input, bos, maxSize); + return bos.toByteArray(); + } + } + static String bytesToString(byte[] bytes, Charset defaultCharset) throws IOException { try (InputStream input = new ByteArrayInputStream(bytes)) { // 解析内容的字符集 @@ -527,7 +616,7 @@ public abstract class FileTools { // 是文件夹, 目标路径已经存在或目标路径在源路径之中(移到源路径下面), 则只能遍历一个个的移动 File sfile = spath.toFile(); File[] files = sfile.listFiles(); - if (files != null && files.length > 0) { + if (files != null) { for (File next : files) { boolean continues = move(next.toPath(), dpath.resolve(next.getName()), exceptionWatcher); if (!continues) { -- Gitee From c61fa24f8ed56cc744b66ada502a3456355eff4b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:55:44 +0800 Subject: [PATCH 55/82] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=B1=BB=E6=A2=B3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../able/exception/EditableException.java | 32 +--- .../able/exception/FormFieldException.java | 161 ++++++++++++++++++ .../qdbp/able/exception/FormatException.java | 14 +- .../able/exception/NonFatalException.java | 133 +++++++++++++++ .../exception/ResourceNotFoundException.java | 12 +- .../qdbp/able/exception/ServiceException.java | 121 ++++++++++--- .../gitee/qdbp/able/result/ResultCode.java | 9 + .../gitee/qdbp/tools/utils/VerifyTools.java | 17 +- .../settings/i18n/ResultCode_zh_CN.properties | 3 + .../exception/ResultSetMismatchException.java | 30 ++-- .../qdbp/tools/excel/json/BeanGroup.java | 2 +- 11 files changed, 459 insertions(+), 75 deletions(-) create mode 100644 able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java create mode 100644 able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java b/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java index 459c4ab..ba0ce14 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/EditableException.java @@ -5,7 +5,9 @@ package com.gitee.qdbp.able.exception; * * @author zhaohuihua * @version 170624 + * @deprecated 改为使用ServiceException (也可以追加消息了) */ +@Deprecated public abstract class EditableException extends RuntimeException { /** 版本序列号 **/ @@ -75,19 +77,8 @@ public abstract class EditableException extends RuntimeException { * @param message 异常消息 */ public void prependMessage(String message) { - if (message == null || message.length() == 0) { - return; - } - - if (this.message == null) { - this.message = message; - } else { - char last = message.charAt(message.length() - 1); - if (last == ' ' || last == '\t' || last == '\r' || last == '\n') { - this.message = message + this.message; - } else { - this.message = message + " " + this.message; - } + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (message + " " + this.message); } } @@ -97,19 +88,8 @@ public abstract class EditableException extends RuntimeException { * @param message 异常消息 */ public void appendMessage(String message) { - if (message == null || message.length() == 0) { - return; - } - - if (this.message == null) { - this.message = message; - } else { - char last = message.charAt(message.length() - 1); - if (last == ' ' || last == '\t' || last == '\r' || last == '\n') { - this.message = this.message + message; - } else { - this.message = this.message + " " + message; - } + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (this.message + " " + message); } } diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java b/able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java new file mode 100644 index 0000000..858ca9e --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/exception/FormFieldException.java @@ -0,0 +1,161 @@ +package com.gitee.qdbp.able.exception; + +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 表单字段异常类 + * + * @author zhaohuihua + * @version 20230726 + */ +public class FormFieldException extends NonFatalException { + + private static final long serialVersionUID = -219502305847916492L; + + private String fieldName; + + /** 默认构造函数 **/ + public FormFieldException() { + super(ResultCode.PARAMETER_FORMAT_ERROR); + } + + /** 构造函数 **/ + public FormFieldException(String fieldName) { + super(ResultCode.PARAMETER_FORMAT_ERROR); + this.fieldName = fieldName; + } + + /** + * 构造函数 + * + * @param fieldName 字段名 + * @param result 错误返回码 + */ + public FormFieldException(String fieldName, IResultMessage result) { + super(result); + this.fieldName = fieldName; + } + + /** + * 构造函数 + * + * @param fieldName 字段名 + * @param result 错误返回码 + * @param cause 引发异常的原因 + */ + public FormFieldException(String fieldName, IResultMessage result, Throwable cause) { + super(result, cause); + this.fieldName = fieldName; + } + + /** 设置字段名 **/ + public FormFieldException setFieldName(String fieldName) { + this.fieldName = fieldName; + return this; + } + + /** 字段名 **/ + public String getFieldName() { + return fieldName; + } + + @Override + protected void appendKeywords(StringBuilder buffer) { + buffer.append('[').append(fieldName).append(']'); + } + + /** + * 设置错误返回码 + * + * @param code 错误返回码 + */ + @Override + public ServiceException setCode(String code) { + super.setCode(code); + return this; + } + + /** + * 设置消息 + * + * @param message 消息 + */ + @Override + public FormFieldException setMessage(String message) { + super.setMessage(message); + return this; + } + + /** + * 重新设置错误消息 + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public FormFieldException setMessage(String pattern, Object... args) { + super.setMessage(pattern, args); + return this; + } + + /** + * 在消息前面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public FormFieldException prependMessage(String message) { + super.prependMessage(message); + return this; + } + + /** + * 在消息后面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public FormFieldException appendMessage(String message) { + super.appendMessage(message); + return this; + } + + /** + * 设置错误详情 + * + * @param details 错误详情 + */ + @Override + public FormFieldException setDetails(String details) { + super.setDetails(details); + return this; + } + + /** + * 设置错误详情 + * + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public FormFieldException setDetails(String pattern, Object... args) { + super.setDetails(pattern, args); + return this; + } + + /** 在错误详情前面追加提示信息 **/ + @Override + public FormFieldException prependDetails(String details) { + super.prependDetails(details); + return this; + } + + /** 在错误详情后面追加提示信息 **/ + @Override + public FormFieldException appendDetails(String details) { + super.appendDetails(details); + return this; + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java b/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java index a771d1f..a83d44d 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/FormatException.java @@ -1,6 +1,8 @@ package com.gitee.qdbp.able.exception; +import com.gitee.qdbp.able.result.ResultCode; + /** * 格式错误异常类 * @@ -8,14 +10,14 @@ package com.gitee.qdbp.able.exception; * @version 20210220 * @since 3.2.11 */ -public class FormatException extends EditableException { +public class FormatException extends ServiceException { /** 版本序列号 **/ private static final long serialVersionUID = 7269605602712999273L; /** 构造函数 **/ public FormatException() { - super(); + super(ResultCode.PARAMETER_FORMAT_ERROR); } /** @@ -24,7 +26,8 @@ public class FormatException extends EditableException { * @param message 异常信息 */ public FormatException(String message) { - super(message); + super(ResultCode.PARAMETER_FORMAT_ERROR); + this.setMessage(message); } /** @@ -33,7 +36,7 @@ public class FormatException extends EditableException { * @param cause 引发原因 */ public FormatException(Throwable cause) { - super(cause); + super(ResultCode.PARAMETER_FORMAT_ERROR, cause); } /** @@ -43,6 +46,7 @@ public class FormatException extends EditableException { * @param cause 引发原因 */ public FormatException(String message, Throwable cause) { - super(message, cause); + super(ResultCode.PARAMETER_FORMAT_ERROR, cause); + this.setMessage(message); } } \ No newline at end of file diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java b/able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java new file mode 100644 index 0000000..feaaa76 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/exception/NonFatalException.java @@ -0,0 +1,133 @@ +package com.gitee.qdbp.able.exception; + +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; + +/** + * 非致命异常 (业务提示级别的异常) + * + * @author zhaohuihua + * @version 20230726 + */ +public class NonFatalException extends ServiceException { + + private static final long serialVersionUID = -5189857843104774374L; + + /** 默认构造函数 **/ + public NonFatalException() { + super(ResultCode.PARAMETER_FORMAT_ERROR); + } + + /** + * 构造函数 + * + * @param result 错误返回码 + */ + public NonFatalException(IResultMessage result) { + super(result); + } + + /** + * 构造函数 + * + * @param result 错误返回码 + * @param cause 引发异常的原因 + */ + public NonFatalException(IResultMessage result, Throwable cause) { + super(result, cause); + } + + /** + * 设置错误返回码 + * + * @param code 错误返回码 + */ + @Override + public ServiceException setCode(String code) { + super.setCode(code); + return this; + } + + /** + * 设置消息 + * + * @param message 消息 + */ + @Override + public NonFatalException setMessage(String message) { + super.setMessage(message); + return this; + } + + /** + * 重新设置错误消息 + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public NonFatalException setMessage(String pattern, Object... args) { + super.setMessage(pattern, args); + return this; + } + + /** + * 在消息前面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public NonFatalException prependMessage(String message) { + super.prependMessage(message); + return this; + } + + /** + * 在消息后面追加异常消息 + * + * @param message 异常消息 + */ + @Override + public NonFatalException appendMessage(String message) { + super.appendMessage(message); + return this; + } + + /** + * 设置错误详情 + * + * @param details 错误详情 + */ + @Override + public NonFatalException setDetails(String details) { + super.setDetails(details); + return this; + } + + /** + * 设置错误详情 + * + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + @Override + public NonFatalException setDetails(String pattern, Object... args) { + super.setDetails(pattern, args); + return this; + } + + /** 在错误详情前面追加提示信息 **/ + @Override + public NonFatalException prependDetails(String details) { + super.prependDetails(details); + return this; + } + + /** 在错误详情后面追加提示信息 **/ + @Override + public NonFatalException appendDetails(String details) { + super.appendDetails(details); + return this; + } +} diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java index 926960a..bf8cfa7 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ResourceNotFoundException.java @@ -1,12 +1,14 @@ package com.gitee.qdbp.able.exception; +import com.gitee.qdbp.able.result.ResultCode; + /** * 资源未找到 * * @author zhaohuihua * @version 170624 */ -public class ResourceNotFoundException extends EditableException { +public class ResourceNotFoundException extends ServiceException { /** 版本序列号 **/ private static final long serialVersionUID = 1L; @@ -16,15 +18,17 @@ public class ResourceNotFoundException extends EditableException { } public ResourceNotFoundException(String message) { - super(message); + super(ResultCode.RESOURCE_NOT_FOUND); + this.setMessage(message); } public ResourceNotFoundException(Throwable cause) { - super(cause); + super(ResultCode.RESOURCE_NOT_FOUND, cause); } public ResourceNotFoundException(String message, Throwable cause) { - super(message, cause); + super(ResultCode.RESOURCE_NOT_FOUND, cause); + this.setMessage(message); } } diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java index a98e3ae..c9ea3bf 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java @@ -4,6 +4,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; import com.gitee.qdbp.able.result.IResultException; import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; import com.gitee.qdbp.tools.utils.StringTools; /** @@ -19,11 +20,14 @@ public class ServiceException extends RuntimeException implements IResultExcepti /** 错误返回码 **/ private String code; + /** 异常消息 **/ + private String message; /** 错误详情 **/ private String details; /** 默认构造函数 **/ public ServiceException() { + this(ResultCode.SERVER_INNER_ERROR); } /** @@ -34,6 +38,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti public ServiceException(IResultMessage result) { super(getRealMessage(result)); this.code = result.getCode(); + this.message = getRealMessage(result); if (result instanceof IResultException) { this.details = ((IResultException) result).getDetails(); } @@ -48,8 +53,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti */ @Deprecated public ServiceException(IResultMessage result, String details) { - super(getRealMessage(result)); - this.code = result.getCode(); + this(result); this.details = details; } @@ -62,8 +66,11 @@ public class ServiceException extends RuntimeException implements IResultExcepti public ServiceException(IResultMessage result, Throwable cause) { super(getRealMessage(result), cause); this.code = result.getCode(); + this.message = getRealMessage(result); if (result instanceof IResultException) { this.details = ((IResultException) result).getDetails(); + } else if (cause instanceof IResultException) { + this.details = ((IResultException) cause).getDetails(); } } @@ -77,8 +84,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti */ @Deprecated public ServiceException(IResultMessage result, String details, Throwable cause) { - super(getRealMessage(result), cause); - this.code = result.getCode(); + this(result, cause); this.details = details; } @@ -94,7 +100,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti /** * 设置错误返回码 - * + * * @param code 错误返回码 */ public ServiceException setCode(String code) { @@ -102,6 +108,79 @@ public class ServiceException extends RuntimeException implements IResultExcepti return this; } + /** 提供给子类追加需要输出在异常信息中的关键字 **/ + protected void appendKeywords(StringBuilder buffer) { + } + + /** + * 获取简化的错误消息 (不会包含错误详情) + * + * @return 错误消息 + */ + @Override + public String getSimpleMessage() { + return super.getMessage(); + } + + @Override + public String getMessage() { + StringBuilder buffer = new StringBuilder(); + appendKeywords(buffer); + buffer.append(getSimpleMessage()); + appendDetails(buffer, details); + return buffer.toString(); + } + + /** + * 设置消息 + * + * @param message 消息 + */ + protected ServiceException setMessage(String message) { + this.message = message; + return this; + } + + /** + * 重新设置错误消息 + * @param pattern 错误消息 + * @param args 替换参数 + * @return 对象自身 + */ + public ServiceException setMessage(String pattern, Object... args) { + if (pattern == null || pattern.length() == 0 || args == null || args.length == 0) { + this.message = pattern; + } else { + String fmt = StringTools.replace(pattern, "{}", "%s"); + this.message = String.format(fmt, args); + } + return this; + } + + /** + * 在消息前面追加异常消息 + * + * @param message 异常消息 + */ + public ServiceException prependMessage(String message) { + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (message + " " + this.message); + } + return this; + } + + /** + * 在消息后面追加异常消息 + * + * @param message 异常消息 + */ + public ServiceException appendMessage(String message) { + if (message != null && message.length() > 0) { + this.message = (this.message == null) ? message : (this.message + " " + message); + } + return this; + } + /** * 获取错误详情 * @@ -114,7 +193,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti /** * 设置错误详情 - * + * * @param details 错误详情 */ public ServiceException setDetails(String details) { @@ -132,30 +211,27 @@ public class ServiceException extends RuntimeException implements IResultExcepti public ServiceException setDetails(String pattern, Object... args) { if (pattern == null || pattern.length() == 0 || args == null || args.length == 0) { this.details = pattern; - return this; } else { String fmt = StringTools.replace(pattern, "{}", "%s"); this.details = String.format(fmt, args); - return this; } + return this; } - /** - * 获取简化的错误消息 (不会包含错误详情) - * - * @return 错误消息 - */ - @Override - public String getSimpleMessage() { - return super.getMessage(); + /** 在错误详情前面追加提示信息 **/ + public ServiceException prependDetails(String details) { + if (details != null && details.length() > 0) { + this.details = (this.details == null) ? details : (details + " " + this.details); + } + return this; } - @Override - public String getMessage() { - StringBuilder buffer = new StringBuilder(); - buffer.append(getSimpleMessage()); - appendDetails(buffer, details); - return buffer.toString(); + /** 在错误详情后面追加提示信息 **/ + public ServiceException appendDetails(String details) { + if (details != null && details.length() > 0) { + this.details = (this.details == null) ? details : (this.details + " " + details); + } + return this; } @Override @@ -163,6 +239,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti StringBuilder buffer = new StringBuilder(); buffer.append(getClass().getSimpleName()); buffer.append('[').append(code).append(']'); + appendKeywords(buffer); buffer.append(getSimpleMessage()); appendDetails(buffer, details); return buffer.toString(); diff --git a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java index d9e6dbb..d4836d5 100644 --- a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java @@ -34,6 +34,15 @@ public enum ResultCode implements IResultMessage { /** 远程服务对方返回失败 **/ REMOTE_SERVICE_FAIL, + /** 远程服务未找到 **/ + REMOTE_SERVICE_NOT_FOUND, + + /** 远程服务请求超时 **/ + REMOTE_SERVICE_TIMEOUT, + + /** 资源不存在 **/ + RESOURCE_NOT_FOUND, + /** 数据库INSERT失败 **/ DB_INSERT_ERROR, diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java index d233f8a..acdbf7c 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/VerifyTools.java @@ -5,7 +5,7 @@ import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; -import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.exception.FormFieldException; import com.gitee.qdbp.able.result.ResultCode; /** @@ -29,7 +29,8 @@ public class VerifyTools { */ public static void requireNonNull(Object object, String name) { if (object == null) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be null."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be null."); } } @@ -42,10 +43,12 @@ public class VerifyTools { */ public static void requireNotBlank(Object object, String name) { if (object == null) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be null."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be null."); } if (isBlank(object)) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be empty."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be empty."); } } @@ -58,10 +61,12 @@ public class VerifyTools { */ public static void requireNotBlank(String string, String name) { if (string == null) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be null."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be null."); } if (isBlank(string)) { - throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED).setDetails(name + " must not be empty."); + throw new FormFieldException(name, ResultCode.PARAMETER_IS_REQUIRED) + .setDetails(name + " must not be empty."); } } diff --git a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties index 8ccb692..da5ddc3 100644 --- a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties @@ -7,6 +7,9 @@ PARAMETER_OUT_RANGE = 参数值超出允许范围 SERVER_INNER_ERROR = 服务器内部异常 REMOTE_SERVICE_ERROR = 远程服务调用失败 REMOTE_SERVICE_FAIL = 远程服务对方返回失败 +REMOTE_SERVICE_NOT_FOUND = 远程服务未找到 +REMOTE_SERVICE_TIMEOUT = 远程服务请求超时 +RESOURCE_NOT_FOUND = 资源不存在 DB_INSERT_ERROR = 数据保存失败 DB_UPDATE_ERROR = 数据更新失败 DB_DELETE_ERROR = 数据删除失败 diff --git a/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java b/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java index 14495ff..f3f73f2 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/excel/exception/ResultSetMismatchException.java @@ -1,6 +1,8 @@ package com.gitee.qdbp.tools.excel.exception; -import com.gitee.qdbp.able.exception.EditableException; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.tools.utils.StringTools; /** * 结果集不匹配 @@ -8,7 +10,7 @@ import com.gitee.qdbp.able.exception.EditableException; * @author zhaohuihua * @version 190324 */ -public class ResultSetMismatchException extends EditableException { +public class ResultSetMismatchException extends ServiceException { /** serialVersionUID **/ private static final long serialVersionUID = 1L; @@ -19,16 +21,22 @@ public class ResultSetMismatchException extends EditableException { * @param message 异常消息 */ public ResultSetMismatchException(String message) { - super(message); + super(ErrorCode.RESULT_SET_MISMATCH); + super.setMessage(message); } - /** - * 构造函数 - * - * @param message 异常消息 - * @param cause 异常原因 - */ - public ResultSetMismatchException(String message, Throwable cause) { - super(message, cause); + private enum ErrorCode implements IResultMessage { + + RESULT_SET_MISMATCH; + + @Override + public String getCode() { + return this.name(); + } + + @Override + public String getMessage() { + return StringTools.replace(this.name(), "_", " ", ".", ""); + } } } diff --git a/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java b/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java index 0a63c29..250180e 100644 --- a/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java +++ b/tools/src/main/java/com/gitee/qdbp/tools/excel/json/BeanGroup.java @@ -501,7 +501,7 @@ public class BeanGroup implements Serializable { private String finalMismatchSummary(Map resources, int total, List errors) { // summary.single = The item don't match. - // summary.multiple = The are {total} items in total, {mismatch} of which don't match. + // summary.multiple = They are {total} items in total, {mismatch} of which don't match. String pattern = resources.get(total > 1 ? "summary.multiple" : "summary.single"); Map params = new HashMap<>(); params.put("total", total); -- Gitee From 5a5c65c4d32f46ef1356ea25e89024d3bb234287 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Mon, 14 Aug 2023 23:57:29 +0800 Subject: [PATCH 56/82] 5.6.230812 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 460a794..8a1841c 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230712 + 5.6.230812 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230712 + 5.6.230812 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 71da000..8a5a490 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230712 + 5.6.230812 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 76d9dee..4e66e71 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230712 + 5.6.230812 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230712 + 5.6.230812 diff --git a/test/pom.xml b/test/pom.xml index 6c9da77..2e7f728 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230712 + 5.6.230812 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 4ffec8e..2a736dc 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index ad9851a..3de47e9 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 7a5a008..031ebc0 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 4c461cc..5341511 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 5e117a0..37c4b1a 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index e1669bc..ceb7bf7 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230712 + 5.6.230812 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 5ece174..0143240 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230712 + 5.6.230812 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 8a7ff414cb34ae9163de364264b2a76d2264f3df Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Fri, 18 Aug 2023 21:38:12 +0800 Subject: [PATCH 57/82] =?UTF-8?q?ServiceException=E7=9A=84SimpleMessage?= =?UTF-8?q?=E5=8F=96=E5=80=BC=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/able/exception/ServiceException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java index c9ea3bf..bc03520 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java @@ -119,7 +119,7 @@ public class ServiceException extends RuntimeException implements IResultExcepti */ @Override public String getSimpleMessage() { - return super.getMessage(); + return message; } @Override -- Gitee From fe71fc48c203f394e0b342f545dbbea905b4c836 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Fri, 18 Aug 2023 21:38:35 +0800 Subject: [PATCH 58/82] 5.6.230815 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8a1841c..98bb1ac 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230812 + 5.6.230815 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230812 + 5.6.230815 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 8a5a490..a473a2c 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230812 + 5.6.230815 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 4e66e71..77f42ab 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230812 + 5.6.230815 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230812 + 5.6.230815 diff --git a/test/pom.xml b/test/pom.xml index 2e7f728..8021f0e 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230812 + 5.6.230815 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 2a736dc..2498d6e 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 3de47e9..29e661c 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 031ebc0..857ab51 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 5341511..eb01039 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 37c4b1a..924f81e 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index ceb7bf7..a09f689 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230812 + 5.6.230815 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 0143240..25117f4 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230812 + 5.6.230815 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From bc7b76e27372ecc891359a4d21238543e1bb366d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:55:09 +0800 Subject: [PATCH 59/82] =?UTF-8?q?=E6=A0=91=E5=BD=A2=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNodes.java | 243 ++++++++++++++---- 1 file changed, 194 insertions(+), 49 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java index 53ee1e4..a7ef7bd 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/TreeNodes.java @@ -1,8 +1,10 @@ package com.gitee.qdbp.able.beans; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -22,8 +24,6 @@ public class TreeNodes { /** 容器节点 **/ private final Node container; - /** KEY与节点的映射表 **/ - private final Map> keyNodeMaps; /** 未找到上级的KEY **/ private final List keysOfWithoutParent; /** 获取KEY的方法 **/ @@ -66,11 +66,15 @@ public class TreeNodes { } } this.container = container; - this.keyNodeMaps = maps; this.keysOfWithoutParent = keysOfWithoutParent; this.keyGetter = keyGetter; } + /** 获取容器节点 **/ + public Node container() { + return this.container; + } + /** 获取容器节点 **/ public Node getContainer() { return this.container; @@ -99,22 +103,12 @@ public class TreeNodes { /** 查找指定节点 **/ public Node findNode(String key) { - Node node = keyNodeMaps.get(key); - if (node != null) { - // 考虑到有可能在外部修改key, 因此增加检查 - String nodeKey = keyGetter.apply(node.element); - if (key.equals(nodeKey)) { - return node; - } - } Iterator> iterator = container.depthFirstNodeIterator(); while (iterator.hasNext()) { - Node next = iterator.next(); - String nextKey = keyGetter.apply(next.element); - // 遍历时更新缓存中的对应关系 - keyNodeMaps.put(nextKey, next); + Node node = iterator.next(); + String nextKey = keyGetter.apply(node.element); if (key.equals(nextKey)) { - return next; + return node; } } return null; @@ -169,6 +163,29 @@ public class TreeNodes { return elements; } + /** 移除指定节点 **/ + public void removeElements(String... keys) { + if (keys != null) { + this.removeElements(Arrays.asList(keys)); + } + } + + /** 移除指定节点 **/ + @SuppressWarnings("all") + public void removeElements(final List keys) { + this.container.removeIf(new BaseFunction, Boolean>() { + @Override + public Boolean apply(Node node) { + return keys.contains(keyGetter.apply(node.element)); + } + }); + } + + /** 移除匹配节点 **/ + public void removeIf(BaseFunction, Boolean> matcher) { + this.container.removeIf(matcher); + } + /** 未找到上级的KEY **/ public List getKeysOfWithoutParent() { return this.keysOfWithoutParent; @@ -184,12 +201,7 @@ public class TreeNodes { * @return 树形数据的根节点 */ public List toTreeList(BinaryConsumer> childSetter) { - List list = new ArrayList<>(); - for (Node child : container.children) { - child.fillAllChildren(childSetter); - list.add(child.element); - } - return list; + return container.toTreeList(childSetter); } /** 广度优先遍历 **/ @@ -212,8 +224,8 @@ public class TreeNodes { * @param keyGetter KEY的获取方法 * @param parentGetter 上级的获取方法 * @param childSetter 子级的设置方法 - * @return 树形数据列表 * @param 数据类型 + * @return 树形数据列表 */ public static List toTreeList(List list, BaseFunction keyGetter, BaseFunction parentGetter, BinaryConsumer> childSetter) { @@ -240,6 +252,10 @@ public class TreeNodes { this.children = new ArrayList<>(); } + public boolean isLeaf() { + return this.children.isEmpty(); + } + public T getElement() { return element; } @@ -258,6 +274,11 @@ public class TreeNodes { return parent == null ? null : parent.element; } + /** 获取父级节点 **/ + public Node getParentNode() { + return parent == null ? null : parent; + } + /** 获取所有祖先元素 **/ public List getAllAncestorElements() { List parents = new ArrayList<>(); @@ -270,6 +291,18 @@ public class TreeNodes { return parents; } + /** 获取所有祖先节点 **/ + public List> getAllAncestorNodes() { + List> parents = new ArrayList<>(); + Node temp = parent; + while (temp != null && temp.element != null) { + parents.add(temp); + temp = temp.parent; + } + Collections.reverse(parents); + return parents; + } + /** 获取直接子级元素 **/ public List getChildElements() { List elements = new ArrayList<>(); @@ -279,11 +312,29 @@ public class TreeNodes { return elements; } + /** 获取直接节点列表 **/ + public List> getChildNodes() { + return children; + } + /** 增加子元素 **/ public void addChildElement(T child) { addChildNode(new Node<>(child)); } + /** 增加子级节点 **/ + protected void addChildNode(Node child) { + children.add(child); + child.parent = this; + } + + /** 增加子级节点 **/ + protected void addChildNodes(List> children) { + for (Node child : children) { + addChildNode(child); + } + } + /** 获取后代元素 **/ public List getAllDescendantElements() { Iterator iterator = depthFirstElementIterator(); @@ -295,33 +346,41 @@ public class TreeNodes { return elements; } + /** 获取后代节点 **/ + public List> getAllDescendantNodes() { + Iterator> iterator = depthFirstNodeIterator(); + List> nodes = new ArrayList<>(); + while (iterator.hasNext()) { + Node next = iterator.next(); + nodes.add(next); + } + return nodes; + } + /** 获取所有叶子元素 **/ public List getAllLeafElements() { Iterator> iterator = depthFirstNodeIterator(); List elements = new ArrayList<>(); while (iterator.hasNext()) { Node next = iterator.next(); - if (next.children.isEmpty()) { + if (next.isLeaf()) { elements.add(next.element); } } return elements; } - /** 获取直接节点列表 **/ - protected List> getChildNodes() { - return children; - } - - /** 增加子级节点 **/ - protected void addChildNode(Node child) { - children.add(child); - child.parent = this; - } - - /** 获取父级节点 **/ - protected Node getParentNode() { - return parent == null ? null : parent; + /** 获取所有叶子节点 **/ + public List> getAllLeafNodes() { + Iterator> iterator = depthFirstNodeIterator(); + List> nodes = new ArrayList<>(); + while (iterator.hasNext()) { + Node next = iterator.next(); + if (next.isLeaf()) { + nodes.add(next); + } + } + return nodes; } /** 广度优先遍历元素 **/ @@ -346,22 +405,108 @@ public class TreeNodes { /** 设置所有后代元素的Children属性 **/ public void fillAllChildren(BinaryConsumer> childSetter) { - Iterator> iterator = this.depthFirstNodeIterator(); - List myChildren = new ArrayList<>(); + if (this.element != null) { + childSetter.accept(this.element, this.getChildElements()); + } + Iterator> iterator = this.breadthFirstNodeIterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + childSetter.accept(node.element, node.getChildElements()); + } + } + + /** 转换为带Children属性的List **/ + public List toTreeList(BinaryConsumer> childSetter) { + List list = new ArrayList<>(); + this.fillAllChildren(childSetter); + if (this.element != null) { + list.add(this.element); + } else { + for (Node child : children) { + list.add(child.element); + } + } + return list; + } + + /** 移除匹配节点 **/ + public void removeIf(BaseFunction, Boolean> matcher) { + Iterator> iterator = this.breadthFirstNodeIterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (matcher.apply(node)) { + iterator.remove(); + } + } + } + + /** 过滤子树 (包含匹配节点及祖先节点, 不包含后代节点) **/ + public Node filterUpBy(BaseFunction, Boolean> matcher) { + return filterBy(true, false, matcher); + } + + /** 过滤子树 (包含匹配节点及后代节点, 不包含祖先节点) **/ + public Node filterDownBy(BaseFunction, Boolean> matcher) { + return filterBy(false, true, matcher); + } + + /** 过滤子树 (包含匹配节点及祖先节点及后代节点) **/ + public Node filterAllBy(BaseFunction, Boolean> matcher) { + return filterBy(true, true, matcher); + } + + /** 过滤子树 (包含匹配节点及祖先节点及后代节点) **/ + private Node filterBy(boolean ancestor, boolean descendant, BaseFunction, Boolean> matcher) { + // 需要保留的节点 + Map, ?> keepNodes = new LinkedHashMap<>(); + // 搜索符合条件的节点 + Iterator> searcher = this.breadthFirstNodeIterator(); + while (searcher.hasNext()) { + Node node = searcher.next(); + if (matcher.apply(node)) { + // 遇到匹配节点, 设置为保留节点 + keepNodes.put(node, null); + if (ancestor) { + // 如果需要包含祖先节点, 就将祖先节点也设置为保留节点 + for (Node parent : node.getAllAncestorNodes()) { + keepNodes.put(parent, null); + } + } + if (descendant) { + // 如果需要包含后代节点, 就将后代节点也设置为保留节点 + for (Node child : node.getAllDescendantNodes()) { + keepNodes.put(child, null); + } + } + } + } + // 根节点集合 + List> rootNodes = new ArrayList<>(); + // key=原节点, value=复制的新节点 + Map, Node> nodeCopies = new LinkedHashMap<>(); + Iterator> iterator = this.breadthFirstNodeIterator(); while (iterator.hasNext()) { Node node = iterator.next(); - if (node.parent == this) { - myChildren.add(node.element); - } else { - List> children = node.children; - List temp = new ArrayList<>(); - for (Node child : children) { - temp.add(child.element); + // 遇到保留节点 + if (keepNodes.containsKey(node)) { + // 复制副本 + Node newer = new Node<>(node.element); + nodeCopies.put(node, newer); + if (node.parent == null || !keepNodes.containsKey(node.parent)) { + // 这是一个新的顶级节点 + rootNodes.add(newer); + } else { + // 这到一个子节点 + Node pNode = nodeCopies.get(node.parent); + // 遍历时一定是先遇到父节点再遇到子节点, 所以pNode不可能为空 + // 将子节点加入父节点副本中 + pNode.addChildNode(newer); } - childSetter.accept(node.element, temp); } } - childSetter.accept(this.element, myChildren); + Node container = new Node<>(null); + container.addChildNodes(rootNodes); + return container; } @Override -- Gitee From a87def295c71e0796abb0a9d749681043e8ecdcb Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:56:41 +0800 Subject: [PATCH 60/82] =?UTF-8?q?Json=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0p?= =?UTF-8?q?arseAs(Type)=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/json/JsonService.java | 10 ++++ .../com/gitee/qdbp/tools/utils/JsonTools.java | 16 +++++++ .../gitee/qdbp/json/JsonServiceForBase.java | 6 +++ .../qdbp/json/JsonServiceForFastjson.java | 16 +++++++ .../gitee/qdbp/json/JsonServiceForGson.java | 47 +++++++++++++++++-- .../qdbp/json/JsonServiceForJackson.java | 21 +++++++++ 6 files changed, 112 insertions(+), 4 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/json/JsonService.java b/able/src/main/java/com/gitee/qdbp/json/JsonService.java index e014d63..2c019b1 100644 --- a/able/src/main/java/com/gitee/qdbp/json/JsonService.java +++ b/able/src/main/java/com/gitee/qdbp/json/JsonService.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.json; +import java.lang.reflect.Type; import java.util.Collection; import java.util.List; import java.util.Map; @@ -12,6 +13,9 @@ import java.util.Map; */ public interface JsonService { + /** 数据类型转换 **/ + T convert(Object object, Type type); + /** 数据类型转换 **/ T convert(Object object, Class clazz); @@ -33,6 +37,12 @@ public interface JsonService { /** 解析Json字符串数组 **/ List> parseAsMaps(String jsonString, JsonFeature.Deserialization feature); + /** 解析Json字符串对象 **/ + T parseAsObject(String jsonString, Type type); + + /** 解析Json字符串对象 **/ + T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature); + /** 解析Json字符串对象 **/ T parseAsObject(String jsonString, Class clazz); diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java index ca02ac1..9ce11ac 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.tools.utils; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; @@ -24,6 +25,11 @@ public class JsonTools extends JsonMaps { private JsonTools() { } + @SuppressWarnings("unchecked") + public static T convert(Object object, Type type) { + return findDefaultJsonService().convert(object, type); + } + @SuppressWarnings("unchecked") public static T convert(Object object, Class clazz) { if (object == null) { @@ -172,6 +178,16 @@ public class JsonTools extends JsonMaps { return findDefaultJsonService().parseAsMaps(jsonString, feature); } + /** 解析Json字符串对象 **/ + public static T parseAsObject(String jsonString, Type type) { + return findDefaultJsonService().parseAsObject(jsonString, type); + } + + /** 解析Json字符串对象 **/ + public static T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + return findDefaultJsonService().parseAsObject(jsonString, type, feature); + } + /** 解析Json字符串对象 **/ public static T parseAsObject(String jsonString, Class clazz) { return findDefaultJsonService().parseAsObject(jsonString, clazz); diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java index a6f2f0d..f67e211 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.json; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -31,6 +32,11 @@ public abstract class JsonServiceForBase implements JsonService { this.deserializationFeature = deserializationFeature.copy().lockToUnmodifiable(); } + @Override + public T parseAsObject(String jsonString, Type type) { + return parseAsObject(jsonString, type, deserializationFeature); + } + @Override public T parseAsObject(String jsonString, Class clazz) { return parseAsObject(jsonString, clazz, deserializationFeature); diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java index a178ed5..2524829 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForFastjson.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.json; import java.lang.reflect.Array; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -75,6 +76,12 @@ public class JsonServiceForFastjson extends JsonServiceForBase { return TypeUtils.castToJavaBean(object, clazz); } + @Override + public T convert(Object object, Type type) { + ParserConfig parserConfig = ParserConfig.getGlobalInstance(); + return TypeUtils.cast(object, type, parserConfig); + } + @Override public String toJsonString(Object object, JsonFeature.Serialization feature) { if (object == null) { @@ -87,6 +94,15 @@ public class JsonServiceForFastjson extends JsonServiceForBase { } } + @Override + public T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + if (jsonString == null || jsonString.trim().length() == 0) { + return null; + } + Feature[] features = generateParserFeatures(feature); + return JSON.parseObject(jsonString, type, features); + } + @Override public T parseAsObject(String jsonString, Class clazz, JsonFeature.Deserialization feature) { if (jsonString == null || jsonString.trim().length() == 0) { diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java index 0ef7b30..dfb9020 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForGson.java @@ -8,6 +8,8 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; @@ -26,6 +28,12 @@ import com.google.gson.reflect.TypeToken; */ public class JsonServiceForGson extends JsonServiceForBase { + @Override + public T convert(Object object, Type type) { + String string = toJsonString(object, serializationFeature); + return parseAsObject(string, type, deserializationFeature); + } + @Override public T convert(Object object, Class clazz) { String string = toJsonString(object, serializationFeature); @@ -61,6 +69,15 @@ public class JsonServiceForGson extends JsonServiceForBase { return gson.fromJson(jsonString, type); } + @Override + public T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + if (jsonString == null || jsonString.trim().length() == 0) { + return null; + } + Gson gson = generateGson(serializationFeature, feature); + return gson.fromJson(jsonString, type); + } + @Override public T parseAsObject(String jsonString, Class clazz, JsonFeature.Deserialization feature) { if (jsonString == null || jsonString.trim().length() == 0) { @@ -88,6 +105,14 @@ public class JsonServiceForGson extends JsonServiceForBase { builder.setLenient(); // 默认的转数字策略是ToNumberPolicy.DOUBLE, 导致所有的整数全转换为double了 builder.setObjectToNumberStrategy(ToNumberPolicy.LAZILY_PARSED_NUMBER); + // 排除STATIC/FINAL字段 + builder.excludeFieldsWithModifiers(Modifier.STATIC); + builder.excludeFieldsWithModifiers(Modifier.FINAL); + // 是否跳过transient修饰的字段 + if (sf.isSkipTransientField()) { + builder.excludeFieldsWithModifiers(Modifier.TRANSIENT); + } + builder.addDeserializationExclusionStrategy(new GsonExclusionStrategy(sf)); // 是否处理循环引用 (设置为true时不应该报错) // mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false); @@ -128,10 +153,6 @@ public class JsonServiceForGson extends JsonServiceForBase { if (sf.isWriteBigDecimalAsPlain()) { builder.registerTypeAdapter(BigDecimal.class, new BigDecimalToPlainStringSerializer()); } - // 是否跳过transient修饰的字段 - if (sf.isSkipTransientField()) { - builder.excludeFieldsWithModifiers(Modifier.TRANSIENT); - } // 是否输出格式化后的Json字符串 if (sf.isPrettyFormat()) { builder.setPrettyPrinting(); @@ -162,6 +183,24 @@ public class JsonServiceForGson extends JsonServiceForBase { return builder.create(); } + private static class GsonExclusionStrategy implements ExclusionStrategy { + private final JsonFeature.Serialization sf; + public GsonExclusionStrategy(JsonFeature.Serialization sf) { + this.sf = sf; + } + + @Override + public boolean shouldSkipField(FieldAttributes f) { + return f.hasModifier(Modifier.FINAL) || f.hasModifier(Modifier.STATIC) || + sf.isSkipTransientField() && f.hasModifier(Modifier.TRANSIENT); + } + + @Override + public boolean shouldSkipClass(Class clazz) { + return false; + } + } + private static class BigDecimalToPlainStringSerializer implements JsonSerializer { @Override public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) { diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java index dafb4b3..cb3ccb2 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForJackson.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.json; import java.io.IOException; +import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -31,6 +32,12 @@ public class JsonServiceForJackson extends JsonServiceForBase { return parseAsObject(string, clazz, deserializationFeature); } + @Override + public T convert(Object object, Type type) { + String string = toJsonString(object, serializationFeature); + return parseAsObject(string, type, deserializationFeature); + } + @Override public String toJsonString(Object object, JsonFeature.Serialization feature) { if (object == null) { @@ -71,6 +78,20 @@ public class JsonServiceForJackson extends JsonServiceForBase { } } + @Override + public T parseAsObject(String jsonString, Type type, JsonFeature.Deserialization feature) { + if (jsonString == null || jsonString.trim().length() == 0) { + return null; + } + ObjectMapper mapper = generateObjectMapper(serializationFeature, feature); + JavaType javaType = mapper.getTypeFactory().constructType(type); + try { + return mapper.readValue(jsonString, javaType); + } catch (IOException e) { + throw new ServiceException(ResultCode.SERVER_INNER_ERROR, e).setDetails("parse json object string error"); + } + } + @Override public T parseAsObject(String jsonString, Class clazz, JsonFeature.Deserialization feature) { if (jsonString == null || jsonString.trim().length() == 0) { -- Gitee From 2bbe825b9fa1b7f15b740e62597c38a942620986 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:57:27 +0800 Subject: [PATCH 61/82] =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/tools/compare/CompareTools.java | 20 +++++++++++++++---- .../com/gitee/qdbp/tools/utils/MapTools.java | 6 ++++++ .../gitee/qdbp/tools/utils/ReflectTools.java | 13 ++++++++++++ .../qdbp/tools/utils/ThrowableToStrings.java | 5 +++-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java b/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java index db30486..a4bd946 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/compare/CompareTools.java @@ -52,25 +52,37 @@ public class CompareTools { */ @SuppressWarnings("all") public static void sort(List> list, Orderings orderings) { + sort(list, orderings, false); + } + + /** + * 对Map列表进行排序 + * + * @param list 列表数据 + * @param orderings 排序规则, e.g. Orderings.of("dept desc, birthday asc, name desc"); + * @param nullsLow 空值优先级: true=空值排最前, false=空值排最后 + */ + @SuppressWarnings("all") + public static void sort(List> list, Orderings orderings, boolean nullsLow) { if (list == null || list.isEmpty() || orderings == null || orderings.isEmpty()) { return; } if (orderings.size() == 1) { - Collections.sort(list, newMapFieldComparator(orderings.get(0))); + Collections.sort(list, newMapFieldComparator(orderings.get(0), nullsLow)); return; } // dept desc, birthday asc, name desc ComplexComparator> comparator = new ComplexComparator<>(); for (Ordering ordering : orderings) { - comparator.addComparator(newMapFieldComparator(ordering)); + comparator.addComparator(newMapFieldComparator(ordering, nullsLow)); } Collections.sort(list, comparator); } - private static MapFieldComparator newMapFieldComparator(Ordering ordering) { + private static MapFieldComparator newMapFieldComparator(Ordering ordering, boolean nullsLow) { String orderBy = ordering.getOrderBy(); boolean ascending = !OrderType.DESC.equals(ordering.getOrderType()); - return new MapFieldComparator<>(orderBy, ascending); + return new MapFieldComparator<>(orderBy, nullsLow, ascending); } /** 链式比较多个字段 **/ diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index faa9042..d422c93 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -395,6 +395,9 @@ public class MapTools { * @return 是否存在 */ public static boolean containsKey(Map map, String key) { + if (map == null) { + return false; + } if (key == null || map.containsKey(key)) { return map.containsKey(key); } else if (isComplexKey(key)) { @@ -424,6 +427,9 @@ public class MapTools { * @return Map值 */ public static Object getValue(Map map, String key) { + if (map == null) { + return null; + } if (key == null || map.containsKey(key)) { if (map instanceof ExpressionMap) { return ((ExpressionMap) map).getOriginal(key); diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java index 4aebb58..e5f213a 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ReflectTools.java @@ -1066,6 +1066,19 @@ public abstract class ReflectTools { return getMethodLogSignature(clazz, clazz.getSimpleName(), constructor.getParameterTypes()); } + /** + * 获取方法签名的简要描述 + * + * @param method 方法 + * @return 方法签名描述 + */ + public static String getMethodLogSignature(Method method) { + Class clazz = method.getDeclaringClass(); + String methodName = method.getName(); + Class[] parameterTypes = method.getParameterTypes(); + return getMethodLogSignature(clazz, methodName, parameterTypes); + } + /** * 获取方法签名的简要描述 * diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java index ee2e47e..33d6630 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java @@ -40,8 +40,9 @@ public class ThrowableToStrings { int size = 0; for (int i = 0; i < (ste.length - numberOfcommonFrames); i++) { // size<1, 保留报错的那一行信息 - if (size < 1 || matcher == null || matcher.matches(ste[i].getClassName())) { - strList.add("\tat " + ste[i].toString()); + String trace = ste[i].toString(); + if (size < 1 || matcher == null || matcher.matches(trace)) { + strList.add("\tat " + trace); size++; } } -- Gitee From 9e22989d53bba4106677ba856003e20b0005e28a Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:57:44 +0800 Subject: [PATCH 62/82] =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/able/exception/ServiceException.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java index bc03520..6f3f7a0 100644 --- a/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java +++ b/able/src/main/java/com/gitee/qdbp/able/exception/ServiceException.java @@ -88,6 +88,11 @@ public class ServiceException extends RuntimeException implements IResultExcepti this.details = details; } + /** 判断是不是特定的异常 **/ + public boolean is(IResultMessage rm) { + return rm.getCode().equals(this.getCode()); + } + /** * 获取错误返回码 * -- Gitee From 12610fb991753440543de19eb7f3f0c58ce36b0f Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:58:35 +0800 Subject: [PATCH 63/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0json=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/json/test/TestCase1.java | 31 +++++++++++++++++++ .../qdbp/json/test/TestCase1ForFastJson.java | 5 +++ .../qdbp/json/test/TestCase1ForGson.java | 5 +++ .../qdbp/json/test/TestCase1ForJackson.java | 5 +++ 4 files changed, 46 insertions(+) diff --git a/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java b/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java index ee0d28f..62acfe0 100644 --- a/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java +++ b/test/qdbp-json-test-base/src/main/java/com/gitee/qdbp/json/test/TestCase1.java @@ -1,18 +1,25 @@ package com.gitee.qdbp.json.test; +import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.testng.Assert; +import com.gitee.qdbp.able.beans.KeyValue; import com.gitee.qdbp.json.JsonFeature; import com.gitee.qdbp.json.JsonService; import com.gitee.qdbp.json.test.entity.Address; import com.gitee.qdbp.json.test.entity.Child; import com.gitee.qdbp.json.test.entity.Father; import com.gitee.qdbp.json.test.entity.Gender; +import com.gitee.qdbp.tools.utils.AssertTools; import com.gitee.qdbp.tools.utils.JsonTools; import com.gitee.qdbp.tools.utils.MapTools; +import com.gitee.qdbp.tools.utils.ReflectTools; /** * TestCase1 @@ -109,4 +116,28 @@ public class TestCase1 { int n1 = JsonTools.convert(null, int.class); Assert.assertEquals(n1, 0); } + + public void test7() { + Method method = ReflectTools.findMethod(ResultType.class, "test"); + Type returnType = method.getGenericReturnType(); + KeyValue item = new KeyValue<>("A001", 10001); + Map source = new LinkedHashMap<>(); + source.put("1", item); + + String jsonString = JsonTools.toJsonString(source); + System.out.println(jsonString); + Map> result = JsonTools.parseAsObject(jsonString, returnType); + + AssertTools.assertDeepEquals(result.keySet(), Collections.singleton(1)); + KeyValue object = result.get(1); + Assert.assertEquals(object.getClass(), KeyValue.class); + Assert.assertEquals(object.getValue().getClass(), Long.class); + } + + public static class ResultType { + + public Map> test() { + return null; + } + } } diff --git a/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java b/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java index 73db2a1..01c664a 100644 --- a/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java +++ b/test/qdbp-json-test-fastjson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForFastJson.java @@ -45,4 +45,9 @@ public class TestCase1ForFastJson extends TestCase1 { public void test6() { super.test6(); } + + @Test + public void test7() { + super.test7(); + } } diff --git a/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java b/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java index c40bc99..e72fdfa 100644 --- a/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java +++ b/test/qdbp-json-test-gson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForGson.java @@ -40,4 +40,9 @@ public class TestCase1ForGson extends TestCase1 { public void test6() { super.test6(); } + + @Test + public void test7() { + super.test7(); + } } diff --git a/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java b/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java index b4803b6..dd260c8 100644 --- a/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java +++ b/test/qdbp-json-test-jackson/src/test/java/com/gitee/qdbp/json/test/TestCase1ForJackson.java @@ -46,4 +46,9 @@ public class TestCase1ForJackson extends TestCase1 { public void test6() { super.test6(); } + + @Test + public void test7() { + super.test7(); + } } -- Gitee From ef2f9725e1d166ade676a71b0842de9ef4546a8b Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 22:59:04 +0800 Subject: [PATCH 64/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0TreeNodes=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/able/beans/TreeNodesTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java index 244ba30..c323319 100644 --- a/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java +++ b/test/qdbp-tools-test-jdk8/src/test/java/com/gitee/qdbp/able/beans/TreeNodesTest.java @@ -104,6 +104,12 @@ public class TreeNodesTest { "T0301", "T030101", "T030103", "T030104", "T030105", "T0303", "T030301", "T030303", "T030304", "T030305")); } + + tree.removeElements("T02"); + List currElements = tree.getAllLeafElements(); + AssertTools.assertDeepEquals(currElements, Arrays.asList( + "T010101", "T010103", "T010104", "T010105", "T010301", "T010303", "T010304", "T010305", + "T030101", "T030103", "T030104", "T030105", "T030301", "T030303", "T030304", "T030305")); } public void test2() { @@ -194,6 +200,12 @@ public class TreeNodesTest { "T0301", "T030101", "T030103", "T030104", "T030105", "T0303", "T030301", "T030303", "T030304", "T030305")); } + + tree.removeElements("T02"); + List currElements = tree.getAllLeafElements(); + AssertTools.assertDeepEquals(currElements, asTreeNodeList( + "T010101", "T010103", "T010104", "T010105", "T010301", "T010303", "T010304", "T010305", + "T030101", "T030103", "T030104", "T030105", "T030301", "T030303", "T030304", "T030305")); } @@ -213,7 +225,7 @@ public class TreeNodesTest { return beans; } - private List asTreeNodeList(String ... codes) { + private List asTreeNodeList(String... codes) { List beans = new ArrayList<>(); for (String item : codes) { beans.add(new TreeNode(item)); -- Gitee From 6a712c7291e9ac26e37dfdd7682fa6fb94e39afb Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Wed, 23 Aug 2023 23:00:15 +0800 Subject: [PATCH 65/82] 5.6.230820 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 98bb1ac..adc0bae 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230815 + 5.6.230820 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230815 + 5.6.230820 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index a473a2c..2e07f68 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230815 + 5.6.230820 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 77f42ab..987828f 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230815 + 5.6.230820 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230815 + 5.6.230820 diff --git a/test/pom.xml b/test/pom.xml index 8021f0e..2e54e0c 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230815 + 5.6.230820 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index 2498d6e..d250b47 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 29e661c..11184c2 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 857ab51..f734508 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index eb01039..71122cf 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 924f81e..2c0c6b2 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index a09f689..d906897 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230815 + 5.6.230820 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 25117f4..4d6b05c 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230815 + 5.6.230820 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 130e2ef5c4d9c45735669510656780d73e31fbff Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:12:26 +0800 Subject: [PATCH 66/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=AC=E5=85=B1?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E8=BF=94=E5=9B=9E=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gitee/qdbp/able/result/ResultCode.java | 6 ++++++ .../resources/settings/i18n/ResultCode_zh_CN.properties | 2 ++ 2 files changed, 8 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java index d4836d5..702996d 100644 --- a/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java +++ b/able/src/main/java/com/gitee/qdbp/able/result/ResultCode.java @@ -79,6 +79,12 @@ public enum ResultCode implements IResultMessage { /** 系统配置错误 **/ SYSTEM_CONFIG_ERROR, + /** 系统配置不存在 **/ + SYSTEM_CONFIG_NOT_FOUND, + + /** 数据转换失败 **/ + DATA_CONVERT_ERROR, + /** 不支持该操作 **/ UNSUPPORTED_OPERATION; diff --git a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties index da5ddc3..627aa3d 100644 --- a/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties +++ b/able/src/main/resources/settings/i18n/ResultCode_zh_CN.properties @@ -22,4 +22,6 @@ FORBIDDEN = 没有权限 ACCESS_DENIED = 访问被拒绝 OPERATE_TIMEOUT = 操作已超时 SYSTEM_CONFIG_ERROR = 系统配置错误 +SYSTEM_CONFIG_NOT_FOUND = 系统配置不存在 +DATA_CONVERT_ERROR = 数据转换失败 UNSUPPORTED_OPERATION = 不支持该操作 -- Gitee From 6568d46282810eea45669104048db1fe68099c89 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:14:11 +0800 Subject: [PATCH 67/82] tryCopyObject --- .../com/gitee/qdbp/tools/utils/ConvertTools.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 8ba11a7..8905d05 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -1686,6 +1686,20 @@ public class ConvertTools { return result; } + /** + * 深度复制对象
+ * 调用Copyable的copy()方法进行复制
+ * List/Set/Map容器将会循环递归复制其中的内容
+ * 与deepCopyObject的不同是, 这个方法不会抛出异常 + * + * @param value 原对象 + * @return 复制后的对象 + * @param 对象类型 + */ + public static T tryCopyObject(T value) { + return doDeepCopyObject(value); + } + @SuppressWarnings("unchecked") private static T doDeepCopyObject(T value) { if (value == null) { -- Gitee From a559a23547932f088555277c0bf03f378f219523 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:15:51 +0800 Subject: [PATCH 68/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ClassTools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ClassTools.java | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java new file mode 100644 index 0000000..89f5e71 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ClassTools.java @@ -0,0 +1,317 @@ +/* + * Copyright 2002-2022 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 com.gitee.qdbp.tools.utils; + +import java.io.Closeable; +import java.io.Externalizable; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + + +/** + * Miscellaneous {@code java.lang.Class} utility methods. + * Mainly for internal use within the framework. + * + * @author Juergen Hoeller + * @author Keith Donald + * @author Rob Harrop + * @author Sam Brannen + * @since 1.1 + */ +public abstract class ClassTools { + + /** Suffix for array class names: {@code "[]"}. */ + public static final String ARRAY_SUFFIX = "[]"; + + /** Prefix for internal array class names: {@code "["}. */ + private static final String INTERNAL_ARRAY_PREFIX = "["; + + /** Prefix for internal non-primitive array class names: {@code "[L"}. */ + private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L"; + + /** The package separator character: {@code '.'}. */ + private static final char PACKAGE_SEPARATOR = '.'; + + /** The nested class separator character: {@code '$'}. */ + private static final char NESTED_CLASS_SEPARATOR = '$'; + + /** The CGLIB class separator: {@code "$$"}. */ + public static final String CGLIB_CLASS_SEPARATOR = "$$"; + + /** The ".class" file suffix. */ + public static final String CLASS_FILE_SUFFIX = ".class"; + + /** + * Map with primitive wrapper type as key and corresponding primitive + * type as value, for example: Integer.class -> int.class. + */ + private static final Map, Class> primitiveWrapperTypeMap = new IdentityHashMap<>(9); + + /** + * Map with primitive type name as key and corresponding primitive + * type as value, for example: "int" -> "int.class". + */ + private static final Map> primitiveTypeNameMap = new HashMap<>(32); + + /** + * Map with common Java language class name as key and corresponding Class as value. + * Primarily for efficient deserialization of remote invocations. + */ + private static final Map> commonClassCache = new HashMap<>(64); + + static { + primitiveWrapperTypeMap.put(Boolean.class, boolean.class); + primitiveWrapperTypeMap.put(Byte.class, byte.class); + primitiveWrapperTypeMap.put(Character.class, char.class); + primitiveWrapperTypeMap.put(Double.class, double.class); + primitiveWrapperTypeMap.put(Float.class, float.class); + primitiveWrapperTypeMap.put(Integer.class, int.class); + primitiveWrapperTypeMap.put(Long.class, long.class); + primitiveWrapperTypeMap.put(Short.class, short.class); + primitiveWrapperTypeMap.put(Void.class, void.class); + + Set> primitiveTypes = new HashSet<>(32); + primitiveTypes.addAll(primitiveWrapperTypeMap.values()); + Collections.addAll(primitiveTypes, boolean[].class, byte[].class, char[].class, + double[].class, float[].class, int[].class, long[].class, short[].class); + for (Class primitiveType : primitiveTypes) { + primitiveTypeNameMap.put(primitiveType.getName(), primitiveType); + } + + registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class, + Float[].class, Integer[].class, Long[].class, Short[].class); + registerCommonClasses(Number.class, Number[].class, String.class, String[].class, + Class.class, Class[].class, Object.class, Object[].class); + registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class, + Error.class, StackTraceElement.class, StackTraceElement[].class); + registerCommonClasses(Enum.class, Iterable.class, Iterator.class, Enumeration.class, + Collection.class, List.class, Set.class, Map.class, Map.Entry.class, Optional.class); + + Class[] javaLanguageInterfaceArray = {Serializable.class, Externalizable.class, + Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class}; + registerCommonClasses(javaLanguageInterfaceArray); + } + + + /** + * Register the given common classes with the ClassUtils cache. + */ + private static void registerCommonClasses(Class... commonClasses) { + for (Class clazz : commonClasses) { + commonClassCache.put(clazz.getName(), clazz); + } + } + + /** + * Return the default ClassLoader to use: typically the thread context + * ClassLoader, if available; the ClassLoader that loaded the ClassUtils + * class will be used as fallback. + *

Call this method if you intend to use the thread context ClassLoader + * in a scenario where you clearly prefer a non-null ClassLoader reference: + * for example, for class path resource loading (but not necessarily for + * {@code Class.forName}, which accepts a {@code null} ClassLoader + * reference as well). + * @return the default ClassLoader (only {@code null} if even the system + * ClassLoader isn't accessible) + * @see Thread#getContextClassLoader() + * @see ClassLoader#getSystemClassLoader() + */ + public static ClassLoader getDefaultClassLoader() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } + catch (Throwable ex) { + // Cannot access thread context ClassLoader - falling back... + } + if (cl == null) { + // getClassLoader() returning null indicates the bootstrap ClassLoader + try { + cl = ClassLoader.getSystemClassLoader(); + } + catch (Throwable ex) { + // Cannot access system ClassLoader - oh well, maybe the caller can live with null... + } + } + return cl; + } + + /** + * Replacement for {@code Class.forName()} that also returns Class instances + * for primitives (e.g. "int") and array class names (e.g. "String[]"). + * Furthermore, it is also capable of resolving nested class names in Java source + * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State"). + * @param name the name of the Class + * (may be {@code null}, which indicates the default class loader) + * @return a class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + */ + public static Class forName(String name) throws ClassNotFoundException, LinkageError { + return forName(name, null); + } + + /** + * Replacement for {@code Class.forName()} that also returns Class instances + * for primitives (e.g. "int") and array class names (e.g. "String[]"). + * Furthermore, it is also capable of resolving nested class names in Java source + * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State"). + * @param name the name of the Class + * @param classLoader the class loader to use + * (may be {@code null}, which indicates the default class loader) + * @return a class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + */ + public static Class forName(String name, ClassLoader classLoader) + throws ClassNotFoundException, LinkageError { + + VerifyTools.requireNonNull(name, "className"); + + Class clazz = resolvePrimitiveClassName(name); + if (clazz == null) { + clazz = commonClassCache.get(name); + } + if (clazz != null) { + return clazz; + } + + // "java.lang.String[]" style arrays + if (name.endsWith(ARRAY_SUFFIX)) { + String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length()); + Class elementClass = forName(elementClassName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + // "[Ljava.lang.String;" style arrays + if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) { + String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1); + Class elementClass = forName(elementName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + // "[[I" or "[[Ljava.lang.String;" style arrays + if (name.startsWith(INTERNAL_ARRAY_PREFIX)) { + String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length()); + Class elementClass = forName(elementName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + ClassLoader clToUse = classLoader; + if (clToUse == null) { + clToUse = getDefaultClassLoader(); + } + try { + return Class.forName(name, false, clToUse); + } + catch (ClassNotFoundException ex) { + int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); + if (lastDotIndex != -1) { + String nestedClassName = + name.substring(0, lastDotIndex) + NESTED_CLASS_SEPARATOR + name.substring(lastDotIndex + 1); + try { + return Class.forName(nestedClassName, false, clToUse); + } + catch (ClassNotFoundException ex2) { + // Swallow - let original exception get through + } + } + throw ex; + } + } + + /** + * Determine whether the {@link Class} identified by the supplied name is present + * and can be loaded. Will return {@code false} if either the class or + * one of its dependencies is not present or cannot be loaded. + * @param className the name of the class to check + * (may be {@code null} which indicates the default class loader) + * @return whether the specified class is present (including all of its + * superclasses and interfaces) + * @throws IllegalStateException if the corresponding class is resolvable but + * there was a readability mismatch in the inheritance hierarchy of the class + * (typically a missing dependency declaration in a Jigsaw module definition + * for a superclass or interface implemented by the class to be checked here) + */ + public static boolean isPresent(String className) { + return isPresent(className, null); + } + + /** + * Determine whether the {@link Class} identified by the supplied name is present + * and can be loaded. Will return {@code false} if either the class or + * one of its dependencies is not present or cannot be loaded. + * @param className the name of the class to check + * @param classLoader the class loader to use + * (may be {@code null} which indicates the default class loader) + * @return whether the specified class is present (including all of its + * superclasses and interfaces) + * @throws IllegalStateException if the corresponding class is resolvable but + * there was a readability mismatch in the inheritance hierarchy of the class + * (typically a missing dependency declaration in a Jigsaw module definition + * for a superclass or interface implemented by the class to be checked here) + */ + public static boolean isPresent(String className, ClassLoader classLoader) { + try { + forName(className, classLoader); + return true; + } + catch (IllegalAccessError err) { + throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" + + className + "]: " + err.getMessage(), err); + } + catch (Throwable ex) { + // Typically ClassNotFoundException or NoClassDefFoundError... + return false; + } + } + + /** + * Resolve the given class name as primitive class, if appropriate, + * according to the JVM's naming rules for primitive classes. + *

Also supports the JVM's internal class names for primitive arrays. + * Does not support the "[]" suffix notation for primitive arrays; + * this is only supported by {@link #forName(String, ClassLoader)}. + * @param name the name of the potentially primitive class + * @return the primitive class, or {@code null} if the name does not denote + * a primitive class or primitive array class + */ + public static Class resolvePrimitiveClassName(String name) { + Class result = null; + // Most class names will be quite long, considering that they + // SHOULD sit in a package, so a length check is worthwhile. + if (name != null && name.length() <= 7) { + // Could be a primitive - likely. + result = primitiveTypeNameMap.get(name); + } + return result; + } + +} -- Gitee From a6ea7f3d9cc9a8206c74d0243e1b74511b1dabf0 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:29:01 +0800 Subject: [PATCH 69/82] =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/files/PathTools.java | 50 ++++++++++++------- .../gitee/qdbp/tools/utils/JsonFactory.java | 24 +++------ .../qdbp/tools/utils/ThrowableToStrings.java | 8 +-- .../{json-service.yml => JsonService.yml} | 0 4 files changed, 42 insertions(+), 40 deletions(-) rename able/src/main/resources/settings/global/{json-service.yml => JsonService.yml} (100%) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java index 9b3f925..9ee481b 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/PathTools.java @@ -33,12 +33,16 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; import java.util.zip.ZipException; +import com.gitee.qdbp.able.beans.KeyString; +import com.gitee.qdbp.able.enums.FileErrorCode; import com.gitee.qdbp.able.exception.ResourceNotFoundException; +import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.matches.AntFileMatcher; import com.gitee.qdbp.able.matches.FileMatcher; import com.gitee.qdbp.able.matches.FileMatcher.Target; import com.gitee.qdbp.able.matches.StringMatcher.LogicType; import com.gitee.qdbp.able.matches.WrapFileMatcher; +import com.gitee.qdbp.tools.utils.ClassTools; import com.gitee.qdbp.tools.utils.StringTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -205,23 +209,9 @@ public abstract class PathTools { } } + @Deprecated public static ClassLoader getDefaultClassLoader() { - ClassLoader cl = null; - try { - cl = Thread.currentThread().getContextClassLoader(); - } catch (Throwable ex) { - // Cannot access thread context ClassLoader - falling back... - } - if (cl == null) { - // No thread context class loader -> use class loader of this class. - // getClassLoader() returning null indicates the bootstrap ClassLoader - try { - cl = ClassLoader.getSystemClassLoader(); - } catch (Throwable ex) { - // Cannot access system ClassLoader - oh well, maybe the caller can live with null... - } - } - return cl; + return ClassTools.getDefaultClassLoader(); } /** @@ -563,6 +553,28 @@ public abstract class PathTools { } } + /** + * 按名称扫描文本资源并返回文件内容 + * + * @param resource 资源路径, 不支持通配符 + * @return 资源内容, key=文件路径, value=文件内容 + * @throws ResourceNotFoundException 资源查找失败, 资源不存在 + */ + public static KeyString scanTextResource(String resource) { + List urls = PathTools.scanResources(resource); + if (urls.isEmpty()) { + throw new ResourceNotFoundException().setDetails(resource); + } + URL url = urls.get(0); + String urlPath = PathTools.getJarRelativePath(url); + try { + String content = PathTools.downloadString(url); + return new KeyString(urlPath, content); + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails(urlPath); + } + } + /** * 查找资源
* classpath:/mmm/nnn.txt = classpath:mmm/nnn.txt -- 相对路径
@@ -863,7 +875,7 @@ public abstract class PathTools { } private static URL getClassLoaderResource(String path) { - ClassLoader cl = getDefaultClassLoader(); + ClassLoader cl = ClassTools.getDefaultClassLoader(); String temp = path; if (path.startsWith("/") || path.startsWith("\\")) { temp = path.substring(1); // 通过ClassLoader获取, 如果路径是/开头的, 会获取失败 @@ -872,7 +884,7 @@ public abstract class PathTools { } private static Enumeration getClassLoaderResources(String path) throws IOException { - ClassLoader cl = getDefaultClassLoader(); + ClassLoader cl = ClassTools.getDefaultClassLoader(); String temp = path; if (path.startsWith("/") || path.startsWith("\\")) { temp = path.substring(1); // 通过ClassLoader获取, 如果路径是/开头的, 会获取失败 @@ -881,7 +893,7 @@ public abstract class PathTools { } private static URL getClassPathUrl() { - ClassLoader cl = getDefaultClassLoader(); + ClassLoader cl = ClassTools.getDefaultClassLoader(); return cl != null ? cl.getResource("") : ClassLoader.getSystemResource(""); } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java index 3d06e73..62285b1 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonFactory.java @@ -1,12 +1,10 @@ package com.gitee.qdbp.tools.utils; -import java.io.IOException; -import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; +import com.gitee.qdbp.able.beans.KeyString; import com.gitee.qdbp.able.beans.StringWithAttrs; -import com.gitee.qdbp.able.enums.FileErrorCode; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.result.ResultCode; import com.gitee.qdbp.json.JsonService; @@ -67,21 +65,13 @@ class JsonFactory { } private static synchronized JsonService findConfigJsonService() { - String configPath = "settings/global/json-service.yml"; - List urls = PathTools.scanResources(configPath); - - URL url = urls.get(0); - String string; - String path = PathTools.getJarRelativePath(url); - try { - string = PathTools.downloadString(url); - } catch (IOException e) { - throw new ServiceException(FileErrorCode.FILE_READ_ERROR, e).setDetails(path); - } - Map roots = RuleTools.splitRuleKeyValues(string).asMap(); + String configPath = "settings/global/JsonService.yml"; + KeyString resource = PathTools.scanTextResource(configPath); + String path = resource.getKey(); + Map roots = RuleTools.splitRuleKeyValues(resource.getValue()).asMap(); String rootValue = roots.get("json-service"); if (VerifyTools.isBlank(rootValue)) { - throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR) + throw new ServiceException(ResultCode.SYSTEM_CONFIG_NOT_FOUND) .setDetails("json-service config missing --> " + path); } List contents = RuleTools.splitRuleWithAttrs(rootValue); @@ -138,6 +128,6 @@ class JsonFactory { // 所有requiredClass都不在jvm当中 String msg = "JsonService instance not found for [{}] --> {}"; String traces = ConvertTools.joinToString(names); - throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR).setDetails(msg, traces, path); + throw new ServiceException(ResultCode.SERVER_INNER_ERROR).setDetails(msg, traces, path); } } diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java index 33d6630..f518900 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ThrowableToStrings.java @@ -34,11 +34,11 @@ public class ThrowableToStrings { StringMatcher matcher) { StackTraceElement[] ste = t.getStackTrace(); - final int numberOfcommonFrames = findNumberOfCommonFrames(ste, parentSTE); + final int numberOfCommonFrames = findNumberOfCommonFrames(ste, parentSTE); strList.add(formatFirstLine(t, parentSTE)); int size = 0; - for (int i = 0; i < (ste.length - numberOfcommonFrames); i++) { + for (int i = 0; i < (ste.length - numberOfCommonFrames); i++) { // size<1, 保留报错的那一行信息 String trace = ste[i].toString(); if (size < 1 || matcher == null || matcher.matches(trace)) { @@ -47,8 +47,8 @@ public class ThrowableToStrings { } } - // if (numberOfcommonFrames != 0) { - // strList.add("\t... " + numberOfcommonFrames + " common frames omitted"); + // if (numberOfCommonFrames != 0) { + // strList.add("\t... " + numberOfCommonFrames + " common frames omitted"); // } Throwable cause = t.getCause(); diff --git a/able/src/main/resources/settings/global/json-service.yml b/able/src/main/resources/settings/global/JsonService.yml similarity index 100% rename from able/src/main/resources/settings/global/json-service.yml rename to able/src/main/resources/settings/global/JsonService.yml -- Gitee From ab6562452985453f13493a4cc950a745ea89b500 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:29:26 +0800 Subject: [PATCH 70/82] convertObjectToMap --- .../com/gitee/qdbp/tools/utils/JsonTools.java | 55 +++++++++++++++++++ .../com/gitee/qdbp/tools/utils/MapTools.java | 21 +------ 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java index 9ce11ac..71ec29e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/JsonTools.java @@ -6,10 +6,14 @@ import java.math.BigInteger; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import com.gitee.qdbp.able.beans.LinkedListMap; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.result.ResultCode; import com.gitee.qdbp.json.JsonFeature; /** @@ -44,6 +48,12 @@ public class JsonTools extends JsonMaps { if (object instanceof String) { return convertStringValue((String) object, clazz); } + if (clazz == Map.class) { + return convertObjectToMap(object); + } + if (clazz == boolean.class || clazz == Boolean.class) { + return (T) convertObjectToBoolean(object, clazz); + } return findDefaultJsonService().convert(object, clazz); } @@ -95,6 +105,26 @@ public class JsonTools extends JsonMaps { } } + private static Boolean convertObjectToBoolean(Object object, Class clazz) { + if (object instanceof Boolean) { + return ((Boolean) object); + } + if (object instanceof Number) { + return ((Number) object).doubleValue() != 0; + } + if (object instanceof CharSequence || object instanceof Character) { + String string = object.toString(); + Boolean result = StringTools.isPositive(string, null); + if (result != null) { + return result; + } + throw new ServiceException(ResultCode.DATA_CONVERT_ERROR) + .setDetails(StringTools.ellipsis(string, 30) + " can't convert to " + clazz.getSimpleName()); + } + throw new ServiceException(ResultCode.DATA_CONVERT_ERROR) + .setDetails(object.getClass().getSimpleName() + " can't convert to " + clazz.getSimpleName()); + } + @SuppressWarnings("unchecked") private static T convertStringValue(String string, Class clazz) { if (clazz == Date.class) { @@ -115,6 +145,12 @@ public class JsonTools extends JsonMaps { if (clazz == boolean.class || clazz == Boolean.class) { return (T) Boolean.valueOf(ConvertTools.toBoolean(string)); } + if (clazz == byte.class || clazz == Byte.class) { + return (T) Byte.valueOf(string); + } + if (clazz == short.class || clazz == Short.class) { + return (T) Short.valueOf(string); + } if (VerifyTools.isJsonObjectString(string)) { if (clazz == Map.class) { return (T) parseAsMap(string); @@ -122,6 +158,9 @@ public class JsonTools extends JsonMaps { if (clazz == HashMap.class) { return (T) new HashMap<>(parseAsMap(string)); } + if (clazz == LinkedHashMap.class) { + return (T) new LinkedHashMap<>(parseAsMap(string)); + } if (!ReflectTools.isPrimitive(clazz, false) && !clazz.isArray() && !Collection.class.isAssignableFrom(clazz)) { Map map = parseAsMap(string); @@ -131,6 +170,22 @@ public class JsonTools extends JsonMaps { return findDefaultJsonService().convert(string, clazz); } + @SuppressWarnings("unchecked") + private static T convertObjectToMap(Object object) { + if (object instanceof Map) { + return (T) MapTools.toJsonMap((Map) object); + } else if (VerifyTools.isPlainObject(object)) { + return (T) beanToMap(object, true, false); + } else if (VerifyTools.isCollection(object)) { + // 如果结果是数组, 包装成Map返回 + List objects = ConvertTools.parseList(object); + return (T) new LinkedListMap(beanToMaps(objects, true, false)); + } else { + throw new ServiceException(ResultCode.DATA_CONVERT_ERROR) + .setDetails(object.getClass().getSimpleName() + " can't convert to Map"); + } + } + /** 对象转换为字符串 **/ public static String toJsonString(Object object) { return findDefaultJsonService().toJsonString(object); diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java index d422c93..85ee76e 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/MapTools.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import com.gitee.qdbp.able.beans.DepthMap; -import com.gitee.qdbp.able.beans.LinkedListMap; import com.gitee.qdbp.able.exception.ServiceException; import com.gitee.qdbp.able.model.entry.EachEntry; import com.gitee.qdbp.able.model.entry.EntryItem; @@ -456,28 +455,12 @@ public class MapTools { return convertValue(value, null, clazz); } - @SuppressWarnings("unchecked") private static T convertValue(Object value, T defaults, Class clazz) { if (value == null && defaults != null) { return defaults; } else { - if (clazz == Map.class) { - List objects = ConvertTools.parseList(value); - if (objects.size() == 1 && objects.get(0) == value) { - // 如果列表容器只有value一个元素, 说明value不是列表 - return (T) toJsonMap((Map) value); - } else { - // 如果结果是数组, 包装成Map返回 - return (T) new LinkedListMap(JsonTools.beanToMaps(objects, true, false)); - } - } else { - try { - T result = JsonTools.convert(value, clazz); - return result != null ? result : defaults; - } catch (Exception e) { - return defaults; - } - } + T result = JsonTools.convert(value, clazz); + return result != null ? result : defaults; } } -- Gitee From c5ac6b24b76e8b8ce2c429b5ed7ae6f7f7bf7eaa Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:30:43 +0800 Subject: [PATCH 71/82] =?UTF-8?q?=E8=BF=94=E5=9B=9E=E8=A7=A3=E5=8E=8B?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gitee/qdbp/tools/files/ZipTools.java | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java b/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java index 6205e3f..152db18 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/files/ZipTools.java @@ -4,7 +4,6 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -13,6 +12,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -32,12 +32,13 @@ public class ZipTools { /** * ZIP文件解压 - * + * * @param srcPath 源文件 * @param saveFolder 保存文件的路径 + * @return 解压后的文件相对路径 */ - public static void decompression(String srcPath, String saveFolder) throws IOException { - decompression(srcPath, saveFolder, StandardCharsets.UTF_8); + public static List decompression(String srcPath, String saveFolder) throws IOException { + return decompression(new File(srcPath), saveFolder, StandardCharsets.UTF_8); } /** @@ -46,13 +47,37 @@ public class ZipTools { * @param srcPath 源文件 * @param saveFolder 保存文件的路径 * @param charset 编码格式 + * @return 解压后的文件相对路径 + */ + public static List decompression(String srcPath, String saveFolder, Charset charset) throws IOException { + return decompression(new File(srcPath), saveFolder, StandardCharsets.UTF_8); + } + + /** + * ZIP文件解压 + * + * @param srcFile 源文件 + * @param saveFolder 保存文件的路径 + * @return 解压后的文件相对路径 + */ + public static List decompression(File srcFile, String saveFolder) throws IOException { + return decompression(srcFile, saveFolder, StandardCharsets.UTF_8); + } + + /** + * ZIP文件解压 + * + * @param srcFile 源文件 + * @param saveFolder 保存文件的路径 + * @param charset 编码格式 + * @return 解压后的文件相对路径 */ - public static void decompression(String srcPath, String saveFolder, Charset charset) throws IOException { - File srcFile = new File(srcPath); + public static List decompression(File srcFile, String saveFolder, Charset charset) throws IOException { if (!srcFile.exists()) { // 判断源文件是否存在 - throw new ResourceNotFoundException(srcPath); + throw new ResourceNotFoundException(srcFile.getPath()); } - String fileName = PathTools.removeExtension(new File(srcPath).getName()) + '/'; + List relativePaths = new ArrayList<>(); + String fileName = PathTools.removeExtension(srcFile.getName()) + '/'; // 开始解压 try (ZipFile zipFile = new ZipFile(srcFile, charset)) { Enumeration entries = zipFile.entries(); @@ -76,9 +101,11 @@ public class ZipTools { // 将压缩文件内容写入文件中 try (InputStream is = zipFile.getInputStream(entry); FileOutputStream os = new FileOutputStream(file)) { FileTools.copy(is, os); + relativePaths.add(relativePath); } } } + return relativePaths; } /** @@ -311,7 +338,7 @@ public class ZipTools { @Override public InputStream getInputStream() throws IOException { - return new FileInputStream(file); + return Files.newInputStream(file.toPath()); } } -- Gitee From ad4cc796082b31e1d8a23251e873a328738ec010 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:31:45 +0800 Subject: [PATCH 72/82] =?UTF-8?q?ClassLoader=E6=94=B9=E4=B8=BAClassTools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java b/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java index 3adb669..f5fb22f 100644 --- a/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java +++ b/able/src/main/java/com/gitee/qdbp/able/i18n/LocaleTools.java @@ -19,6 +19,7 @@ import java.util.ResourceBundle; import java.util.ResourceBundle.Control; import com.gitee.qdbp.able.exception.ResourceNotFoundException; import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.ClassTools; import com.gitee.qdbp.tools.utils.Config; import com.gitee.qdbp.tools.utils.StringTools; import com.gitee.qdbp.tools.utils.VerifyTools; @@ -257,7 +258,7 @@ public class LocaleTools { public InputStream run() throws IOException { List urls = PathTools.scanResources(resource); - ClassLoader threadLoader = PathTools.getDefaultClassLoader(); + ClassLoader threadLoader = ClassTools.getDefaultClassLoader(); if (threadLoader == null) { threadLoader = ClassLoader.getSystemClassLoader(); } -- Gitee From 889ff89853ae7160f5c01360457ae79eb8b4d998 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:32:27 +0800 Subject: [PATCH 73/82] =?UTF-8?q?VolatileData=E5=A2=9E=E5=8A=A0copy?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/able/beans/VolatileData.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java index e2062b5..d597ed8 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java @@ -1,6 +1,7 @@ package com.gitee.qdbp.able.beans; import java.io.Serializable; +import com.gitee.qdbp.tools.utils.ConvertTools; /** * 带有过期时间的数据 @@ -8,7 +9,7 @@ import java.io.Serializable; * @author zhaohuihua * @version 180223 */ -public class VolatileData implements Serializable { +public class VolatileData implements Copyable, Serializable { /** serialVersionUID **/ private static final long serialVersionUID = 1L; @@ -33,7 +34,7 @@ public class VolatileData implements Serializable { return this.value; } - // 设置过期时间(相对时间) + /** 设置过期时间(相对时间) **/ public VolatileData expire(Long expire) { if (expire != null) { this.expireTime = System.currentTimeMillis() + expire; @@ -41,13 +42,33 @@ public class VolatileData implements Serializable { return this; } - // 移除过期时间 + /** 设置过期时间(绝对时间) **/ + public VolatileData setExpireTime(Long expireTime) { + this.expireTime = expireTime; + return this; + } + + /** 获取过期时间(绝对时间) **/ + public Long getExpireTime() { + return expireTime; + } + + /** 移除过期时间 **/ public VolatileData persist() { this.expireTime = null; return this; } + /** 判断是否已过期 **/ public boolean expired() { return this.expireTime != null && this.expireTime < System.currentTimeMillis(); } + + @Override + public VolatileData copy() { + VolatileData newer = new VolatileData<>(); + newer.value = ConvertTools.tryCopyObject(this.value); + newer.expireTime = this.expireTime; + return newer; + } } -- Gitee From c0c17bb37a30aaf23d56a2d27f09eea028236840 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:33:09 +0800 Subject: [PATCH 74/82] =?UTF-8?q?NetworkTools=E5=A2=9E=E5=8A=A0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/NetworkTools.java | 146 +++++++++++++++++- .../settings/global/NetworkTools.yml | 13 ++ 2 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 able/src/main/resources/settings/global/NetworkTools.yml diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java index 8919445..62431a0 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/NetworkTools.java @@ -1,5 +1,6 @@ package com.gitee.qdbp.tools.utils; +import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; @@ -7,7 +8,16 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import com.gitee.qdbp.able.beans.KeyString; +import com.gitee.qdbp.able.beans.StringWithAttrs; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.matches.StringMatcher; +import com.gitee.qdbp.able.matches.WrapStringMatcher; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.files.PathTools; /** * 网络工具类 @@ -52,8 +62,18 @@ public class NetworkTools { return getLocalIpv4Addresses(); } + private static List CACHED_LOCAL_IPV4_ADDRESSES; + /** 获取本机IPv4地址 **/ public static List getLocalIpv4Addresses() { + // 查找NetworkTools.yml配置 + Map yaml = findYamlMaps(); + // 是否启用缓存 + boolean cacheEnabled = MapTools.getValue(yaml, "cacheEnabled", true, boolean.class); + if (cacheEnabled && CACHED_LOCAL_IPV4_ADDRESSES != null) { + return CACHED_LOCAL_IPV4_ADDRESSES; + } + String hostIp = findHostIp(yaml); // 遍历本机的所有网络接口 Enumeration networks; try { @@ -61,6 +81,10 @@ public class NetworkTools { } catch (SocketException e) { return new ArrayList<>(); } + // 忽略网卡的规则 + StringMatcher ignoreMatcher = findIgnoreRules(yaml); + // 可达检测等待毫秒数 + int reachableWaitMillis = findReachableWaitMillis(yaml); List iplist = new ArrayList<>(); List backup = new ArrayList<>(); while (networks.hasMoreElements()) { @@ -76,9 +100,8 @@ public class NetworkTools { continue; } String name = network.getDisplayName().toLowerCase(); - if (name.contains("virtual") || name.contains("veth") || name.contains("virbr") - || name.contains("docker")) { - continue; // 忽略虚拟机的IP地址 + if (ignoreMatcher != null && ignoreMatcher.matches(name)) { + continue; // 忽略指定的网卡 } // 遍历该网络接口绑定的IP地址 Enumeration addresses = network.getInetAddresses(); @@ -90,9 +113,16 @@ public class NetworkTools { if (address.isLoopbackAddress() || address.getHostAddress().startsWith("127")) { continue; // 忽略127.0.0.1地址, 127.xxx.xxx.xxx属于loopback, 只有本机可见 } - // if (!address.isReachable(50)) { - // continue; - // } + if (reachableWaitMillis > 0) { + // 检查是否可达 + try { + if (!address.isReachable(reachableWaitMillis)) { + continue; + } + } catch (IOException e) { + continue; + } + } if (address.isSiteLocalAddress()) { // 优先返回该地址 // 192.168.xxx.xxx属于private私有地址(SiteLocalAddress), 只能在本地局域网可见 // 公网地址一般都不会出现在网卡配置中, 都是通过映射访问的 @@ -104,6 +134,15 @@ public class NetworkTools { } } iplist.addAll(backup); + // 将配置的hostIp放在最前面 + if (hostIp != null) { + iplist.remove(hostIp); + iplist.add(0, hostIp); + } + if (cacheEnabled) { + // 缓存本机IP地址 + CACHED_LOCAL_IPV4_ADDRESSES = iplist; + } return iplist; } @@ -120,4 +159,99 @@ public class NetworkTools { } } } + + private static Map findYamlMaps() { + String configPath = "settings/global/NetworkTools.yml"; + KeyString resource = PathTools.scanTextResource(configPath); + String path = resource.getKey(); + Map roots = RuleTools.splitRuleKeyValues(resource.getValue()).asMap(); + String rootValue = roots.get("network-tools"); + if (VerifyTools.isBlank(rootValue)) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_NOT_FOUND) + .setDetails("network-tools config missing --> " + path); + } + List contents = RuleTools.splitRuleWithAttrs(rootValue); + if (contents.isEmpty()) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR) + .setDetails("network-tools config error --> " + path); + } + Map maps = new LinkedHashMap<>(); + for (StringWithAttrs content : contents) { + String name = StringTools.trimRight(content.getString(), ':', ' '); + if (VerifyTools.isBlank(content.getAttrs())) { + maps.put(name, null); + } else { + maps.putAll(content.getAttrs().asMap()); + } + } + return maps; + } + + private static String findHostIp(Map yaml) { + // 从NetworkTools.yml中获取hostIpKey(默认为host.ip) + String hostKey = MapTools.getString(yaml, "hostIpKey"); + if (VerifyTools.isBlank(hostKey)) { + return null; + } + // 从JVM环境变量中获取host.ip + String hostIp = getSystemProperty(hostKey); + if (VerifyTools.isBlank(hostIp)) { + return null; + } + try { + // host.ip可以配置IP或主机名, 转换为ip地址 + return InetAddress.getByName(hostIp).getHostAddress(); + } catch (UnknownHostException e) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR, e) + .setDetails(hostKey + "=" + hostIp); + } + } + + private static StringMatcher findIgnoreRules(Map yaml) { + // 从NetworkTools.yml中获取ignoreKey(默认为network.ignore) + String ignoreKey = MapTools.getString(yaml, "ignoreKey"); + if (VerifyTools.isBlank(ignoreKey)) { + return null; + } + // 从JVM环境变量中获取network.ignore + String configValue = getSystemProperty(ignoreKey); + if (VerifyTools.isBlank(configValue)) { + // 从NetworkTools.yml中获取ignoreNames + configValue = MapTools.getString(yaml, "ignoreNames"); + } + if (VerifyTools.isBlank(configValue)) { + return null; + } + List ignoreRules = StringTools.splits(configValue, ','); + return WrapStringMatcher.parseMatchers(ignoreRules, StringMatcher.LogicType.OR, "contains"); + } + + private static int findReachableWaitMillis(Map yaml) { + // 从NetworkTools.yml中获取reachableWaitKey(默认为network.reachable) + String reachableWaitKey = MapTools.getString(yaml, "reachableWaitKey"); + if (VerifyTools.isBlank(reachableWaitKey)) { + return 0; + } + // 从JVM环境变量中获取network.reachable + String propValue = getSystemProperty(reachableWaitKey); + if (VerifyTools.isBlank(propValue)) { + try { + return ConvertTools.toInteger(propValue); + } catch (NumberFormatException e) { + throw new ServiceException(ResultCode.SYSTEM_CONFIG_ERROR, e) + .setDetails(reachableWaitKey + '=' + propValue); + } + } else { + // 从NetworkTools.yml中获取reachableWaitMillis + String configKey = "reachableWaitMillis"; + return MapTools.getValue(yaml, configKey, int.class); + } + } + + private static String getSystemProperty(String name) { + // JVM环境变量, 可通过-D设置变量值 + String value = System.getProperty(name); + // 系统环境变量 + return value != null ? value : System.getenv(name); + } } diff --git a/able/src/main/resources/settings/global/NetworkTools.yml b/able/src/main/resources/settings/global/NetworkTools.yml new file mode 100644 index 0000000..a13e050 --- /dev/null +++ b/able/src/main/resources/settings/global/NetworkTools.yml @@ -0,0 +1,13 @@ +network-tools: + # 是否缓存IP地址 + cacheEnabled: true + # 忽略的网卡名 + ignoreNames: virtual,veth,virbr,docker + # 可达检测的等待时长(毫秒), 0表示不检测 + reachableWaitMillis: 0 + # -Dhost.ip=192.168.8.88 + hostIpKey: host.ip + # -Dnetwork.ignore=virtual,veth,virbr,docker + ignoreKey: network.ignore + # -Dnetwork.reachable=50 + reachableWaitKey: network.reachable -- Gitee From fb741c5b2148dfd53ad9ada221d3fd5ac2f37c55 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 19:52:10 +0800 Subject: [PATCH 75/82] =?UTF-8?q?SqlScript=E5=B7=A5=E5=85=B7=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=B9=B6=E7=A7=BB=E8=87=B3qdbp-able?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdbp/able/jdbc/utils/SqlScriptTools.java | 775 ++++++++++++++++++ 1 file changed, 775 insertions(+) create mode 100644 able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java diff --git a/able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java b/able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java new file mode 100644 index 0000000..0fcbfa7 --- /dev/null +++ b/able/src/main/java/com/gitee/qdbp/able/jdbc/utils/SqlScriptTools.java @@ -0,0 +1,775 @@ +/* + * Copyright 2002-2021 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 com.gitee.qdbp.able.jdbc.utils; + +import java.io.File; +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.Reader; +import java.io.StringReader; +import java.net.URL; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.gitee.qdbp.able.enums.FileErrorCode; +import com.gitee.qdbp.able.exception.ServiceException; +import com.gitee.qdbp.able.i18n.LocaleTools; +import com.gitee.qdbp.able.result.IResultMessage; +import com.gitee.qdbp.able.result.ResultCode; +import com.gitee.qdbp.tools.files.FileTools; +import com.gitee.qdbp.tools.files.PathTools; +import com.gitee.qdbp.tools.utils.ClassTools; +import com.gitee.qdbp.tools.utils.StringTools; +import com.gitee.qdbp.tools.utils.VerifyTools; + + +/** + * copy from spring-jdbc-5.3.23.jar ScriptUtils
+ * Generic utility methods for working with SQL scripts in conjunction with JDBC. + * + *

Mainly for internal use within the framework.

+ * + * @author Thomas Risberg + * @author Sam Brannen + * @author Juergen Hoeller + * @author Keith Donald + * @author Dave Syer + * @author Chris Beams + * @author Oliver Gierke + * @author Chris Baldwin + * @author Nicolas Debeissat + * @author Phillip Webb + */ +public abstract class SqlScriptTools { + + private static Logger log; + + static { + if (ClassTools.isPresent("org.slf4j.Logger")) { + log = LoggerFactory.getLogger(SqlScriptTools.class); + } + } + + /** + * Default statement separator within SQL scripts: {@code ";"}. + */ + public static final String DEFAULT_STATEMENT_SEPARATOR = ";"; + + /** + * Fallback statement separator within SQL scripts: {@code "\n"}. + *

Used if neither a custom separator nor the + * {@link #DEFAULT_STATEMENT_SEPARATOR} is present in a given script. + */ + public static final String FALLBACK_STATEMENT_SEPARATOR = "\n"; + + /** + * End of file (EOF) SQL statement separator: {@code "^^^ END OF SCRIPT ^^^"}. + *

This value may be supplied as the {@code separator} to {@link + * #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String)} + * to denote that an SQL script contains a single statement (potentially + * spanning multiple lines) with no explicit statement separator. Note that + * such a script should not actually contain this value; it is merely a + * virtual statement separator. + */ + public static final String EOF_STATEMENT_SEPARATOR = "^^^ END OF SCRIPT ^^^"; + + /** + * Default prefix for single-line comments within SQL scripts: {@code "--"}. + */ + public static final String DEFAULT_COMMENT_PREFIX = "--"; + + /** + * Default prefixes for single-line comments within SQL scripts: {@code ["--"]}. + * @since 5.2 + */ + public static final String[] DEFAULT_COMMENT_PREFIXES = {DEFAULT_COMMENT_PREFIX}; + + /** + * Default start delimiter for block comments within SQL scripts: {@code "/*"}. + */ + public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*"; + + /** + * Default end delimiter for block comments within SQL scripts: "*/". + */ + public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/"; + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, URL resource) { + return executeSqlScript(connection, resource, false, false); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, URL resource, + boolean continueOnError, boolean ignoreFailedDrops) { + String resourceName = PathTools.getFileName(resource.getPath()); + String resourceScript; + try { + resourceScript = PathTools.downloadString(resource); + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR).setDetails(resource.toString()); + } + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, File resource) { + return executeSqlScript(connection, resource, false, false); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resource resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, File resource, + boolean continueOnError, boolean ignoreFailedDrops) { + String resourceName = resource.getName(); + String resourceScript; + try { + resourceScript = FileTools.readTextContent(resource); + } catch (IOException e) { + throw new ServiceException(FileErrorCode.FILE_READ_ERROR).setDetails(resource.toString()); + } + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript) { + return executeSqlScript(connection, resourceName, resourceScript, false, false, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script using default settings for statement + * separators, comment delimiters, and exception handling flags. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #executeSqlScript(Connection, String, String, boolean, boolean, String, String, String, String) + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #DEFAULT_COMMENT_PREFIX + * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER + * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript, + boolean continueOnError, boolean ignoreFailedDrops) { + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, + DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } + + /** + * Execute the given SQL script. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @param commentPrefix the prefix that identifies single-line comments in the + * SQL script (typically "--") + * @param separator the script statement separator; defaults to + * {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to + * {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to + * {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a + * single statement without a separator + * @param blockCommentStartDelimiter the start block comment delimiter + * @param blockCommentEndDelimiter the end block comment delimiter + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #FALLBACK_STATEMENT_SEPARATOR + * @see #EOF_STATEMENT_SEPARATOR + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript, + boolean continueOnError, boolean ignoreFailedDrops, String commentPrefix, String separator, + String blockCommentStartDelimiter, String blockCommentEndDelimiter) { + return executeSqlScript(connection, resourceName, resourceScript, continueOnError, ignoreFailedDrops, + new String[] { commentPrefix }, separator, blockCommentStartDelimiter, blockCommentEndDelimiter); + } + + /** + * Execute the given SQL script. + *

Statement separators and comments will be removed before executing + * individual statements within the supplied script. + *

Warning: this method does not release the + * provided {@link Connection}. + * @param connection the JDBC connection to use to execute the script; already + * configured and ready to use + * @param resourceName resource name + * @param resourceScript resource content script + * @param continueOnError whether to continue without throwing an exception + * in the event of an error + * @param ignoreFailedDrops whether to continue in the event of specifically + * an error on a {@code DROP} statement + * @param commentPrefixes the prefixes that identify single-line comments in the + * SQL script (typically "--") + * @param separator the script statement separator; defaults to + * {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to + * {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to + * {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a + * single statement without a separator + * @param blockCommentStartDelimiter the start block comment delimiter + * @param blockCommentEndDelimiter the end block comment delimiter + * @return all script fragments executed successfully will return true + * @throws ServiceException if an error occurred while executing the SQL script + * @since 5.2 + * @see #DEFAULT_STATEMENT_SEPARATOR + * @see #FALLBACK_STATEMENT_SEPARATOR + * @see #EOF_STATEMENT_SEPARATOR + */ + public static boolean executeSqlScript(Connection connection, String resourceName, String resourceScript, + boolean continueOnError, boolean ignoreFailedDrops, String[] commentPrefixes, String separator, + String blockCommentStartDelimiter, String blockCommentEndDelimiter) { + try { + if (log != null && log.isDebugEnabled()) { + log.debug("Executing SQL script from " + resourceName); + } + long startTime = System.currentTimeMillis(); + + // clear comment + String script; + try { + script = readScript(resourceScript, separator, commentPrefixes, blockCommentEndDelimiter); + } catch (IOException e) { + throw new ServiceException(ScriptErrorCode.SCRIPT_READ_ERROR) + .setDetails("Cannot read SQL script from " + resourceName); + } + + if (separator == null) { + separator = DEFAULT_STATEMENT_SEPARATOR; + } + if (!EOF_STATEMENT_SEPARATOR.equals(separator) && + !containsStatementSeparator(resourceName, script, separator, commentPrefixes, + blockCommentStartDelimiter, blockCommentEndDelimiter)) { + separator = FALLBACK_STATEMENT_SEPARATOR; + } + + List statements = new ArrayList<>(); + splitSqlScript(resourceName, script, separator, commentPrefixes, blockCommentStartDelimiter, + blockCommentEndDelimiter, statements); + + int stmtNumber = 0; + boolean allSuccessfully = true; + Statement stmt = connection.createStatement(); + try { + for (String statement : statements) { + stmtNumber++; + try { + stmt.execute(statement); + int rowsAffected = stmt.getUpdateCount(); + if (log != null && log.isDebugEnabled()) { + String ellipsis = ellipsisScript(statement, 100); + log.debug(rowsAffected + " returned as update count for SQL[{}]: {}", stmtNumber, ellipsis); + SQLWarning warning = stmt.getWarnings(); + while (warning != null) { + log.debug("SQLWarning ignored: SQL state '{}', error code '{}', message [{}]", + warning.getSQLState(), warning.getErrorCode(), warning.getMessage()); + warning = warning.getNextWarning(); + } + } + } catch (SQLException e) { + boolean dropStatement = startsWithIgnoreCase(statement.trim(), "drop"); + if (!dropStatement || !ignoreFailedDrops) { + allSuccessfully = false; + } + if (continueOnError || (dropStatement && ignoreFailedDrops)) { + if (log != null && log.isDebugEnabled()) { + String ellipsis = ellipsisScript(statement, 100); + String message = buildExecuteMessage(ellipsis, stmtNumber, resourceName); + log.debug(message, e); + } + } else { + String ellipsis = ellipsisScript(statement, 100); + throw buildExecuteException(ellipsis, stmtNumber, resourceName, e); + } + } + } + } finally { + try { + stmt.close(); + } catch (Throwable e) { + if (log != null && log.isTraceEnabled()) { + log.trace("Could not close JDBC Statement", e); + } + } + } + + long elapsedTime = System.currentTimeMillis() - startTime; + if (log != null && log.isDebugEnabled()) { + log.debug("Executed {} SQL script statement from {} in {} ms.", stmtNumber, resourceName, elapsedTime); + } + return allSuccessfully; + } catch (Exception e) { + if (e instanceof ServiceException) { + throw (ServiceException) e; + } + throw new ServiceException(ResultCode.SERVER_INNER_ERROR, e) + .setDetails("Failed to execute database script from resource [{}]", resourceName); + } + } + + /** + * Read a script from the provided resource, using the supplied comment prefixes + * and statement separator, and build a {@code String} containing the lines. + *

Lines beginning with one of the comment prefixes are excluded + * from the results; however, line comments anywhere else — for example, + * within a statement — will be included in the results. + * @param resource the script string + * to be processed + * @param separator the statement separator in the SQL script (typically ";") + * @param commentPrefixes the prefixes that identify comments in the SQL script + * (typically "--") + * @param blockCommentEndDelimiter the end block comment delimiter + * @return a {@code String} containing the script lines + * @throws IOException in case of I/O errors + */ + static String readScript(String resource, String separator, + String[] commentPrefixes, String blockCommentEndDelimiter) throws IOException { + + Reader reader = new StringReader(resource); + try (LineNumberReader lnr = new LineNumberReader(reader)) { + return readScript(lnr, commentPrefixes, separator, blockCommentEndDelimiter); + } + } + + /** + * Read a script from the provided {@code LineNumberReader}, using the supplied + * comment prefixes and statement separator, and build a {@code String} containing + * the lines. + *

Lines beginning with one of the comment prefixes are excluded + * from the results; however, line comments anywhere else — for example, + * within a statement — will be included in the results. + * @param lineNumberReader the {@code LineNumberReader} containing the script + * to be processed + * @param commentPrefixes the prefixes that identify comments in the SQL script + * (typically "--") + * @param separator the statement separator in the SQL script (typically ";") + * @param blockCommentEndDelimiter the end block comment delimiter + * @return a {@code String} containing the script lines + * @throws IOException in case of I/O errors + * @since 5.2 + */ + private static String readScript(LineNumberReader lineNumberReader, String[] commentPrefixes, + String separator, String blockCommentEndDelimiter) throws IOException { + + String currentStatement = lineNumberReader.readLine(); + StringBuilder scriptBuilder = new StringBuilder(); + while (currentStatement != null) { + if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) || + (commentPrefixes != null && !startsWithAny(currentStatement, commentPrefixes, 0))) { + if (scriptBuilder.length() > 0) { + scriptBuilder.append('\n'); + } + scriptBuilder.append(currentStatement); + } + currentStatement = lineNumberReader.readLine(); + } + appendSeparatorToScriptIfNecessary(scriptBuilder, separator); + return scriptBuilder.toString(); + } + + private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, String separator) { + if (separator == null) { + return; + } + String trimmed = separator.trim(); + if (trimmed.length() == separator.length()) { + return; + } + // separator ends in whitespace, so we might want to see if the script is trying + // to end the same way + if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length() - trimmed.length()) { + scriptBuilder.append(separator.substring(trimmed.length())); + } + } + + /** + * Determine if the provided SQL script contains the specified statement separator. + *

This method is intended to be used to find the string separating each + * SQL statement — for example, a ';' character. + *

Any occurrence of the separator within the script will be ignored if it + * is within a literal block of text enclosed in single quotes + * ({@code '}) or double quotes ({@code "}), if it is escaped with a backslash + * ({@code \}), or if it is within a single-line comment or block comment. + * @param resource the resource from which the script was read, or {@code null} + * if unknown + * @param script the SQL script to search within + * @param separator the statement separator to search for + * @param commentPrefixes the prefixes that identify single-line comments + * (typically {@code "--"}) + * @param blockCommentStartDelimiter the start block comment delimiter + * (typically {@code "/*"}) + * @param blockCommentEndDelimiter the end block comment delimiter + * (typically "*/") + * @since 5.2.16 + */ + private static boolean containsStatementSeparator(String resource, String script, + String separator, String[] commentPrefixes, String blockCommentStartDelimiter, + String blockCommentEndDelimiter) { + + boolean inSingleQuote = false; + boolean inDoubleQuote = false; + boolean inEscape = false; + + for (int i = 0; i < script.length(); i++) { + char c = script.charAt(i); + if (inEscape) { + inEscape = false; + continue; + } + // MySQL style escapes + if (c == '\\') { + inEscape = true; + continue; + } + if (!inDoubleQuote && (c == '\'')) { + inSingleQuote = !inSingleQuote; + } + else if (!inSingleQuote && (c == '"')) { + inDoubleQuote = !inDoubleQuote; + } + if (!inSingleQuote && !inDoubleQuote) { + if (script.startsWith(separator, i)) { + return true; + } + else if (startsWithAny(script, commentPrefixes, i)) { + // Skip over any content from the start of the comment to the EOL + int indexOfNextNewline = script.indexOf('\n', i); + if (indexOfNextNewline > i) { + i = indexOfNextNewline; + continue; + } + else { + // If there's no EOL, we must be at the end of the script, so stop here. + break; + } + } + else if (script.startsWith(blockCommentStartDelimiter, i)) { + // Skip over any block comments + int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); + if (indexOfCommentEnd > i) { + i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; + continue; + } + else { + String cause = "Missing block comment end delimiter: " + blockCommentEndDelimiter; + throw buildParseException(cause, resource); + } + } + } + } + + return false; + } + + private static ServiceException buildParseException(String message, String resource) { + String details = String.format("Failed to parse SQL script from resource [%s]: %s", + (resource == null ? "" : resource), message); + return new ServiceException(ScriptErrorCode.SCRIPT_PARSE_ERROR).setDetails(details); + } + + private static String buildExecuteMessage(String stmt, int stmtNumber, String resource) { + return String.format("Failed to execute SQL script statement #%s of [%s]: %s", + stmtNumber, (resource == null ? "" : resource), stmt); + } + + private static ServiceException buildExecuteException(String stmt, int stmtNumber, String resource, Throwable e) { + String details = buildExecuteMessage(stmt, stmtNumber, resource); + return new ServiceException(ScriptErrorCode.SCRIPT_EXECUTE_ERROR, e).setDetails(details); + } + + private static String ellipsisScript(String script, int limit) { + String inline = StringTools.replace(script, "\r\n", " ", "\r", " ", "\n", " "); + return StringTools.ellipsis(inline, limit); + } + + /** + * Split an SQL script into separate statements delimited by the provided + * separator string. Each individual statement will be added to the provided + * {@code List}. + *

Within the script, the provided {@code commentPrefixes} will be honored: + * any text beginning with one of the comment prefixes and extending to the + * end of the line will be omitted from the output. Similarly, the provided + * {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter} + * delimiters will be honored: any text enclosed in a block comment will be + * omitted from the output. In addition, multiple adjacent whitespace characters + * will be collapsed into a single space. + * @param resource the resource from which the script was read + * @param script the SQL script + * @param separator text separating each statement + * (typically a ';' or newline character) + * @param commentPrefixes the prefixes that identify SQL line comments + * (typically "--") + * @param blockCommentStartDelimiter the start block comment delimiter; + * never {@code null} or empty + * @param blockCommentEndDelimiter the end block comment delimiter; + * never {@code null} or empty + * @param statements the list that will contain the individual statements + * @throws ServiceException if an error occurred while splitting the SQL script + * @since 5.2 + */ + private static void splitSqlScript(String resource, String script, + String separator, String[] commentPrefixes, String blockCommentStartDelimiter, + String blockCommentEndDelimiter, List statements) { + + VerifyTools.requireNotBlank(script, "script"); + VerifyTools.requireNotBlank(separator, "separator"); + VerifyTools.requireNotBlank(commentPrefixes, "commentPrefixes"); + for (String commentPrefix : commentPrefixes) { + VerifyTools.requireNotBlank(commentPrefix, "commentPrefixes"); + } + VerifyTools.requireNotBlank(blockCommentStartDelimiter, "blockCommentStartDelimiter"); + VerifyTools.requireNotBlank(blockCommentEndDelimiter, "blockCommentEndDelimiter"); + + StringBuilder sb = new StringBuilder(); + boolean inSingleQuote = false; + boolean inDoubleQuote = false; + boolean inEscape = false; + + for (int i = 0; i < script.length(); i++) { + char c = script.charAt(i); + if (inEscape) { + inEscape = false; + sb.append(c); + continue; + } + // MySQL style escapes + if (c == '\\') { + inEscape = true; + sb.append(c); + continue; + } + if (!inDoubleQuote && (c == '\'')) { + inSingleQuote = !inSingleQuote; + } else if (!inSingleQuote && (c == '"')) { + inDoubleQuote = !inDoubleQuote; + } + if (!inSingleQuote && !inDoubleQuote) { + if (script.startsWith(separator, i)) { + // We've reached the end of the current statement + if (sb.length() > 0) { + statements.add(sb.toString()); + sb = new StringBuilder(); + } + i += separator.length() - 1; + continue; + } else if (startsWithAny(script, commentPrefixes, i)) { + // Skip over any content from the start of the comment to the EOL + int indexOfNextNewline = script.indexOf('\n', i); + if (indexOfNextNewline > i) { + i = indexOfNextNewline; + continue; + } else { + // If there's no EOL, we must be at the end of the script, so stop here. + break; + } + } else if (script.startsWith(blockCommentStartDelimiter, i)) { + // Skip over any block comments + int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); + if (indexOfCommentEnd > i) { + i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; + continue; + } else { + String cause = "Missing block comment end delimiter: " + blockCommentEndDelimiter; + throw buildParseException(cause, resource); + } + } else if (c == ' ' || c == '\r' || c == '\n' || c == '\t') { + // Avoid multiple adjacent whitespace characters + if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') { + c = ' '; + } else { + continue; + } + } + } + sb.append(c); + } + + if (sb.length() > 0) { + statements.add(sb.toString()); + } + } + + private static boolean startsWithAny(String script, String[] prefixes, int offset) { + for (String prefix : prefixes) { + if (script.startsWith(prefix, offset)) { + return true; + } + } + return false; + } + + /** + * Test if the given {@code String} starts with the specified prefix, + * ignoring upper/lower case. + * @param str the {@code String} to check + * @param prefix the prefix to look for + * @see String#startsWith + */ + private static boolean startsWithIgnoreCase(String str, String prefix) { + return (str != null && prefix != null && str.length() >= prefix.length() && + str.regionMatches(true, 0, prefix, 0, prefix.length())); + } + + + /** + * 脚本错误枚举 + * + * @author zhaohuihua + * @version 20211127 + */ + private enum ScriptErrorCode implements IResultMessage { + + /** 脚本读取异常 **/ + SCRIPT_READ_ERROR, + /** 脚本解析异常 **/ + SCRIPT_PARSE_ERROR, + /** 脚本执行失败 **/ + SCRIPT_EXECUTE_ERROR; + + /** {@inheritDoc} **/ + @Override + public String getCode() { + return this.name(); + } + + /** {@inheritDoc} **/ + @Override + public String getMessage() { + return LocaleTools.getMessage(this); + } + } +} -- Gitee From 3d3c16029d84455fe9f8ea403a2b7a34c858ada5 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 20:06:27 +0800 Subject: [PATCH 76/82] 5.6.231114 --- README.md | 4 ++-- able/pom.xml | 11 ++++++++++- json/pom.xml | 4 ++-- test/pom.xml | 3 ++- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 23 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index adc0bae..b289bfa 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.230820 + 5.6.231114 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.230820 + 5.6.231114 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 2e07f68..18fad33 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.230820 + 5.6.231114 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ @@ -20,4 +20,13 @@ https://gitee.com/qdbp/qdbp-able/ + + + org.slf4j + slf4j-api + 1.7.36 + true + + + diff --git a/json/pom.xml b/json/pom.xml index 987828f..39138b2 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.230820 + 5.6.231114 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.230820 + 5.6.231114 diff --git a/test/pom.xml b/test/pom.xml index 2e54e0c..83be4e1 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.230820 + 5.6.231114 https://gitee.com/qdbp/qdbp-able/ qdbp json test @@ -22,6 +22,7 @@ qdbp-json-test-base qdbp-json-test-fastjson + qdbp-json-test-fastjson2 qdbp-json-test-gson qdbp-json-test-jackson qdbp-tools-test-jdk7 diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index d250b47..ec707ee 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 11184c2..7a2f37b 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index f734508..52d9b1f 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index 71122cf..aa6d861 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 2c0c6b2..3df57da 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index d906897..12bf95b 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.230820 + 5.6.231114 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 4d6b05c..404ed99 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.230820 + 5.6.231114 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee From 2083ddeafca157d9475330f000c3da276c1bb2c2 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Tue, 14 Nov 2023 20:14:08 +0800 Subject: [PATCH 77/82] VolatileData.expireAt --- able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java index d597ed8..ab6664e 100644 --- a/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java +++ b/able/src/main/java/com/gitee/qdbp/able/beans/VolatileData.java @@ -43,7 +43,7 @@ public class VolatileData implements Copyable, Serializable { } /** 设置过期时间(绝对时间) **/ - public VolatileData setExpireTime(Long expireTime) { + public VolatileData expireAt(Long expireTime) { this.expireTime = expireTime; return this; } -- Gitee From d1fe3dec60f873ed9d4332821c9b58139e601e27 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Thu, 16 Nov 2023 19:19:48 +0800 Subject: [PATCH 78/82] =?UTF-8?q?pom=E7=9A=84profile=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- json/pom.xml | 2 +- pom.xml | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/json/pom.xml b/json/pom.xml index 39138b2..87e96fc 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-parent - 5.0.1 + 5.0.2 qdbp-json diff --git a/pom.xml b/pom.xml index 55de679..2600de9 100644 --- a/pom.xml +++ b/pom.xml @@ -100,17 +100,6 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.8 - true - - sonatype-qdbp - https://oss.sonatype.org/ - true - - @@ -147,6 +136,17 @@ + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + sonatype-qdbp + https://oss.sonatype.org/ + true + + org.apache.maven.plugins maven-gpg-plugin -- Gitee From c654d6134abd86d1a2e824a1b1c8fd73ba3e455a Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:34:22 +0800 Subject: [PATCH 79/82] =?UTF-8?q?ExtraBase.getExtra=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=B3=9B=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gitee/qdbp/able/model/reusable/ExtraBase.java | 2 +- .../java/com/gitee/qdbp/able/model/reusable/ExtraData.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java index 2fdf49c..b6a39dc 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraBase.java @@ -20,7 +20,7 @@ public interface ExtraBase { boolean containsExtra(String key); /** 获取指定的附加数据 **/ - Object getExtra(String key); + T getExtra(String key); /** 获取指定类型的附加数据 **/ T getExtra(String key, Class clazz); diff --git a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java index 144c235..2423549 100644 --- a/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java +++ b/able/src/main/java/com/gitee/qdbp/able/model/reusable/ExtraData.java @@ -46,8 +46,9 @@ public class ExtraData implements Serializable, ExtraBase { /** 获取指定的附加数据 **/ @Override - public Object getExtra(String key) { - return this.extra == null ? null : this.extra.get(key); + @SuppressWarnings("unchecked") + public T getExtra(String key) { + return this.extra == null ? null : (T) this.extra.get(key); } /** 获取指定类型的附加数据 **/ -- Gitee From 1d73133ab3e8cd4ed00c8dcb5cc3849de63f8509 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:34:59 +0800 Subject: [PATCH 80/82] =?UTF-8?q?isLikeDateFormat=E6=8F=90=E5=8F=96?= =?UTF-8?q?=E4=B8=BA=E5=85=AC=E5=85=B1=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/qdbp/tools/utils/ConvertTools.java | 51 ++----------------- .../com/gitee/qdbp/tools/utils/DateTools.java | 43 ++++++++++++++++ 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java index 8905d05..fe0b827 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/ConvertTools.java @@ -1294,22 +1294,21 @@ public class ConvertTools { } } else if (fieldName != null) { try { - if (fieldName.endsWith("OfMinInDay") || fieldName.endsWith("OfMinDay")) { + if (fieldName.endsWith("OfMinWithDay") || fieldName.endsWith("OfMinDay")) { Date date = DateTools.parse(fieldValue); return DateTools.toStartTime(date); - } else if (fieldName.endsWith("OfMaxInDay") || fieldName.endsWith("OfMaxDay")) { + } else if (fieldName.endsWith("OfMaxWithDay") || fieldName.endsWith("OfMaxDay")) { Date date = DateTools.parse(fieldValue); return DateTools.toEndTime(date); } else if (fieldName.endsWith("Date") || fieldName.endsWith("_DATE")) { return DateTools.parse(fieldValue); } else if (fieldName.endsWith("Time") || fieldName.endsWith("_TIME")) { return DateTools.parse(fieldValue); - } else if (isLikeDateFormat(fieldValue)) { - return DateTools.parse(fieldValue); } } catch (IllegalArgumentException ignore) { } - } else if (isLikeDateFormat(fieldValue)) { + } + if (DateTools.isLikeDateFormat(fieldValue)) { try { return DateTools.parse(fieldValue); } catch (IllegalArgumentException ignore) { @@ -1319,48 +1318,6 @@ public class ConvertTools { return fieldValue; } - /** 支持哪些日期格式 **/ - private static final List DATE_FORMATS = Arrays.asList( - "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.SSS" - ); - - private static boolean isLikeDateFormat(String source) { - for (String format : DATE_FORMATS) { - if (isDateFormatMatches(source, format)) { - return true; - } - } - return false; - } - - // 检查字符串是不是日期时间格式 - private static boolean isDateFormatMatches(String source, String format) { - if (VerifyTools.isAnyBlank(source, format)) { - return false; - } - int sLength = source.length(); - int fLength = format.length(); - if (sLength != fLength) { - return false; - } - for (int i = 0; i < fLength; i++) { - char s = source.charAt(i); - char c = format.charAt(i); - if (c == 'y' || c == 'M' || c == 'd' || c == 'H' || c == 'h' || c == 'm' || c == 's' || c == 'S') { - // 遇到yyyy MM dd HH mm ss SSS之类的字符, 则原字符必须是数字 - if (s < '0' || s > '9') { - return false; - } - } else { - // 遇到其他字符, 则原字符必须与该字符相等 - if (s != c) { - return false; - } - } - } - return true; - } - /** * 压缩列表, 保留指定数目 * diff --git a/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java b/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java index 8b4a3e5..34dd016 100644 --- a/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java +++ b/able/src/main/java/com/gitee/qdbp/tools/utils/DateTools.java @@ -1294,4 +1294,47 @@ public class DateTools { return d.getTime(); } } + + /** 检查字符串是不是日期时间格式 **/ + public static boolean isLikeDateFormat(String source) { + return isLikeDateFormat(source, PATTERN_GENERAL_DATE, PATTERN_GENERAL_DATETIME, PATTERN_GENERAL_NORMATIVE); + } + + /** 检查字符串是不是日期时间格式 **/ + public static boolean isLikeDateFormat(String source, String... formats) { + for (String format : formats) { + if (isDateFormatMatches(source, format)) { + return true; + } + } + return false; + } + + /** 检查字符串是不是日期时间格式 **/ + private static boolean isDateFormatMatches(String source, String format) { + if (VerifyTools.isAnyBlank(source, format)) { + return false; + } + int sLength = source.length(); + int fLength = format.length(); + if (sLength != fLength) { + return false; + } + for (int i = 0; i < fLength; i++) { + char s = source.charAt(i); + char c = format.charAt(i); + if (c == 'y' || c == 'M' || c == 'd' || c == 'H' || c == 'h' || c == 'm' || c == 's' || c == 'S') { + // 遇到yyyy MM dd HH mm ss SSS之类的字符, 则原字符必须是数字 + if (s < '0' || s > '9') { + return false; + } + } else { + // 遇到其他字符, 则原字符必须与该字符相等 + if (s != c) { + return false; + } + } + } + return true; + } } -- Gitee From 48cc54dfd1e9afa5191ea76036716d36b1e92965 Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:35:57 +0800 Subject: [PATCH 81/82] =?UTF-8?q?beanToMap=E6=94=B9=E4=B8=BA=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=B8=8D=E6=B8=85=E9=99=A4=E7=A9=BA=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java index f67e211..cc1ba68 100644 --- a/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java +++ b/json/src/main/java/com/gitee/qdbp/json/JsonServiceForBase.java @@ -74,7 +74,7 @@ public abstract class JsonServiceForBase implements JsonService { if (bean == null) { return null; } - return beanToMap(bean, true, true); + return beanToMap(bean, true, false); } /** -- Gitee From 3320f2f42e008d7b4fc8146f8a119de20374e24d Mon Sep 17 00:00:00 2001 From: zhaohuihua Date: Sun, 26 Nov 2023 19:46:16 +0800 Subject: [PATCH 82/82] 5.6.231125 --- README.md | 4 ++-- able/pom.xml | 2 +- json/pom.xml | 4 ++-- test/pom.xml | 2 +- test/qdbp-json-test-base/pom.xml | 2 +- test/qdbp-json-test-fastjson/pom.xml | 2 +- test/qdbp-json-test-gson/pom.xml | 2 +- test/qdbp-json-test-jackson/pom.xml | 2 +- test/qdbp-tools-test-jdk7/pom.xml | 2 +- test/qdbp-tools-test-jdk8/pom.xml | 2 +- tools/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b289bfa..35b11f6 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ com.gitee.qdbp qdbp-able - 5.6.231114 + 5.6.231125 ``` ```xml com.gitee.qdbp qdbp-tools - 5.6.231114 + 5.6.231125 ``` \ No newline at end of file diff --git a/able/pom.xml b/able/pom.xml index 18fad33..68630f4 100644 --- a/able/pom.xml +++ b/able/pom.xml @@ -9,7 +9,7 @@ qdbp-able - 5.6.231114 + 5.6.231125 jar ${project.artifactId} https://gitee.com/qdbp/qdbp-able/ diff --git a/json/pom.xml b/json/pom.xml index 87e96fc..c647960 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -10,7 +10,7 @@ qdbp-json jar - 5.6.231114 + 5.6.231125 https://gitee.com/qdbp/qdbp-able/ qdbp json library @@ -24,7 +24,7 @@ com.gitee.qdbp qdbp-able - 5.6.231114 + 5.6.231125 diff --git a/test/pom.xml b/test/pom.xml index 83be4e1..a6b4941 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -10,7 +10,7 @@ qdbp-json-test pom - 5.6.231114 + 5.6.231125 https://gitee.com/qdbp/qdbp-able/ qdbp json test diff --git a/test/qdbp-json-test-base/pom.xml b/test/qdbp-json-test-base/pom.xml index ec707ee..5f15217 100644 --- a/test/qdbp-json-test-base/pom.xml +++ b/test/qdbp-json-test-base/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-base diff --git a/test/qdbp-json-test-fastjson/pom.xml b/test/qdbp-json-test-fastjson/pom.xml index 7a2f37b..a32e9d0 100644 --- a/test/qdbp-json-test-fastjson/pom.xml +++ b/test/qdbp-json-test-fastjson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-fastjson diff --git a/test/qdbp-json-test-gson/pom.xml b/test/qdbp-json-test-gson/pom.xml index 52d9b1f..ec12c46 100644 --- a/test/qdbp-json-test-gson/pom.xml +++ b/test/qdbp-json-test-gson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-gson diff --git a/test/qdbp-json-test-jackson/pom.xml b/test/qdbp-json-test-jackson/pom.xml index aa6d861..e6c9267 100644 --- a/test/qdbp-json-test-jackson/pom.xml +++ b/test/qdbp-json-test-jackson/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-json-test-jackson diff --git a/test/qdbp-tools-test-jdk7/pom.xml b/test/qdbp-tools-test-jdk7/pom.xml index 3df57da..bcf96e9 100644 --- a/test/qdbp-tools-test-jdk7/pom.xml +++ b/test/qdbp-tools-test-jdk7/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-tools-test-jdk7 diff --git a/test/qdbp-tools-test-jdk8/pom.xml b/test/qdbp-tools-test-jdk8/pom.xml index 12bf95b..01c624c 100644 --- a/test/qdbp-tools-test-jdk8/pom.xml +++ b/test/qdbp-tools-test-jdk8/pom.xml @@ -5,7 +5,7 @@ com.gitee.qdbp qdbp-json-test - 5.6.231114 + 5.6.231125 qdbp-tools-test-jdk8 diff --git a/tools/pom.xml b/tools/pom.xml index 404ed99..9bff829 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -10,7 +10,7 @@ qdbp-tools jar - 5.6.231114 + 5.6.231125 https://gitee.com/qdbp/qdbp-able/ qdbp tools library -- Gitee