diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/bean/PropDesc.java b/hutool-core/src/main/java/cn/hutool/v7/core/bean/PropDesc.java index bee62e1fb..6ddf11571 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/bean/PropDesc.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/bean/PropDesc.java @@ -55,6 +55,11 @@ public class PropDesc { */ protected Invoker setter; + private Boolean hasTransientForGetter; + private Boolean hasTransientForSetter; + private Boolean isReadable; + private Boolean isWritable; + /** * 构造
* Getter和Setter方法设置为默认可访问 @@ -181,27 +186,12 @@ public class PropDesc { * @since 5.4.2 */ public boolean isReadable(final boolean checkTransient) { - Field field = null; - if (this.fieldInvoker instanceof FieldInvoker) { - field = ((FieldInvoker) this.fieldInvoker).getField(); - } - Method getterMethod = null; - if (this.getter instanceof MethodInvoker) { - getterMethod = ((MethodInvoker) this.getter).getMethod(); - } + cacheReadable(); - // 检查transient关键字和@Transient注解 - if (checkTransient && isTransientForGet(field, getterMethod)) { + if(checkTransient && this.hasTransientForGetter){ return false; } - - // 检查@PropIgnore注解 - if (isIgnoreGet(field, getterMethod)) { - return false; - } - - // 检查是否有getter方法或是否为public修饰 - return null != getterMethod || ModifierUtil.isPublic(field); + return this.isReadable; } /** @@ -260,27 +250,12 @@ public class PropDesc { * @since 5.4.2 */ public boolean isWritable(final boolean checkTransient) { - Field field = null; - if (this.fieldInvoker instanceof FieldInvoker) { - field = ((FieldInvoker) this.fieldInvoker).getField(); - } - Method setterMethod = null; - if (this.setter instanceof MethodInvoker) { - setterMethod = ((MethodInvoker) this.setter).getMethod(); - } + cacheWritable(); - // 检查transient关键字和@Transient注解 - if (checkTransient && isTransientForSet(field, setterMethod)) { + if(checkTransient && this.hasTransientForSetter){ return false; } - - // 检查@PropIgnore注解 - if(isIgnoreSet(field, setterMethod)){ - return false; - } - - // 检查是否有setter方法或是否为public修饰 - return null != setterMethod || ModifierUtil.isPublic(field); + return this.isWritable; } /** @@ -373,6 +348,66 @@ public class PropDesc { // region ----- private methods + /** + * 缓存读取属性的可读性,如果已经检查过,直接返回true + */ + private void cacheReadable(){ + if(null != this.isReadable){ + return; + } + + Field field = null; + if (this.fieldInvoker instanceof FieldInvoker) { + field = ((FieldInvoker) this.fieldInvoker).getField(); + } + Method getterMethod = null; + if (this.getter instanceof MethodInvoker) { + getterMethod = ((MethodInvoker) this.getter).getMethod(); + } + + // 检查transient关键字和@Transient注解 + this.hasTransientForGetter = isTransientForGet(field, getterMethod); + + // 检查@PropIgnore注解 + if (isIgnoreGet(field, getterMethod)) { + this.isReadable = false; + return; + } + + // 检查是否有getter方法或是否为public修饰 + this.isReadable = null != getterMethod || ModifierUtil.isPublic(field); + } + + /** + * 缓存写入属性的可写性,如果已经检查过,直接返回true + */ + private void cacheWritable(){ + if(null != this.isWritable){ + return; + } + + Field field = null; + if (this.fieldInvoker instanceof FieldInvoker) { + field = ((FieldInvoker) this.fieldInvoker).getField(); + } + Method setterMethod = null; + if (this.setter instanceof MethodInvoker) { + setterMethod = ((MethodInvoker) this.setter).getMethod(); + } + + // 检查transient关键字和@Transient注解 + this.hasTransientForSetter = isTransientForSet(field, setterMethod); + + // 检查@PropIgnore注解 + if(isIgnoreSet(field, setterMethod)){ + this.isWritable = false; + return; + } + + // 检查是否有setter方法或是否为public修饰 + this.isWritable = null != setterMethod || ModifierUtil.isPublic(field); + } + /** * 通过Getter和Setter方法中找到属性类型 * diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/bean/SimpleBeanDesc.java b/hutool-core/src/main/java/cn/hutool/v7/core/bean/SimpleBeanDesc.java index 62de028f5..315e6693e 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/bean/SimpleBeanDesc.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/bean/SimpleBeanDesc.java @@ -22,6 +22,7 @@ import cn.hutool.v7.core.reflect.method.MethodNameUtil; import cn.hutool.v7.core.reflect.method.MethodUtil; import cn.hutool.v7.core.util.BooleanUtil; +import java.io.Serial; import java.lang.reflect.Method; import java.util.Map; @@ -37,6 +38,7 @@ import java.util.Map; * @since 6.0.0 */ public class SimpleBeanDesc extends AbstractBeanDesc { + @Serial private static final long serialVersionUID = 1L; /** diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/bean/StrictBeanDesc.java b/hutool-core/src/main/java/cn/hutool/v7/core/bean/StrictBeanDesc.java index 64438f8da..d65e616ca 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/bean/StrictBeanDesc.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/bean/StrictBeanDesc.java @@ -25,6 +25,7 @@ import cn.hutool.v7.core.reflect.method.MethodUtil; import cn.hutool.v7.core.text.StrUtil; import cn.hutool.v7.core.util.BooleanUtil; +import java.io.Serial; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Map; @@ -44,6 +45,7 @@ import java.util.Map; * @since 3.1.2 */ public class StrictBeanDesc extends AbstractBeanDesc { + @Serial private static final long serialVersionUID = 1L; /** diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/bean/path/AbstractBeanDesc.java b/hutool-core/src/main/java/cn/hutool/v7/core/bean/path/AbstractBeanDesc.java index e2f491469..fabe8e70c 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/bean/path/AbstractBeanDesc.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/bean/path/AbstractBeanDesc.java @@ -21,6 +21,7 @@ import cn.hutool.v7.core.bean.PropDesc; import cn.hutool.v7.core.lang.Assert; import cn.hutool.v7.core.map.CaseInsensitiveMap; +import java.io.Serial; import java.lang.reflect.Field; import java.util.LinkedHashMap; import java.util.Map; @@ -32,6 +33,7 @@ import java.util.Map; * @since 6.0.0 */ public abstract class AbstractBeanDesc implements BeanDesc { + @Serial private static final long serialVersionUID = 1L; /** diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/file/FileUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/file/FileUtil.java index 58d0ee354..3289b9f17 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/file/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/file/FileUtil.java @@ -314,7 +314,7 @@ public class FileUtil { } // 如果用户需要相对项目路径,则使用project:前缀 - if (path.startsWith("project:")) { + if (path.startsWith(UrlUtil.PROJECT_URL_PREFIX)) { return new File(path); } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ClassPathResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ClassPathResource.java index b718849da..95c05b05d 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ClassPathResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ClassPathResource.java @@ -24,6 +24,7 @@ import cn.hutool.v7.core.net.url.UrlUtil; import cn.hutool.v7.core.text.StrUtil; import cn.hutool.v7.core.util.ObjUtil; +import java.io.Serial; import java.net.URL; /** @@ -35,6 +36,7 @@ import java.net.URL; * */ public class ClassPathResource extends UrlResource { + @Serial private static final long serialVersionUID = 1L; private final String path; diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java index 3b6bdaa7f..8bed3b51a 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java @@ -23,6 +23,7 @@ import cn.hutool.v7.core.util.ObjUtil; import java.io.File; import java.io.InputStream; +import java.io.Serial; import java.io.Serializable; import java.net.URL; import java.nio.file.Path; @@ -33,6 +34,7 @@ import java.nio.file.Path; * @author Looly */ public class FileResource implements Resource, Serializable { + @Serial private static final long serialVersionUID = 1L; private final File file; diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ResourceUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ResourceUtil.java index f789b174b..b079af1cc 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ResourceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/ResourceUtil.java @@ -243,7 +243,7 @@ public class ResourceUtil { */ public static Resource getResource(final String path) { if (StrUtil.isNotBlank(path)) { - if (path.startsWith(UrlUtil.FILE_URL_PREFIX) || FileUtil.isAbsolutePath(path)) { + if (StrUtil.startWithAny(path, UrlUtil.FILE_URL_PREFIX, UrlUtil.PROJECT_URL_PREFIX) || FileUtil.isAbsolutePath(path)) { return new FileResource(path); } } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/net/url/UrlUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/net/url/UrlUtil.java index e8f87a58a..a1f26a8db 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/net/url/UrlUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/net/url/UrlUtil.java @@ -55,6 +55,10 @@ public class UrlUtil { * 针对ClassPath路径的伪协议前缀(兼容Spring): "classpath:" */ public static final String CLASSPATH_URL_PREFIX = "classpath:"; + /** + * 针对project路径的伪协议前缀: "project:" + */ + public static final String PROJECT_URL_PREFIX = "project:"; /** * URL 前缀表示文件: "file:" */ diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java index 6a7031d9e..dc9f57c7b 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java @@ -59,6 +59,6 @@ public class ResourceUtilTest { @Test void getResourceTest2() { // project:开头表示基于项目的相对路径,此处无文件报错 - Assertions.assertThrows(NoResourceException.class, () -> ResourceUtil.getResource("project:test.xml")); + Assertions.assertThrows(NoResourceException.class, () -> ResourceUtil.getResource("project:test.xml").getStream()); } }