GSON属性个性化定制

 

时候我们不需要把实体的所有属性都导出,只想把一部分属性导出为Json.

有时候我们的实体类会随着版本的升级而修改.

有时候我们想对输出的json默认排好格式.

... ...

请看下面的例子吧:

实体类:

public enum ClientIdEnum {
    APP_GAME(1) // 1:应用中心
    , KITTYPLAY_2V(22) // 22:美化中心
    ;
    private final int value;

    private ClientIdEnum(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

 

public class AppInfo {
	
	public String name;//针对所有产品
	
	@ClientLimit(closeAll = true)
	public String extendMes ;//屏蔽所有产品
	
	@ClientLimit(open = {ClientIdEnum.KITTYPLAY_2V,ClientIdEnum.APP_GAME})
	public String pic;//只针对 美化中心/应用中心 产品
	
	@ClientLimit(close = {ClientIdEnum.APP_GAME})
	public Mes mes = new Mes();//只针对 应用中心 产品

	@Since(value = 1.3)
	public String imgs;//只针对 >=1.3 版本号的所有产品
	
	@Until(value = 1.2)
	public String banner;//只针对 <1.2 版本号的所有产品
	
	public AppInfo(){
		this.name = "应用宝";
		this.pic = "http://pic.png";
		this.imgs = "http://imgs1.png#http://imgs2.png";
		this.banner = "http://banner.png";
		this.extendMes = "备注信息";
	}
}

 

@Target({ElementType.FIELD}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Inherited
public @interface ClientLimit {
	/**
	 * @Title: open
	 * @Description:  定义需开放的产品,进行json转换
	 * @param @return    设定文件
	 * @return ClientIdEnum[]    返回类型
	 * @throws
	 */
	ClientIdEnum[] open() default {};
	
	/**
	 * @Title: close
	 * @Description: 定义需关闭的产品,不进行json转换
	 * @param @return    设定文件
	 * @return ClientIdEnum[]    返回类型
	 * @throws
	 */
	ClientIdEnum[] close() default {};
	
	/**
	 * @Title: closeAll
	 * @Description: 定义关闭所有产品,不进行json转换
	 * @param @return    设定文件
	 * @return boolean    返回类型
	 * @throws
	 */
	boolean closeAll() default false;
}

 

public class ClientIdExclusionStrategy implements ExclusionStrategy {

	private ClientIdEnum clientId = null;
	
	public ClientIdExclusionStrategy(ClientIdEnum clientId){
		this.clientId = clientId;
	}
	@Override
	public boolean shouldSkipField(FieldAttributes f) {
		boolean filter = false;
		
		ClientLimit clientLimit = f.getAnnotation(ClientLimit.class);
		if(clientLimit != null){
			boolean closeAll = clientLimit.closeAll();
			if(closeAll){
				filter = true;
			}else {
				ClientIdEnum[] open = clientLimit.open();
				ClientIdEnum[] close = clientLimit.close();
				if(open.length > 0){
					filter = true;
					for(ClientIdEnum clientIdEnum:open){
						if(clientId == clientIdEnum){
							filter = false;
							break;
						}
					}
				}else if (close.length > 0) {
					filter = false;
					for(ClientIdEnum clientIdEnum:close){
						if(clientId == clientIdEnum){
							filter = true;
							break;
						}
					}
				}
			}
		}
		return filter;
	}

	@Override
	public boolean shouldSkipClass(Class<?> clazz) {
		// TODO Auto-generated method stub
		return false;
	}

}

 

 

public class Test  extends TestCase{

	public void testGson(){
		AppInfo appInfo = new AppInfo();
		//注意这里的Gson的构建方式为GsonBuilder,区别于test1中的Gson gson = new Gson();  
        Gson gson = new GsonBuilder()  
//        .excludeFieldsWithoutExposeAnnotation() //不导出实体中没有用@Expose注解的属性  
        .enableComplexMapKeySerialization() //支持Map的key为复杂对象的形式  
        .serializeNulls() //若对象为null,则进行 null 转换;默认null值不进行转换
        .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")//时间转化为特定格式    
//        .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//会把字段首字母大写,注:对于实体上使用了@SerializedName注解的不会生效.  
        .setPrettyPrinting() //对json结果格式化.  
        .setVersion(1.2)    //有的字段不是一开始就有的,会随着版本的升级添加进来,那么在进行序列化和返序列化的时候就会根据版本号来选择是否要序列化.  
                            //@Since(版本号)能完美地实现这个功能.还的字段可能,随着版本的升级而删除,那么  
                            //@Until(版本号)也能实现这个功能,GsonBuilder.setVersion(double)方法需要调用.  
        .setExclusionStrategies(new ClientIdExclusionStrategy(ClientIdEnum.APP_GAME))//自定义属性过滤器
//        .registerTypeAdapter(type, typeAdapter) //自定义适配器,对属性类型为 type类型的,进行typeAdapter转换,如时间格式化等 
        .create(); 
        System.out.println(gson.toJson(appInfo));
	}
}

 

### JSON反序列化的原理 JSON反序列化是指将JSON格式的字符串转换为程序中的对象的过程。这一过程通常依赖于解析器,其核心在于识别JSON结构并将其映射到目标语言的对象模型中。 #### 解析阶段 在反序列化过程中,首先需要对输入的JSON字符串进行词法分析和语法分析。这一步骤的目标是从原始字符串提取键值对,并构建一个中间表示形式(通常是树状结构)。例如,在Java中,`JsonReader` 或 `ObjectMapper` 类负责逐字符扫描JSON字符串,识别出诸如 `{}` 表示的对象、`[]` 表示的数组以及基本数据类型如整数、浮点数、布尔值等[^1]。 #### 映射阶段 一旦完成了初步解析,下一步就是将这些抽象出来的节点与实际的应用层对象关联起来。具体来说: - **属性匹配**:对于每一个从JSON读取出的名字-值组合,系统尝试找到对应实体类里的同名成员变量。如果名字完全一致,则直接赋值;否则可能涉及到自定义规则的支持,比如大小写忽略或前缀移除等功能。 - **类型转换**:即使名称能够成功配对,还需要考虑源端的数据类型是否能无损地转为目标平台上的某种表达方式。例如日期时间字段往往不是简单的字符串而是复杂的Calendar实例,这就要求额外编写适配逻辑[^3]。 #### 处理嵌套结构 当遇到复合型数据时——即包含其他子对象或者集合类型的字段情况下的处理尤为重要。此时递归调用成为必要手段之一。每当触及一个新的层次级次,就启动新一轮的小规模重复操作直至最底层单元全部被遍历完毕为止[^5]。 另外值得注意的是某些高级框架还提供插件扩展能力使得用户可以在默认行为之外加入个性化定制选项,像Gson里提到过的可以通过实现`JsonDeserializer<T>`接口来自行决定如何解释特定种类的信息块。 ```java // 示例代码展示了一个简单版本的手动实现部分功能片段 public class CustomDeserializer implements JsonDeserializer<MyClass> { @Override public MyClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); String fieldA = jsonObject.get("field_a").getAsString(); // 获取string类型的字段 int fieldB = jsonObject.get("field_b").getAsInt(); // 获取integer类型的字段 List<String> listFieldC = new ArrayList<>(); JsonArray jsonArray = (JsonArray) jsonObject.get("list_field_c"); for (JsonElement element : jsonArray){ listFieldC.add(element.getAsString()); } return new MyClass(fieldA, fieldB, listFieldC); } } ``` 上述例子展示了手动控制反序列化进程的一个方面,其中包含了获取不同基础类型的方法调用以及针对List这样的容器类型特别设计的操作流程说明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值