fastjson tostring ref 问题

本文介绍了解决Fastjson在序列化过程中遇到的循环引用问题的方法,并提供了使用SerializerFeature.DisableCircularReferenceDetect的具体示例。

 

 解决方法:SerializerFeature.DisableCircularReferenceDetect

JSON.toJSONString(result,SerializerFeature.DisableCircularReferenceDetect)

 

 

 

/*
 * Project: DemoJava
 * 
 * File Created at 2017年5月23日
 * 
 * Copyright 2016 CMCC Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * curiousby Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license.
 */
package com.curiousby.fastjson;

import java.util.ArrayList;
import java.util.List;

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

/**
 * @Type FastjsonTest.java
 * @Desc 
 * @author baoyou curiousby@163.com
 * @date 2017年5月23日 上午11:01:21
 * @version 
 */
public class FastjsonTest {

     
    
    public static void main(String[] args) {
        FastJsonEntity entity = new FastJsonEntity(1,"baoyou","hello");
        FastResultEnity result = new FastResultEnity();
        result.setLast(entity);
        List<FastJsonEntity> list = new ArrayList<>();
        list.add(entity);
        result.setHistory(list);
        System.out.println(JSON.toJSONString(result));
        System.out.println(JSON.toJSONString(result,SerializerFeature.DisableCircularReferenceDetect));
        
        
    }
}
class FastResultEnity{
    private FastJsonEntity last;
    private List<FastJsonEntity> history;
    public FastJsonEntity getLast() {
        return last;
    }
    public List<FastJsonEntity> getHistory() {
        return history;
    }
    public void setLast(FastJsonEntity last) {
        this.last = last;
    }
    public void setHistory(List<FastJsonEntity> history) {
        this.history = history;
    }
    
}
class FastJsonEntity{
    private int id;
    private String name;
    private String description;
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public String getDescription() {
        return description;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public FastJsonEntity(){}
    public FastJsonEntity(int id, String name, String description) {
        this.id = id;
        this.name = name;
        this.description = description;
    }
    
    
}

/**
 * Revision history
 * -------------------------------------------------------------------------
 * 
 * Date Author Note
 * -------------------------------------------------------------------------
 * 2017年5月23日 baoyou curiousby@163.com creat
 */

 

 

test 

 

{"history":[{"description":"hello","id":1,"name":"baoyou"}],"last":{"$ref":"$.history[0]"}}
{"history":[{"description":"hello","id":1,"name":"baoyou"}],"last":{"description":"hello","id":1,"name":"baoyou"}}

 

 

 

 

 

 

 

 

 

 

 

 

捐助开发者 

在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(支持支付宝和微信 以及扣扣群),没钱捧个人场,谢谢各位。

 

个人主页http://knight-black-bob.iteye.com/



 
 
