fastjson:javabean按字段(field)序列化存储为Map并反序列化改进

Fastjson优化序列化
本文介绍了一种使用Fastjson优化的序列化方法,该方法减少了序列化过程中的步骤,提高了效率。通过直接将JavaBean转换为JSONObject再进一步序列化为字符串的方式,避免了不必要的反序列化过程。

#需求说明

最近的项目应用到redis数据库,需要将java bean存储在redis数据库。因为需要对数据库中的某个字段进行修改,所以在redis上不能用简单的string类型存储,而要以hash类型存储。这就需要在向数据库写入java bean对象之前要将java bean按字段序列化为一个Map<String,String>
而在从数据库读取后,又需要将所有字段合并反序列化还原成一个java bean对象。

上一篇博客《fastjson:javabean按字段(field)序列化存储为Map并反序列化》实现了 java bean按字段序列化和反序列化,但在文章结尾总结时也说明了这种方式的缺点,就是存在反复序列化的过程,会在一定程度上影响效率,不够完美。

刚才进一步研究了fastjson的代码,找到了更好的方案,减少序列化过程。

#序列化
实现步骤:
1.用JSON.toJSON(Object)将java bean解析为JSONObject对象(其实也是一个Map<String,Object>,JSONObject实现了Map接口).
2.对上一步中的JSONObject中每个字段调用JSON.toJSONString(Object)进行序列化,最终生成符合redis数据库hash类型存储要求的Map<String,String>

与前文《fastjson:javabean按字段(field)序列化存储为Map并反序列化》的方法相比,只有两个步骤,没有多余的序列化和反序列化过程。

#反序列化
反序列化阶段与与前文《fastjson:javabean按字段(field)序列化存储为Map并反序列化》的方法相同
实现步骤:
1.从redis获取所有字段数据,也就是一个Map<String,String>.对Map中每个字段的json string调用 JSON.parse(String)反序列化,生成一个Map<String,Object>,其中的Object就是字段反序列化生成的对象
2.调用 com.alibaba.fastjson.util.TypeUtils.cast(Object , Type , ParserConfig)方法将上一步的Map<String,Object>还原为java bean对象

#实现代码及测试

package net.gdface.facelog.message;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class TestFastjson {


	@Test
	public void testJSONObject() {
		Group group = new Group();
		group.setId(0L);
		group.setName("admin");

		User guestUser = new User();
		guestUser.setId(2L);
		guestUser.setName("guest");

		User rootUser = new User();
		rootUser.setId(3L);
		rootUser.setName("root");

		group.addUser(guestUser);
		group.addUser(rootUser);
		{
			////////// 按字段序列化 ///////////////
			// 序列化步骤1
			JSONObject jsonObject = (JSONObject) JSON.toJSON(group);
			Map<String, String> jsonObj = new HashMap<String, String>();
			// 序列化步骤2
			for (Entry<String, Object> entry : jsonObject.entrySet()) {
				Object value = entry.getValue();
				if(null !=value){
					String jsonValue=JSON.toJSONString(value);
					jsonObj.put(entry.getKey(), jsonValue);
				}
			}
            ////////// 按字段反序列化 ///////////////
            // 反序列化步骤1
			Map<String, Object> deJsonMap = new HashMap<String, Object>();
			for (Entry<String, String> entry : jsonObj.entrySet()) {
				String json = (String) entry.getValue();
				String key = entry.getKey();
				Object field = JSON.parse( json);
				deJsonMap.put(entry.getKey(), field);
			}
            // 循环结束时 Map<String, Object>中的每个字段对应的Object都是反序列化后的对象
            // 反序列化步骤2
			Group dgroup = com.alibaba.fastjson.util.TypeUtils.cast(deJsonMap, Group.class, null);
			System.out.println(JSON.toJSONString(dgroup));
		}		
	}
	public interface Person<T>{
		
	}
	public static class User implements Person<String>{

	    private Long   id;
	    private String name;


	    public Long getId() {
	        return id;
	    }

	    public void setId(Long id) {
	        this.id = id;
	    }

	    public String getName() {
	        return name;
	    }

	    public void setName(String name) {
	        this.name = name;
	    }

	}
	public static  class Group {

	    private Long       id;
	    private String     name;
	    private List<User> users = new ArrayList<User>();
	    public Date date=new Date();
	    public java.sql.Date sqldate=new java.sql.Date(date.getTime());
	    public byte[] array=new byte[]{22,33,3,2,3,1,5,-1};
	    public String nullStr=null;
	    private String privString="private string";
	    public Long getId() {
	        return id;
	    }

	    public void setId(Long id) {
	        this.id = id;
	    }

	    public String getName() {
	        return name;
	    }

	    public void setName(String name) {
	        this.name = name;
	    }

	    public List<User> getUsers() {
	        return users;
	    }

	    public void setUsers(List<User> users) {
	        this.users = users;
	    }

	        public void addUser(User user) {
	            users.add(user);
	        }
	}
}

