Using TreeSet causes serialization exception java.io.NotSerializableException

Keywords: Redis Hibernate Java

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.

Posted by flameche on Fri, 18 Oct 2019 10:26:20 -0700