hessian序列化的坑

之前使用dubbo服务的过程中发生了一个关于hessian序列化引起的bug,有点意思,记录一下。

hessian序列化Collections.emptyList()时,会转换成ArrayList(),并且同一对象内会共用同一个ArrayList对象,例如:

ProductDTO.java

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 商品属性表DTO
*/
List<ProductAttributeDTO> productAttributeDTOs = Collections.emptyList();
/**
* 配件DTO
*/
List<PartsDTO> partsDTOs = Collections.emptyList();
/**
* 车型DTO
*/
List<CarTypeDTO> carTypeDTOs = Collections.emptyList();

以下代码:

1
2
3
4
5
6
7
8
9
List<ProductAttributeNameDTO> productAttributeNameDTOs = queryProductAttributeNamesByCategoryId(topCategoryId);
List<ProductAttributeDTO> productAttributeDTOs = productDTO.getProductAttributeDTOs();// @1
Set<Integer> attrNameIds = Sets2.transform(productAttributeDTOs, ProductAttributeDTO::getAttrNameId);
productAttributeNameDTOs.stream()
.filter(v -> !attrNameIds.contains(v.getAttrNameId()))
.forEach(v -> {
ProductAttributeDTO productAttributeDTO = ProductDTOTransformers.convert(v, new ProductAttributeDTO());
productAttributeDTOs.add(productAttributeDTO);// @2
});

以上代码的productDTO是从dubbo服务获取的,虽然ProductDTO的默认值是Collections.emptyList()(代码@1),但由于Collections#EMPTY_LIST并无实现序列化接口,hessian在序列化的过程中将其转换成ArrayList,并且同一对象内的Collections.emptyList()都会共用同一个ArrayList对象,造成执行@2操作的时候,partsDTOscarTypeDTOs同样持有相同的ArrayList对象(java是伪泛型,运行期会抹除),所以当打开debugger或将productDTO序列化成JSON时会发现productAttributeDTOs, partsDTOscarTypeDTOs的内容是一样的。