Browse Source

add config

Looly 5 years ago
parent
commit
f6f97668cf

+ 1 - 0
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修复
 

+ 88 - 53
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等相关信息描述<br>
  * 查找Getter和Setter方法时会:
- * 
+ *
  * <pre>
  * 1. 忽略字段和方法名的大小写
  * 2. Getter查找getXXX、isXXX、getIsXXX
  * 3. Setter查找setXXX、setIsXXX
  * 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
  * </pre>
- * 
+ *
  * @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<String, PropDesc> 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<PropDesc> 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
+
 	/**
 	 * 初始化<br>
 	 * 只有与属性关联的相关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{
 	/**
 	 * 根据字段创建属性描述<br>
 	 * 查找Getter和Setter方法时会:
-	 * 
+	 *
 	 * <pre>
 	 * 1. 忽略字段和方法名的大小写
 	 * 2. Getter查找getXXX、isXXX、getIsXXX
 	 * 3. Setter查找setXXX、setIsXXX
 	 * 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
 	 * </pre>
-	 * 
+	 *
 	 * @param field 字段
 	 * @return {@link PropDesc}
 	 * @since 4.0.2
@@ -201,7 +208,7 @@ public class BeanDesc implements Serializable{
 	/**
 	 * 方法是否为Getter方法<br>
 	 * 匹配规则如下(忽略大小写):
-	 * 
+	 *
 	 * <pre>
 	 * 字段名    -》 方法名
 	 * isName  -》 isName
@@ -210,9 +217,9 @@ public class BeanDesc implements Serializable{
 	 * name     -》 isName
 	 * name     -》 getName
 	 * </pre>
-	 * 
-	 * @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方法<br>
 	 * 匹配规则如下(忽略大小写):
-	 * 
+	 *
 	 * <pre>
 	 * 字段名    -》 方法名
 	 * isName  -》 setName
 	 * isName  -》 setIsName
 	 * name     -》 setName
 	 * </pre>
-	 * 
-	 * @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;
 
 		/**
 		 * 构造<br>
 		 * 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{
 		/**
 		 * 获得字段类型<br>
 		 * 先获取字段的类型,如果字段不存在,则获取Getter方法的返回类型,否则获取Setter的第一个参数类型
-		 * 
+		 *
 		 * @return 字段类型
 		 */
 		public Type getFieldType() {
@@ -364,7 +376,7 @@ public class BeanDesc implements Serializable{
 		/**
 		 * 获得字段类型<br>
 		 * 先获取字段的类型,如果字段不存在,则获取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;
 		}
-		
+
 		/**
 		 * 获取字段值<br>
 		 * 首先调用字段对应的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的字段值<br>
 		 * 首先调用字段对应的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}

+ 55 - 18
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;
+	}
 }

+ 5 - 0
hutool-json/src/main/java/cn/hutool/json/JSONObject.java

@@ -625,6 +625,11 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
 		Method getter;
 		Object value;
 		for (PropDesc prop : props) {
+			if(this.config.isIgnoreTransient() && prop.isTransient()){
+				// 忽略Transient字段和方法
+				continue;
+			}
+
 			// 得到property对应的getter方法
 			getter = prop.getGetter();
 			if (null == getter) {

+ 25 - 0
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());
+	}
+}