 谢谢您的赞助,我会做的更好!

<think> 我们正在讨论FastJSON的序列化使用方法和注意事项。根据用户的问题,他想要了解fastjson序列化的相关知识,包括使用方法和注意事项。 根据引用内容,我们可以总结出以下几点: 1. 使用方法: - 在Spring MVC或Spring Boot项目中整合FastJSON,需要添加依赖(如引用[3]所示)。 - 配置FastJSON作为消息转换器(如引用[2]中在RabbitMQ中使用FastJson进行序列化/反序列化)。 - 在Redis缓存中使用FastJSON进行序列化(如引用[4]中提到的,虽然代码示例是RedisTemplate,但我们可以扩展)。 2. 注意事项: - 版本兼容性:不同版本的FastJSON在功能和行为上可能存在差异,升级时需要测试序列化结果(引用[1])。 - 枚举类型的反序列化:需要注意方法的使用(引用[5]提到了通过反射获取方法,但具体到枚举反序列化,FastJSON有特定的处理方式)。 下面我们将详细展开。 ### 一、FastJSON序列化的使用方法 #### 1. 添加依赖 在Maven项目的`pom.xml`中添加FastJSON依赖(注意版本号): ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.39</version> <!-- 请使用最新稳定版本 --> </dependency> ``` #### 2. 在Spring MVC中配置FastJSON 在Spring MVC中,我们可以配置FastJSON作为HTTP消息转换器,这样Controller返回的对象会自动序列化为JSON字符串。 示例配置(基于注解的配置): ```java @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // 创建FastJson消息转换器 FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); // 创建配置类 FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures( SerializerFeature.PrettyFormat, // 格式化输出 SerializerFeature.WriteMapNullValue, // 输出空值字段 SerializerFeature.WriteNullListAsEmpty, // 空集合输出为[]而非null SerializerFeature.WriteNullStringAsEmpty // 空字符串输出为""而非null ); // 设置日期格式 config.setDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置配置 converter.setFastJsonConfig(config); converter.setDefaultCharset(StandardCharsets.UTF_8); // 设置支持的类型 converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); // 将FastJson添加到转换器列表,并放在首位 converters.add(0, converter); } } ``` #### 3. 在Spring Boot中使用FastJSON序列化Redis缓存 在Spring Boot中,如果想要使用FastJSON来序列化Redis中的值,可以自定义RedisTemplate: ```java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 使用FastJson2作为序列化工具 FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class); // 设置Key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); // 设置Value的序列化采用FastJsonRedisSerializer template.setValueSerializer(serializer); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } } ``` #### 4. 在RabbitMQ中使用FastJSON序列化 如引用[2]所示,我们可以配置一个使用FastJSON的消息转换器,用于RabbitMQ的消息序列化和反序列化。 ```java @Configuration public class MyRabbitListenerConfigurer implements RabbitListenerConfigurer { @Bean public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() { DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); // 设置使用FastJson的消息转换器 factory.setMessageConverter(new MappingFastJsonMessageConverter()); return factory; } @Override public void configureRabbitListeners(RabbitListenerEndpointRegistrar rabbitListenerEndpointRegistrar) { rabbitListenerEndpointRegistrar.setMessageHandlerMethodFactory(myHandlerMethodFactory()); } } ``` ### 二、FastJSON序列化的注意事项 1. **版本兼容性**:不同版本的FastJSON(如1.x和2.x)在API和功能上可能存在较大差异。升级版本时,务必进行充分的测试,确保序列化结果符合预期[^1]。例如,FastJSON 2.x完全重构并支持了JDK新版本,性能更高,但部分配置方式与1.x不同。 2. **循环引用问题**:默认情况下,FastJSON会检测循环引用并避免无限递归,但可能导致同一个对象被多次序列化时出现引用标记(如`$ref`)。可以通过`SerializerFeature.DisableCircularReferenceDetect`关闭循环引用检测,但需确保数据无循环引用以避免栈溢出。 3. **日期格式**:FastJSON默认将日期序列化为时间戳(Long类型)。如果需要特定格式,可以通过`FastJsonConfig`设置全局日期格式(如`yyyy-MM-dd HH:mm:ss`),或在具体字段上使用`@JSONField`注解指定格式。 4. **字段过滤**:可以通过`@JSONField`注解控制字段的序列化行为,例如: - `@JSONField(serialize = false)`:不序列化该字段。 - `@JSONField(name = "new_name")`:序列化时使用别名。 - `@JSONField(format = "yyyy-MM-dd")`:指定日期格式。 5. **枚举序列化**:默认情况下,FastJSON序列化枚举使用`name()`方法(即枚举常量名)。若需要自定义,可以在枚举类中实现`toString`方法,或者在枚举字段上使用`@JSONField`指定序列化方式。 6. **反序列化安全**:FastJSON在反序列化时存在一定的安全风险(如反序列化漏洞)。建议: - 使用最新版本(修复已知漏洞)。 - 避免反序列化不可信的JSON字符串。 - 使用`ParserConfig.getGlobalInstance().addAccept("需要反序列化的类的全限定名")`来开启白名单控制(FastJSON 1.2.68+支持)。 7. **特殊字符处理**:FastJSON默认会转义特殊字符(如`<`、`>`等),可通过`SerializerFeature.BrowserCompatible`开启浏览器兼容模式,自动转义更多HTML字符。 8. **性能优化**:FastJSON在序列化时提供多种特性(`SerializerFeature`)以平衡性能与功能。例如: - `SerializerFeature.WriteNonStringValueAsString`:将所有非字符串类型转为字符串(可能影响性能)。 - 在不需要格式化输出时,关闭`SerializerFeature.PrettyFormat`可提升性能。 ### 三、示例:使用FastJSON进行简单对象序列化 ```java import com.alibaba.fastjson2.JSON; public class FastJsonExample { public static void main(String[] args) { User user = new User("John", 30); // 序列化 String jsonString = JSON.toJSONString(user); System.out.println(jsonString); // 输出:{"age":30,"name":"John"} // 反序列化 User parsedUser = JSON.parseObject(jsonString, User.class); System.out.println(parsedUser.getName()); } static class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } // 必须有无参构造方法和getter/setter(或public字段)才能正确反序列化 public User() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } } ``` ### 总结 FastJSON是一个高性能的JSON处理库,使用简单但需注意版本兼容性和安全配置。在整合到Spring、Redis或RabbitMQ时,通过配置相应的转换器即可实现快速集成。同时,根据业务需求合理选择序列化特性,并注意防范安全风险。 §§相关问题§§ 1. 如何解决FastJSON循环引用导致的`$ref`问题? 2. FastJSON如何配置白名单以提高安全性? 3. 如何自定义FastJSON的日期格式? </think> ### FastJSON序列化的使用方法和注意事项 FastJSON是阿里巴巴开源的高性能JSON处理库,广泛应用于Java对象的序列化(对象→JSON)和反序列化(JSON→对象)。以下是详细的使用指南和关键注意事项。 --- #### 一、核心使用方法 ##### 1. **基础序列化** 使用 `JSON.toJSONString()` 将对象转换为JSON字符串: ```java User user = new User("John", 30); String json = JSON.toJSONString(user); // 输出:{"name":"John","age":30} ``` ##### 2. **配置序列化特性** 通过 `SerializerFeature` 控制序列化行为: ```java String json = JSON.toJSONString(user, SerializerFeature.PrettyFormat, // 格式化输出 SerializerFeature.WriteNullStringAsEmpty, // 空字符串转为"" SerializerFeature.WriteMapNullValue // 保留空值字段 ); ``` ##### 3. **整合Spring框架** - **Spring MVC配置**(引用[^3]): ```xml <!-- pom.xml添加依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.39</version> </dependency> ``` ```java // 配置HttpMessageConverter @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); converters.add(converter); } ``` - **RabbitMQ序列化**(引用[^2]): ```java @Bean public MessageConverter fastJsonMessageConverter() { return new MappingFastJsonMessageConverter(); // 替换默认Jackson } ``` - **Redis序列化**(引用[^4]): ```java @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setValueSerializer(new GenericFastJsonRedisSerializer()); // 使用FastJSON template.setConnectionFactory(factory); return template; } ``` ##### 4. **自定义序列化规则** 通过 `@JSONField` 注解控制字段行为: ```java public class User { @JSONField(name = "user_name") // 修改JSON字段名 private String name; @JSONField(serialize = false) // 忽略序列化 private String password; } ``` --- #### 二、关键注意事项 1. **版本兼容性** - 不同版本的FastJSON(如1.x vs 2.x)的API和默认行为可能不同。 - **建议**:升级版本时需全面测试序列化结果,避免字段丢失或格式变化(引用[^1])。 2. **循环引用问题** - 当对象存在循环引用(如A→B→A)时,默认会生成 `"$ref"` 引用标识。 - **解决方法**: ```java JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect); ``` 3. **枚举类型处理** - 默认序列化枚举的 `name()` 值(如 `"RED"`)。 - **自定义序列化**(引用[^5]): ```java public enum Color { @JSONField(name = "1") RED, @JSONField(name = "2") BLUE } ``` 4. **日期格式控制** - 默认输出时间戳(如 `1685097600000`)。 - **指定格式**: ```java @JSONField(format = "yyyy-MM-dd HH:mm:ss") private Date createTime; ``` 5. **安全风险防范** - FastJSON曾曝出反序列化漏洞(如AutoType绕过)。 - **安全实践**: - 使用最新版本(≥1.2.83)。 - 关闭AutoType:`ParserConfig.getGlobalInstance().setAutoTypeSupport(false);` - 添加白名单:`ParserConfig.getGlobalInstance().addAccept("com.example.safe.*");` 6. **性能优化** - 避免频繁创建 `JSONObject`/`JSONArray`,复用对象。 - 关闭不需要的 `SerializerFeature`(如 `PrettyFormat` 会增加CPU开销)。 --- #### 三、常见问题解决 - **字段丢失问题**:检查是否有 `transient` 修饰符或缺失getter方法。 - **中文乱码**:确保序列化时指定UTF-8编码: ```java new SerializeConfig().setPropertyNamingStrategy(PropertyNamingStrategy.CamelCase); ``` - **反序列化失败**:确认JSON字符串与目标类结构匹配,或使用 `@JSONType(ignores = {"unknownField"})` 忽略多余字段。 --- ### 总结 FastJSON的高性能和易用性使其成为Java生态中流行的JSON工具,但需注意版本升级兼容性、安全问题及特殊场景处理(如循环引用)。整合Spring、Redis、RabbitMQ时,通过配置消息转换器可快速替换默认序列化方案(引用[^2][^3][^4])。始终优先使用最新版本并遵循安全最佳实践[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值