#注意

《fastjson:javabean按字段(field)序列化存储为Map并反序列化》的方法(简称方法1)相比,这种方式序列化出的json string是不同的。
比如对于byte[]类型方法1会序列成base64格式的字符串"FiEDAgMBBf8="
而本方法则会序列化成json数组[22,33,3,2,3,1,5,-1],显然方法1对byte[]类型序列化的字符串体积要小。

总而言之,方法1序列化的字符串与用JSON.toJSONString(Object)方法对java bean整体序列化的结果保持一致。而本方法序列化的结果则不会。

<think> 首先,用户的问题是:“我想查找fastjson对Date类型进行反序列化的相关内容,如方法、示例、解决方案等 请问fastjson对Date类型进行反序列化的方法和示例”。基于用户提供的引用,我需要整合信息来回答。 用户提供的引用包括: - [^1]:讨论定制序列化反序列化使用@JSONField注解或指定序列化/反序列化类。 - [^2]:解决反序列化日期0000-00-00失败的问题,提到全局设置和自定义反序列化解析器。 - [^3]:自定义反序列化方法,通过实现ObjectDeserializer接口。 - [^4]:自定义Date类型反序列化,提到DateCodec类和解决方案。 - [^5]:fastjson对Date类型的处理,包括日期格式设置和使用SerializerFeature。 我的回答需要: - 使用中文。 - 结构清晰,帮助用户逐步解决问题。 - 尽量保证真实可靠。 - 在行内数学表达式用$...$,独立公式用$$...$$(但在本内容中可能不涉及数学公式)。 - 生成相关问题。 - 在引用的末尾自然地添加引用标识。 系统指令还强调:生成相关问题,在回答中引用的段落末尾添加引用标识。 关键点:用户问的是fastjson对Date类型进行反序列化的方法和示例。所以,我需要专注于反序列化反序列化是将JSON字符串转换为Java对象),而不是序列化。 从引用中提取相关信息: - [^1]:提到自定义序列化反序列化,可以使用serializeUsing和deserializeUsing指定类。 - [^2]:建议使用自定义反序列化解析器来处理特定日期格式问题。 - [^3]:描述如何添加类的自定义反序列化方法,通过实现ObjectDeserializer接口注册。 - [^4]:指出在fastjson中,Date类型的反序列化使用DateCodec类,提供解决方案。 - [^5]:展示如何设置日期格式全局或使用SerializerFeature。 结构化回答: 1. **介绍方法**:总结fastjson反序列化Date类型的常见方法。 2. **提供示例**:基于引用,给出代码示例。 3. **解决方案**:讨论常见问题和解决方案,如处理特定日期格式或错误。 4. **添加引用**:在相关内容末尾添加引用标识。 5. **生成相关问题**:在回答结束添加相关问题部分。 ### 回答大纲: - **简介**:简述fastjson处理Date类型反序列化的方式。 - **方法1:使用全局日期格式**:通过设置静态属性或使用SerializerFeature。 - 示例代码:[^5] - **方法2:使用注解**:在类属性上使用@JSONField注解指定格式。 - 示例:[^1],但[^1]更侧重自定义类。 - **方法3:自定义反序列化器**:实现ObjectDeserializer接口。 - 示例:[^3]和[^2] - **常见问题解决**:如处理"0000-00-00"失败问题。 - 方案:[^2] - **示例整合**:结合引用提供完整示例。 - **相关问题**:生成相关问题。 确保引用添加: - 在描述每个方法,如果基于某个引用,就在末尾添加[^x]。 ### 完整回答: #### fastjson对Date类型反序列化的方法和示例 在fastjson中,反序列化Date类型有多种方式,包括设置全局日期格式、使用注解或自定义反序列化器。以下是详细方法和示例。 1. **设置全局日期格式** 可以通过设置`JSON.DEFFAULT_DATE_FORMAT`静态属性来定义全局日期格式。但请注意,这会影响所有反序列化操作[^2]。 示例代码: ```java JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; Date date = JSON.parseObject(jsonString, Date.class); // 反序列化会应用格式 ``` 或者使用`SerializerFeature.WriteDateUseDateFormat`特性: ```java JSONObject.parseObject(jsonString, Date.class, SerializerFeature.WriteDateUseDateFormat); // 但此特性主要用于序列化反序列化需注意 ``` 参考[^5]。 2. **使用@JSONField注解** 在JavaBean的属性上添加`@JSONField`注解,指定`format`属性来控制日期格式。 示例: ```java public class MyBean { @JSONField(format = "yyyy-MM-dd") private Date myDate; // getters and setters } MyBean bean = JSON.parseObject(jsonString, MyBean.class); // 反序列化自动应用格式 ``` 这简化了处理[^1]。 3. **自定义反序列化器** 对于更复杂的需求,如处理特殊日期格式(如"0000-00-00")或自定义逻辑,可以实现`ObjectDeserializer`接口注册。 步骤: - 实现`com.alibaba.fastjson.parser.deserializer.ObjectDeserializer`接口。 - 重写`deserialze`方法。 - 注册自定义反序列化器到`ParserConfig`。 示例代码: ```java public class CustomDateDeserializer implements ObjectDeserializer { @Override public Date deserialze(DefaultJSONParser parser, Type type, Object fieldName) { // 自定义解析逻辑,例如处理"0000-00-00" String dateStr = parser.parseString(); if ("0000-00-00".equals(dateStr)) { return null; // 或自定义处理 } try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.parse(dateStr); } catch (ParseException e) { throw new JSONException("Parse date error", e); } } @Override public int getFastMatchToken() { return JSONToken.LITERAL_STRING; } } // 注册自定义反序列化器 ParserConfig.getGlobalInstance().putDeserializer(Date.class, new CustomDateDeserializer()); // 然后使用JSON.parseObject反序列化 Date date = JSON.parseObject(jsonString, Date.class); ``` 参考[^2][^3][^4]。 **常见问题解决方案** - **处理"0000-00-00"失败**:fastjson可能无法解析无效日期。使用自定义反序列化器可以绕过此问题[^2]。 - **版本兼容**:在较新版本中(如1.2.38+),Date类型的反序列化通过`DateCodec`类处理[^4]。 以上方法可根据具体需求选择使用。 §§相关问题§§ 1. 如何设置fastjson的全局日期格式? 2. 使用@JSONField注解需要注意什么? 3. 自定义反序列化器如何应用于特定类? 4. 解决fastjson反序列化Date类型遇到的常见错误? 5. fastjson序列化Date类型有哪些方法? 在回答中,我已自然地添加了引用标识。 </think> ### fastjson对Date类型进行反序列化的方法和示例 在fastjson中,反序列化Date类型涉及处理JSON字符串转换为Java `java.util.Date`对象的需求。以下是核心方法、示例和解决方案,基于最佳实践和常见问题总结。fastjson提供了灵活的机制,包括全局设置、注解和自定义反序列化器。 #### 1. **使用全局日期格式** - **方法**:通过设置静态属性 `JSON.DEFFAULT_DATE_FORMAT` 定义全局日期格式,适用于所有反序列化操作。但需注意,此设置是全局性的,可能影响其他部分的代码[^2]。 - **示例代码**: ```java // 设置全局日期格式 JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; // 反序列化JSON字符串到Date对象 String jsonString = "{\"date\":\"2023-10-01 12:30:45\"}"; Date date = JSON.parseObject(jsonString).getObject("date", Date.class); System.out.println(date); // 输出: Sat Oct 01 12:30:45 CST 2023 ``` - **说明**:此方法简单,但全局设置需谨慎,避免副作用[^2][^5]。 #### 2. **使用@JSONField注解** - **方法**:在JavaBean的属性上添加 `@JSONField` 注解,指定日期格式(`format` 属性)。这允许每个字段独立控制格式,避免全局影响[^1]。 - **示例代码**: ```java public class User { @JSONField(format = "yyyy-MM-dd") // 指定日期格式 private Date birthDate; // Getter和Setter省略 } // 反序列化 String json = "{\"birthDate\":\"1990-05-15\"}"; User user = JSON.parseObject(json, User.class); System.out.println(user.getBirthDate()); // 输出: Tue May 15 00:00:00 CST 1990 ``` - **说明**:适合结构化对象,但不能直接用于基本类型(如直接 `Date` 反序列化)[^1]。 #### 3. **自定义反序列化器** - **方法**:实现 `ObjectDeserializer` 接口,自定义日期解析逻辑(如处理特殊格式或无效日期)。注册到 `ParserConfig` 后,fastjson反序列化自动调用[^3]。这是最灵活的解决方案,尤其适用于复杂场景。 - **示例代码**(处理"0000-00-00"等无效日期): ```java // 自定义反序列化器类 public class CustomDateDeserializer implements ObjectDeserializer { @Override public Date deserialze(DefaultJSONParser parser, Type type, Object fieldName) { String dateStr = parser.parseString(); // 获取JSON中的字符串 if ("0000-00-00".equals(dateStr)) { return null; // 处理无效日期,返回null或默认值 } try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.parse(dateStr); } catch (ParseException e) { throw new JSONException("Date parse error", e); } } @Override public int getFastMatchToken() { return JSONToken.LITERAL_STRING; // 标识处理字符串类型 } } // 注册反序列化 ParserConfig.getGlobalInstance().putDeserializer(Date.class, new CustomDateDeserializer()); String json = "\"0000-00-00\""; Date date = JSON.parseObject(json, Date.class); // 返回null ``` - **说明**:有效解决如"0000-00-00"解析失败的问题,支持高度定制化[^2][^3][^4]。 #### 4. **使用内置特性(如WriteDateUseDateFormat)** - **方法**:通过 `SerializerFeature.WriteDateUseDateFormat` 特性指定日期格式,但主要在序列化使用反序列化通常需结合其他方法[^5]。 - **示例代码**: ```java // 全局设置(影响序列化反序列化JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; String json = "\"2023-10-01\""; Date date = JSON.parseObject(json, Date.class); // 成功反序列化 ``` - **说明**:简单场景有效,但非纯反序列化方案[^5]。 ### 常见问题解决方案 - **问题:反序列化"0000-00-00"失败** **方案**:使用自定义反序列化器(如上示例),在 `deserialze` 方法中处理无效日期逻辑[^2][^4]。 - **问题:版本兼容性问题** **方案**:在fastjson 1.2.38+ 中,优先使用 `DateCodec` 类替代旧方案。检查依赖版本更新代码[^4]。 - **问题:全局格式副作用** **方案**:避免设置 `JSON.DEFFAULT_DATE_FORMAT` 全局属性,改用注解或自定义反序列化器隔离影响[^2][^1]。 ### 最佳实践建议 - **简单场景**:优先使用 `@JSONField` 注解(如 `@JSONField(format = "yyyy-MM-dd")`)。 - **复杂格式或错误处理**:实现自定义 `ObjectDeserializer`。 - **测试**:验证日期格式是否匹配JSON输入,避免 `ParseException`。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值