diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd87252ad..833dc595f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
* 【captcha】 AbstractCaptcha增加getImageBase64Data方法(pr#985@Github)
* 【core 】 增加PhoneUtil(pr#990@Github)
* 【core 】 改进Img,目标图片类型未定义使用源图片类型(issue#I1PB0B@Gitee)
+* 【json 】 JSONConfig增加Transient选项(issue#I1PLHN@Gitee)
### Bug修复
diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java
index fb41e24ff..c843bec87 100644
--- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java
+++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java
@@ -1,5 +1,6 @@
package cn.hutool.core.bean;
+import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.util.BooleanUtil;
@@ -9,6 +10,7 @@ import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
+import java.beans.Transient;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -20,28 +22,32 @@ import java.util.Map;
/**
* Bean信息描述做为BeanInfo替代方案,此对象持有JavaBean中的setters和getters等相关信息描述
* 查找Getter和Setter方法时会:
- *
+ *
*
* 1. 忽略字段和方法名的大小写
* 2. Getter查找getXXX、isXXX、getIsXXX
* 3. Setter查找setXXX、setIsXXX
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
*
- *
+ *
* @author looly
* @since 3.1.2
*/
-public class BeanDesc implements Serializable{
+public class BeanDesc implements Serializable {
private static final long serialVersionUID = 1L;
- /** Bean类 */
+ /**
+ * Bean类
+ */
private final Class> beanClass;
- /** 属性Map */
+ /**
+ * 属性Map
+ */
private final Map propMap = new LinkedHashMap<>();
/**
* 构造
- *
+ *
* @param beanClass Bean类
*/
public BeanDesc(Class> beanClass) {
@@ -52,7 +58,7 @@ public class BeanDesc implements Serializable{
/**
* 获取Bean的全类名
- *
+ *
* @return Bean的类名
*/
public String getName() {
@@ -61,7 +67,7 @@ public class BeanDesc implements Serializable{
/**
* 获取Bean的简单类名
- *
+ *
* @return Bean的类名
*/
public String getSimpleName() {
@@ -70,7 +76,7 @@ public class BeanDesc implements Serializable{
/**
* 获取字段名-字段属性Map
- *
+ *
* @param ignoreCase 是否忽略大小写,true为忽略,false不忽略
* @return 字段名-字段属性Map
*/
@@ -80,7 +86,7 @@ public class BeanDesc implements Serializable{
/**
* 获取字段属性列表
- *
+ *
* @return {@link PropDesc} 列表
*/
public Collection getProps() {
@@ -89,7 +95,7 @@ public class BeanDesc implements Serializable{
/**
* 获取属性,如果不存在返回null
- *
+ *
* @param fieldName 字段名
* @return {@link PropDesc}
*/
@@ -99,7 +105,7 @@ public class BeanDesc implements Serializable{
/**
* 获得字段名对应的字段对象,如果不存在返回null
- *
+ *
* @param fieldName 字段名
* @return 字段值
*/
@@ -110,7 +116,7 @@ public class BeanDesc implements Serializable{
/**
* 获取Getter方法,如果不存在返回null
- *
+ *
* @param fieldName 字段名
* @return Getter方法
*/
@@ -121,7 +127,7 @@ public class BeanDesc implements Serializable{
/**
* 获取Setter方法,如果不存在返回null
- *
+ *
* @param fieldName 字段名
* @return Setter方法
*/
@@ -129,17 +135,18 @@ public class BeanDesc implements Serializable{
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getSetter();
}
-
+
// ------------------------------------------------------------------------------------------------------ Private method start
+
/**
* 初始化
* 只有与属性关联的相关Getter和Setter方法才会被读取,无关的getXXX和setXXX都被忽略
- *
+ *
* @return this
*/
private BeanDesc init() {
for (Field field : ReflectUtil.getFields(this.beanClass)) {
- if(false == ModifierUtil.isStatic(field)) {
+ if (false == ModifierUtil.isStatic(field)) {
//只针对非static属性
this.propMap.put(ReflectUtil.getFieldName(field), createProp(field));
}
@@ -150,14 +157,14 @@ public class BeanDesc implements Serializable{
/**
* 根据字段创建属性描述
* 查找Getter和Setter方法时会:
- *
+ *
*
* 1. 忽略字段和方法名的大小写
* 2. Getter查找getXXX、isXXX、getIsXXX
* 3. Setter查找setXXX、setIsXXX
* 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
*
- *
+ *
* @param field 字段
* @return {@link PropDesc}
* @since 4.0.2
@@ -201,7 +208,7 @@ public class BeanDesc implements Serializable{
/**
* 方法是否为Getter方法
* 匹配规则如下(忽略大小写):
- *
+ *
*
* 字段名 -》 方法名
* isName -》 isName
@@ -210,9 +217,9 @@ public class BeanDesc implements Serializable{
* name -》 isName
* name -》 getName
*
- *
- * @param methodName 方法名
- * @param fieldName 字段名
+ *
+ * @param methodName 方法名
+ * @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段
* @return 是否匹配
*/
@@ -225,7 +232,7 @@ public class BeanDesc implements Serializable{
// 非标准Getter方法
return false;
}
- if("getclass".equals(methodName)) {
+ if ("getclass".equals(methodName)) {
//跳过getClass方法
return false;
}
@@ -253,16 +260,16 @@ public class BeanDesc implements Serializable{
/**
* 方法是否为Setter方法
* 匹配规则如下(忽略大小写):
- *
+ *
*
* 字段名 -》 方法名
* isName -》 setName
* isName -》 setIsName
* name -》 setName
*
- *
- * @param methodName 方法名
- * @param fieldName 字段名
+ *
+ * @param methodName 方法名
+ * @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段
* @return 是否匹配
*/
@@ -293,24 +300,29 @@ public class BeanDesc implements Serializable{
/**
* 属性描述
- *
- * @author looly
*
+ * @author looly
*/
public static class PropDesc {
- /** 字段 */
+ /**
+ * 字段
+ */
private final Field field;
- /** Getter方法 */
+ /**
+ * Getter方法
+ */
private final Method getter;
- /** Setter方法 */
+ /**
+ * Setter方法
+ */
private final Method setter;
/**
* 构造
* Getter和Setter方法设置为默认可访问
- *
- * @param field 字段
+ *
+ * @param field 字段
* @param getter get方法
* @param setter set方法
*/
@@ -322,7 +334,7 @@ public class BeanDesc implements Serializable{
/**
* 获取字段名,如果存在Alias注解,读取注解的值作为名称
- *
+ *
* @return 字段名
*/
public String getFieldName() {
@@ -341,7 +353,7 @@ public class BeanDesc implements Serializable{
/**
* 获取字段
- *
+ *
* @return 字段
*/
public Field getField() {
@@ -351,7 +363,7 @@ public class BeanDesc implements Serializable{
/**
* 获得字段类型
* 先获取字段的类型,如果字段不存在,则获取Getter方法的返回类型,否则获取Setter的第一个参数类型
- *
+ *
* @return 字段类型
*/
public Type getFieldType() {
@@ -364,7 +376,7 @@ public class BeanDesc implements Serializable{
/**
* 获得字段类型
* 先获取字段的类型,如果字段不存在,则获取Getter方法的返回类型,否则获取Setter的第一个参数类型
- *
+ *
* @return 字段类型
*/
public Class> getFieldClass() {
@@ -376,7 +388,7 @@ public class BeanDesc implements Serializable{
/**
* 获取Getter方法,可能为{@code null}
- *
+ *
* @return Getter方法
*/
public Method getGetter() {
@@ -385,52 +397,75 @@ public class BeanDesc implements Serializable{
/**
* 获取Setter方法,可能为{@code null}
- *
+ *
* @return {@link Method}Setter 方法对象
*/
public Method getSetter() {
return this.setter;
}
-
+
/**
* 获取字段值
* 首先调用字段对应的Getter方法获取值,如果Getter方法不存在,则判断字段如果为public,则直接获取字段值
- *
+ *
* @param bean Bean对象
* @return 字段值
* @since 4.0.5
*/
public Object getValue(Object bean) {
- if(null != this.getter) {
+ if (null != this.getter) {
return ReflectUtil.invoke(bean, this.getter);
- } else if(ModifierUtil.isPublic(this.field)) {
+ } else if (ModifierUtil.isPublic(this.field)) {
return ReflectUtil.getFieldValue(bean, this.field);
}
return null;
}
-
+
/**
* 设置Bean的字段值
* 首先调用字段对应的Setter方法,如果Setter方法不存在,则判断字段如果为public,则直接赋值字段值
- *
- * @param bean Bean对象
+ *
+ * @param bean Bean对象
* @param value 值
* @return this
* @since 4.0.5
*/
public PropDesc setValue(Object bean, Object value) {
- if(null != this.setter) {
+ if (null != this.setter) {
ReflectUtil.invoke(bean, this.setter, value);
- } else if(ModifierUtil.isPublic(this.field)) {
+ } else if (ModifierUtil.isPublic(this.field)) {
ReflectUtil.setFieldValue(bean, this.field, value);
}
return this;
}
-
+
+ /**
+ * 字段和Getter方法是否为Transient关键字修饰的
+ *
+ * @return 是否为Transient关键字修饰的
+ * @since 5.3.11
+ */
+ public boolean isTransient() {
+ boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT);
+
+ // 检查Getter方法
+ if(false == isTransient && null != this.getter){
+ isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT);
+
+ // 检查注解
+ if(false == isTransient){
+ isTransient = null != AnnotationUtil.getAnnotation(this.getter, Transient.class);
+ }
+ }
+
+ return isTransient;
+ }
+
//------------------------------------------------------------------------------------ Private method start
+
/**
* 通过Getter和Setter方法中找到属性类型
- *
+ *
* @param getter Getter方法
* @param setter Setter方法
* @return {@link Type}
@@ -448,7 +483,7 @@ public class BeanDesc implements Serializable{
/**
* 通过Getter和Setter方法中找到属性类型
- *
+ *
* @param getter Getter方法
* @param setter Setter方法
* @return {@link Type}
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java
index 9b6ba3a31..7c1d49a0c 100644
--- a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java
@@ -4,26 +4,41 @@ import java.io.Serializable;
/**
* JSON配置项
- *
+ *
* @author looly
* @since 4.1.19
*/
public class JSONConfig implements Serializable {
private static final long serialVersionUID = 119730355204738278L;
- /** 是否有序,顺序按照加入顺序排序 */
+ /**
+ * 是否有序,顺序按照加入顺序排序
+ */
private boolean order;
- /** 是否忽略转换过程中的异常 */
+ /**
+ * 是否忽略转换过程中的异常
+ */
private boolean ignoreError;
- /** 是否忽略键的大小写 */
+ /**
+ * 是否忽略键的大小写
+ */
private boolean ignoreCase;
- /** 日期格式,null表示默认的时间戳 */
+ /**
+ * 日期格式,null表示默认的时间戳
+ */
private String dateFormat;
- /** 是否忽略null值 */
+ /**
+ * 是否忽略null值
+ */
private boolean ignoreNullValue = true;
-
+ /**
+ * 是否忽略transient关键字修饰的字段
+ */
+ private boolean ignoreTransient = true;
+
/**
* 创建默认的配置项
+ *
* @return JSONConfig
*/
public static JSONConfig create() {
@@ -32,7 +47,7 @@ public class JSONConfig implements Serializable {
/**
* 是否有序,顺序按照加入顺序排序
- *
+ *
* @return 是否有序
*/
public boolean isOrder() {
@@ -41,7 +56,7 @@ public class JSONConfig implements Serializable {
/**
* 设置是否有序,顺序按照加入顺序排序
- *
+ *
* @param order 是否有序
* @return this
*/
@@ -52,7 +67,7 @@ public class JSONConfig implements Serializable {
/**
* 是否忽略转换过程中的异常
- *
+ *
* @return 是否忽略转换过程中的异常
*/
public boolean isIgnoreError() {
@@ -61,7 +76,7 @@ public class JSONConfig implements Serializable {
/**
* 设置是否忽略转换过程中的异常
- *
+ *
* @param ignoreError 是否忽略转换过程中的异常
* @return this
*/
@@ -72,7 +87,7 @@ public class JSONConfig implements Serializable {
/**
* 是否忽略键的大小写
- *
+ *
* @return 是否忽略键的大小写
*/
public boolean isIgnoreCase() {
@@ -81,7 +96,7 @@ public class JSONConfig implements Serializable {
/**
* 设置是否忽略键的大小写
- *
+ *
* @param ignoreCase 是否忽略键的大小写
* @return this
*/
@@ -92,7 +107,7 @@ public class JSONConfig implements Serializable {
/**
* 日期格式,null表示默认的时间戳
- *
+ *
* @return 日期格式,null表示默认的时间戳
*/
public String getDateFormat() {
@@ -101,7 +116,7 @@ public class JSONConfig implements Serializable {
/**
* 设置日期格式,null表示默认的时间戳
- *
+ *
* @param dateFormat 日期格式,null表示默认的时间戳
* @return this
*/
@@ -109,10 +124,10 @@ public class JSONConfig implements Serializable {
this.dateFormat = dateFormat;
return this;
}
-
+
/**
* 是否忽略null值
- *
+ *
* @return 是否忽略null值
*/
public boolean isIgnoreNullValue() {
@@ -121,7 +136,7 @@ public class JSONConfig implements Serializable {
/**
* 设置是否忽略null值
- *
+ *
* @param ignoreNullValue 是否忽略null值
* @return this
*/
@@ -129,4 +144,26 @@ public class JSONConfig implements Serializable {
this.ignoreNullValue = ignoreNullValue;
return this;
}
+
+ /**
+ * 是否忽略transient关键字修饰的字段
+ *
+ * @return 是否忽略transient关键字修饰的字段
+ * @since 5.3.11
+ */
+ public boolean isIgnoreTransient() {
+ return this.ignoreTransient;
+ }
+
+ /**
+ * 设置是否忽略transient关键字修饰的字段
+ *
+ * @param ignoreTransient 是否忽略transient关键字修饰的字段
+ * @return this
+ * @since 5.3.11
+ */
+ public JSONConfig setIgnoreTransient(boolean ignoreTransient) {
+ this.ignoreTransient = ignoreTransient;
+ return this;
+ }
}
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java
index 765656d2f..580a7c417 100644
--- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java
@@ -625,6 +625,11 @@ public class JSONObject implements JSON, JSONGetter, Map
Method getter;
Object value;
for (PropDesc prop : props) {
+ if(this.config.isIgnoreTransient() && prop.isTransient()){
+ // 忽略Transient字段和方法
+ continue;
+ }
+
// 得到property对应的getter方法
getter = prop.getGetter();
if (null == getter) {
diff --git a/hutool-json/src/test/java/cn/hutool/json/TransientTest.java b/hutool-json/src/test/java/cn/hutool/json/TransientTest.java
new file mode 100644
index 000000000..7f6509aa2
--- /dev/null
+++ b/hutool-json/src/test/java/cn/hutool/json/TransientTest.java
@@ -0,0 +1,25 @@
+package cn.hutool.json;
+
+import lombok.Data;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TransientTest {
+
+ @Data
+ static class Bill{
+ private transient String id;
+ private String bizNo;
+ }
+
+ @Test
+ public void beanWithTransientTest(){
+ Bill detailBill = new Bill();
+ detailBill.setId("3243");
+ detailBill.setBizNo("bizNo");
+
+ final JSONObject jsonObject = new JSONObject(detailBill,
+ JSONConfig.create().setIgnoreTransient(true));
+ Assert.assertEquals("{\"bizNo\":\"bizNo\"}", jsonObject.toString());
+ }
+}