Using TreeSet causes serialization exception
- Problem Description: sort the second level classifications under the first level classification according to the order field (Integer type). At that time, a TreeSet was made and a user-defined Comparator was passed. It was OK to run locally, and the sorting was arranged. It also passed the test environment. As a result, once the thing came online, it reported a serialization exception, and the online environment was cached. Check the data and say that TreeSet has a bug that can't be serialized. It's immediately depressed.
- The exception information is as follows
- Scene description
The JavaBean s corresponding to the following requirements are simulated as follows:
public class ProductCategory implements Serializable { private String id; private String name; private Integer order; private Set<ProductCategory> children = new HashSet<>(); }
Omit getter,setter methods, hibernate for online environment, and previous JavaBean s, which have been used for a long time and dare not be changed. The subcategory corresponds to a HashSet(), which is unordered. Now we need to sort the children subcategory. The simulation test is as follows:
@Test public void contextLoads() { ProductCategory productCategory = new ProductCategory(); // Create 4 subclass objects ProductCategory children1 = new ProductCategory(); ProductCategory children2 = new ProductCategory(); ProductCategory children3 = new ProductCategory(); ProductCategory children4 = new ProductCategory(); // ID children1.setId(UUID.randomUUID().toString()); children2.setId(UUID.randomUUID().toString()); children3.setId(UUID.randomUUID().toString()); children4.setId(UUID.randomUUID().toString()); // name children1.setName(UUID.randomUUID().toString()); children2.setName(UUID.randomUUID().toString()); children3.setName(UUID.randomUUID().toString()); children4.setName(UUID.randomUUID().toString()); // order sort field children1.setOrder(10); children2.setOrder(8); children3.setOrder(9); children4.setOrder(12); // Pass a TreeSet to replace the HashSet, and customize a Comparator to compare through the order field (for self Baidu, which is not familiar with the Comparator) productCategory1.setChildren(new TreeSet<>(Comparator.comparingInt(o -> o.getOrder() == null ? 0 : o.getOrder()))); // All added to the HashSet productCategory.getChildren().add(children1); productCategory.getChildren().add(children2); productCategory.getChildren().add(children3); productCategory.getChildren().add(children4); //////////////////////////////////////// // Here, the children have been arranged according to the order (8, 9, 10, 12), so the printed results will not be put. You can debug and view them by yourself. //////////////////////////////////////// // Simulate online cache and save a copy of redis (the result is reported as java.io.NotSerializableException in this step) redisTemplate.opsForValue().set("productcategory", productCategory.getChildren()); }
- Solution
// Still use the original HashSet productCategory2.getChildren().add(children1); productCategory2.getChildren().add(children2); productCategory2.getChildren().add(children3); productCategory2.getChildren().add(children4); // Convert HastSet to List List<ProductCategory> list = new ArrayList<>(productCategory1.getChildren()); // sort Collections.sort(list, (Comparator.comparingInt(o -> (o.getOrder() == null ? 0 : o.getOrder())))); // Turn it into a LinkedHashSet and plug it back to ensure order. productCategory1.setChildren(new LinkedHashSet<>(list)); // Simulate the online cache and save a copy of redis (it can also be serialized normally here) redisTemplate.opsForValue().set("productcategory", productCategory.getChildren());
The default sorting of hashsets is based on HashCode. Without affecting the business, you can also override the hashCode() method or implement the Comparable interface to override the compareTo method.