add config

This commit is contained in:
Looly 2020-07-31 09:43:05 +08:00
parent dd7f04af44
commit f6f97668cf
5 changed files with 174 additions and 71 deletions

View File

@ -9,6 +9,7 @@
* 【captcha】 AbstractCaptcha增加getImageBase64Data方法pr#985@Github * 【captcha】 AbstractCaptcha增加getImageBase64Data方法pr#985@Github
* 【core 】 增加PhoneUtilpr#990@Github * 【core 】 增加PhoneUtilpr#990@Github
* 【core 】 改进Img目标图片类型未定义使用源图片类型issue#I1PB0B@Gitee * 【core 】 改进Img目标图片类型未定义使用源图片类型issue#I1PB0B@Gitee
* 【json 】 JSONConfig增加Transient选项issue#I1PLHN@Gitee
### Bug修复 ### Bug修复

View File

@ -1,5 +1,6 @@
package cn.hutool.core.bean; package cn.hutool.core.bean;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.util.BooleanUtil; 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.StrUtil;
import cn.hutool.core.util.TypeUtil; import cn.hutool.core.util.TypeUtil;
import java.beans.Transient;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -20,28 +22,32 @@ import java.util.Map;
/** /**
* Bean信息描述做为BeanInfo替代方案此对象持有JavaBean中的setters和getters等相关信息描述<br> * Bean信息描述做为BeanInfo替代方案此对象持有JavaBean中的setters和getters等相关信息描述<br>
* 查找Getter和Setter方法时会 * 查找Getter和Setter方法时会
* *
* <pre> * <pre>
* 1. 忽略字段和方法名的大小写 * 1. 忽略字段和方法名的大小写
* 2. Getter查找getXXXisXXXgetIsXXX * 2. Getter查找getXXXisXXXgetIsXXX
* 3. Setter查找setXXXsetIsXXX * 3. Setter查找setXXXsetIsXXX
* 4. Setter忽略参数值与字段值不匹配的情况因此有多个参数类型的重载时会调用首次匹配的 * 4. Setter忽略参数值与字段值不匹配的情况因此有多个参数类型的重载时会调用首次匹配的
* </pre> * </pre>
* *
* @author looly * @author looly
* @since 3.1.2 * @since 3.1.2
*/ */
public class BeanDesc implements Serializable{ public class BeanDesc implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** Bean类 */ /**
* Bean类
*/
private final Class<?> beanClass; private final Class<?> beanClass;
/** 属性Map */ /**
* 属性Map
*/
private final Map<String, PropDesc> propMap = new LinkedHashMap<>(); private final Map<String, PropDesc> propMap = new LinkedHashMap<>();
/** /**
* 构造 * 构造
* *
* @param beanClass Bean类 * @param beanClass Bean类
*/ */
public BeanDesc(Class<?> beanClass) { public BeanDesc(Class<?> beanClass) {
@ -52,7 +58,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取Bean的全类名 * 获取Bean的全类名
* *
* @return Bean的类名 * @return Bean的类名
*/ */
public String getName() { public String getName() {
@ -61,7 +67,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取Bean的简单类名 * 获取Bean的简单类名
* *
* @return Bean的类名 * @return Bean的类名
*/ */
public String getSimpleName() { public String getSimpleName() {
@ -70,7 +76,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取字段名-字段属性Map * 获取字段名-字段属性Map
* *
* @param ignoreCase 是否忽略大小写true为忽略false不忽略 * @param ignoreCase 是否忽略大小写true为忽略false不忽略
* @return 字段名-字段属性Map * @return 字段名-字段属性Map
*/ */
@ -80,7 +86,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取字段属性列表 * 获取字段属性列表
* *
* @return {@link PropDesc} 列表 * @return {@link PropDesc} 列表
*/ */
public Collection<PropDesc> getProps() { public Collection<PropDesc> getProps() {
@ -89,7 +95,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取属性如果不存在返回null * 获取属性如果不存在返回null
* *
* @param fieldName 字段名 * @param fieldName 字段名
* @return {@link PropDesc} * @return {@link PropDesc}
*/ */
@ -99,7 +105,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获得字段名对应的字段对象如果不存在返回null * 获得字段名对应的字段对象如果不存在返回null
* *
* @param fieldName 字段名 * @param fieldName 字段名
* @return 字段值 * @return 字段值
*/ */
@ -110,7 +116,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取Getter方法如果不存在返回null * 获取Getter方法如果不存在返回null
* *
* @param fieldName 字段名 * @param fieldName 字段名
* @return Getter方法 * @return Getter方法
*/ */
@ -121,7 +127,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取Setter方法如果不存在返回null * 获取Setter方法如果不存在返回null
* *
* @param fieldName 字段名 * @param fieldName 字段名
* @return Setter方法 * @return Setter方法
*/ */
@ -129,17 +135,18 @@ public class BeanDesc implements Serializable{
final PropDesc desc = this.propMap.get(fieldName); final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getSetter(); return null == desc ? null : desc.getSetter();
} }
// ------------------------------------------------------------------------------------------------------ Private method start // ------------------------------------------------------------------------------------------------------ Private method start
/** /**
* 初始化<br> * 初始化<br>
* 只有与属性关联的相关Getter和Setter方法才会被读取无关的getXXX和setXXX都被忽略 * 只有与属性关联的相关Getter和Setter方法才会被读取无关的getXXX和setXXX都被忽略
* *
* @return this * @return this
*/ */
private BeanDesc init() { private BeanDesc init() {
for (Field field : ReflectUtil.getFields(this.beanClass)) { for (Field field : ReflectUtil.getFields(this.beanClass)) {
if(false == ModifierUtil.isStatic(field)) { if (false == ModifierUtil.isStatic(field)) {
//只针对非static属性 //只针对非static属性
this.propMap.put(ReflectUtil.getFieldName(field), createProp(field)); this.propMap.put(ReflectUtil.getFieldName(field), createProp(field));
} }
@ -150,14 +157,14 @@ public class BeanDesc implements Serializable{
/** /**
* 根据字段创建属性描述<br> * 根据字段创建属性描述<br>
* 查找Getter和Setter方法时会 * 查找Getter和Setter方法时会
* *
* <pre> * <pre>
* 1. 忽略字段和方法名的大小写 * 1. 忽略字段和方法名的大小写
* 2. Getter查找getXXXisXXXgetIsXXX * 2. Getter查找getXXXisXXXgetIsXXX
* 3. Setter查找setXXXsetIsXXX * 3. Setter查找setXXXsetIsXXX
* 4. Setter忽略参数值与字段值不匹配的情况因此有多个参数类型的重载时会调用首次匹配的 * 4. Setter忽略参数值与字段值不匹配的情况因此有多个参数类型的重载时会调用首次匹配的
* </pre> * </pre>
* *
* @param field 字段 * @param field 字段
* @return {@link PropDesc} * @return {@link PropDesc}
* @since 4.0.2 * @since 4.0.2
@ -201,7 +208,7 @@ public class BeanDesc implements Serializable{
/** /**
* 方法是否为Getter方法<br> * 方法是否为Getter方法<br>
* 匹配规则如下忽略大小写 * 匹配规则如下忽略大小写
* *
* <pre> * <pre>
* 字段名 - 方法名 * 字段名 - 方法名
* isName - isName * isName - isName
@ -210,9 +217,9 @@ public class BeanDesc implements Serializable{
* name - isName * name - isName
* name - getName * name - getName
* </pre> * </pre>
* *
* @param methodName 方法名 * @param methodName 方法名
* @param fieldName 字段名 * @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段 * @param isBooeanField 是否为Boolean类型字段
* @return 是否匹配 * @return 是否匹配
*/ */
@ -225,7 +232,7 @@ public class BeanDesc implements Serializable{
// 非标准Getter方法 // 非标准Getter方法
return false; return false;
} }
if("getclass".equals(methodName)) { if ("getclass".equals(methodName)) {
//跳过getClass方法 //跳过getClass方法
return false; return false;
} }
@ -253,16 +260,16 @@ public class BeanDesc implements Serializable{
/** /**
* 方法是否为Setter方法<br> * 方法是否为Setter方法<br>
* 匹配规则如下忽略大小写 * 匹配规则如下忽略大小写
* *
* <pre> * <pre>
* 字段名 - 方法名 * 字段名 - 方法名
* isName - setName * isName - setName
* isName - setIsName * isName - setIsName
* name - setName * name - setName
* </pre> * </pre>
* *
* @param methodName 方法名 * @param methodName 方法名
* @param fieldName 字段名 * @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段 * @param isBooeanField 是否为Boolean类型字段
* @return 是否匹配 * @return 是否匹配
*/ */
@ -293,24 +300,29 @@ public class BeanDesc implements Serializable{
/** /**
* 属性描述 * 属性描述
*
* @author looly
* *
* @author looly
*/ */
public static class PropDesc { public static class PropDesc {
/** 字段 */ /**
* 字段
*/
private final Field field; private final Field field;
/** Getter方法 */ /**
* Getter方法
*/
private final Method getter; private final Method getter;
/** Setter方法 */ /**
* Setter方法
*/
private final Method setter; private final Method setter;
/** /**
* 构造<br> * 构造<br>
* Getter和Setter方法设置为默认可访问 * Getter和Setter方法设置为默认可访问
* *
* @param field 字段 * @param field 字段
* @param getter get方法 * @param getter get方法
* @param setter set方法 * @param setter set方法
*/ */
@ -322,7 +334,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取字段名如果存在Alias注解读取注解的值作为名称 * 获取字段名如果存在Alias注解读取注解的值作为名称
* *
* @return 字段名 * @return 字段名
*/ */
public String getFieldName() { public String getFieldName() {
@ -341,7 +353,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取字段 * 获取字段
* *
* @return 字段 * @return 字段
*/ */
public Field getField() { public Field getField() {
@ -351,7 +363,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获得字段类型<br> * 获得字段类型<br>
* 先获取字段的类型如果字段不存在则获取Getter方法的返回类型否则获取Setter的第一个参数类型 * 先获取字段的类型如果字段不存在则获取Getter方法的返回类型否则获取Setter的第一个参数类型
* *
* @return 字段类型 * @return 字段类型
*/ */
public Type getFieldType() { public Type getFieldType() {
@ -364,7 +376,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获得字段类型<br> * 获得字段类型<br>
* 先获取字段的类型如果字段不存在则获取Getter方法的返回类型否则获取Setter的第一个参数类型 * 先获取字段的类型如果字段不存在则获取Getter方法的返回类型否则获取Setter的第一个参数类型
* *
* @return 字段类型 * @return 字段类型
*/ */
public Class<?> getFieldClass() { public Class<?> getFieldClass() {
@ -376,7 +388,7 @@ public class BeanDesc implements Serializable{
/** /**
* 获取Getter方法可能为{@code null} * 获取Getter方法可能为{@code null}
* *
* @return Getter方法 * @return Getter方法
*/ */
public Method getGetter() { public Method getGetter() {
@ -385,52 +397,75 @@ public class BeanDesc implements Serializable{
/** /**
* 获取Setter方法可能为{@code null} * 获取Setter方法可能为{@code null}
* *
* @return {@link Method}Setter 方法对象 * @return {@link Method}Setter 方法对象
*/ */
public Method getSetter() { public Method getSetter() {
return this.setter; return this.setter;
} }
/** /**
* 获取字段值<br> * 获取字段值<br>
* 首先调用字段对应的Getter方法获取值如果Getter方法不存在则判断字段如果为public则直接获取字段值 * 首先调用字段对应的Getter方法获取值如果Getter方法不存在则判断字段如果为public则直接获取字段值
* *
* @param bean Bean对象 * @param bean Bean对象
* @return 字段值 * @return 字段值
* @since 4.0.5 * @since 4.0.5
*/ */
public Object getValue(Object bean) { public Object getValue(Object bean) {
if(null != this.getter) { if (null != this.getter) {
return ReflectUtil.invoke(bean, 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 ReflectUtil.getFieldValue(bean, this.field);
} }
return null; return null;
} }
/** /**
* 设置Bean的字段值<br> * 设置Bean的字段值<br>
* 首先调用字段对应的Setter方法如果Setter方法不存在则判断字段如果为public则直接赋值字段值 * 首先调用字段对应的Setter方法如果Setter方法不存在则判断字段如果为public则直接赋值字段值
* *
* @param bean Bean对象 * @param bean Bean对象
* @param value * @param value
* @return this * @return this
* @since 4.0.5 * @since 4.0.5
*/ */
public PropDesc setValue(Object bean, Object value) { public PropDesc setValue(Object bean, Object value) {
if(null != this.setter) { if (null != this.setter) {
ReflectUtil.invoke(bean, this.setter, value); ReflectUtil.invoke(bean, this.setter, value);
} else if(ModifierUtil.isPublic(this.field)) { } else if (ModifierUtil.isPublic(this.field)) {
ReflectUtil.setFieldValue(bean, this.field, value); ReflectUtil.setFieldValue(bean, this.field, value);
} }
return this; 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 //------------------------------------------------------------------------------------ Private method start
/** /**
* 通过Getter和Setter方法中找到属性类型 * 通过Getter和Setter方法中找到属性类型
* *
* @param getter Getter方法 * @param getter Getter方法
* @param setter Setter方法 * @param setter Setter方法
* @return {@link Type} * @return {@link Type}
@ -448,7 +483,7 @@ public class BeanDesc implements Serializable{
/** /**
* 通过Getter和Setter方法中找到属性类型 * 通过Getter和Setter方法中找到属性类型
* *
* @param getter Getter方法 * @param getter Getter方法
* @param setter Setter方法 * @param setter Setter方法
* @return {@link Type} * @return {@link Type}

View File

@ -4,26 +4,41 @@ import java.io.Serializable;
/** /**
* JSON配置项 * JSON配置项
* *
* @author looly * @author looly
* @since 4.1.19 * @since 4.1.19
*/ */
public class JSONConfig implements Serializable { public class JSONConfig implements Serializable {
private static final long serialVersionUID = 119730355204738278L; private static final long serialVersionUID = 119730355204738278L;
/** 是否有序,顺序按照加入顺序排序 */ /**
* 是否有序顺序按照加入顺序排序
*/
private boolean order; private boolean order;
/** 是否忽略转换过程中的异常 */ /**
* 是否忽略转换过程中的异常
*/
private boolean ignoreError; private boolean ignoreError;
/** 是否忽略键的大小写 */ /**
* 是否忽略键的大小写
*/
private boolean ignoreCase; private boolean ignoreCase;
/** 日期格式null表示默认的时间戳 */ /**
* 日期格式null表示默认的时间戳
*/
private String dateFormat; private String dateFormat;
/** 是否忽略null值 */ /**
* 是否忽略null值
*/
private boolean ignoreNullValue = true; private boolean ignoreNullValue = true;
/**
* 是否忽略transient关键字修饰的字段
*/
private boolean ignoreTransient = true;
/** /**
* 创建默认的配置项 * 创建默认的配置项
*
* @return JSONConfig * @return JSONConfig
*/ */
public static JSONConfig create() { public static JSONConfig create() {
@ -32,7 +47,7 @@ public class JSONConfig implements Serializable {
/** /**
* 是否有序顺序按照加入顺序排序 * 是否有序顺序按照加入顺序排序
* *
* @return 是否有序 * @return 是否有序
*/ */
public boolean isOrder() { public boolean isOrder() {
@ -41,7 +56,7 @@ public class JSONConfig implements Serializable {
/** /**
* 设置是否有序顺序按照加入顺序排序 * 设置是否有序顺序按照加入顺序排序
* *
* @param order 是否有序 * @param order 是否有序
* @return this * @return this
*/ */
@ -52,7 +67,7 @@ public class JSONConfig implements Serializable {
/** /**
* 是否忽略转换过程中的异常 * 是否忽略转换过程中的异常
* *
* @return 是否忽略转换过程中的异常 * @return 是否忽略转换过程中的异常
*/ */
public boolean isIgnoreError() { public boolean isIgnoreError() {
@ -61,7 +76,7 @@ public class JSONConfig implements Serializable {
/** /**
* 设置是否忽略转换过程中的异常 * 设置是否忽略转换过程中的异常
* *
* @param ignoreError 是否忽略转换过程中的异常 * @param ignoreError 是否忽略转换过程中的异常
* @return this * @return this
*/ */
@ -72,7 +87,7 @@ public class JSONConfig implements Serializable {
/** /**
* 是否忽略键的大小写 * 是否忽略键的大小写
* *
* @return 是否忽略键的大小写 * @return 是否忽略键的大小写
*/ */
public boolean isIgnoreCase() { public boolean isIgnoreCase() {
@ -81,7 +96,7 @@ public class JSONConfig implements Serializable {
/** /**
* 设置是否忽略键的大小写 * 设置是否忽略键的大小写
* *
* @param ignoreCase 是否忽略键的大小写 * @param ignoreCase 是否忽略键的大小写
* @return this * @return this
*/ */
@ -92,7 +107,7 @@ public class JSONConfig implements Serializable {
/** /**
* 日期格式null表示默认的时间戳 * 日期格式null表示默认的时间戳
* *
* @return 日期格式null表示默认的时间戳 * @return 日期格式null表示默认的时间戳
*/ */
public String getDateFormat() { public String getDateFormat() {
@ -101,7 +116,7 @@ public class JSONConfig implements Serializable {
/** /**
* 设置日期格式null表示默认的时间戳 * 设置日期格式null表示默认的时间戳
* *
* @param dateFormat 日期格式null表示默认的时间戳 * @param dateFormat 日期格式null表示默认的时间戳
* @return this * @return this
*/ */
@ -109,10 +124,10 @@ public class JSONConfig implements Serializable {
this.dateFormat = dateFormat; this.dateFormat = dateFormat;
return this; return this;
} }
/** /**
* 是否忽略null值 * 是否忽略null值
* *
* @return 是否忽略null值 * @return 是否忽略null值
*/ */
public boolean isIgnoreNullValue() { public boolean isIgnoreNullValue() {
@ -121,7 +136,7 @@ public class JSONConfig implements Serializable {
/** /**
* 设置是否忽略null值 * 设置是否忽略null值
* *
* @param ignoreNullValue 是否忽略null值 * @param ignoreNullValue 是否忽略null值
* @return this * @return this
*/ */
@ -129,4 +144,26 @@ public class JSONConfig implements Serializable {
this.ignoreNullValue = ignoreNullValue; this.ignoreNullValue = ignoreNullValue;
return this; 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;
}
} }

View File

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

View File

@ -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());
}
}