0

A month ago, I asked this question. I implemented the selected solution using the following method to register it with Spring Boot (2.7):

@Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> builder.annotationIntrospector(new EmptyAsNullCollectionJacksonAnnotationIntrospector()); 

The result is that nothing is getting serialized properly. It is just blank with maybe an empty array "[]." I've seen this happen when the JsonView is wrong but I don't know how this code could have caused that.

The other problem is that while most things are deserialized properly, the one thing that doesn't work is collections which have members. Instead of those members being deserialized back into their Java objects, they're deserialized as LinkedHashMaps.

Perhaps I'm going about this in the wrong way. Here are the two problems I'm trying to solve:

  1. My front end guys would like to get empty collections instead of nulls. I could fix this problem by just initializing every collection. Easily done but I was hoping for an automated solution so I wouldn't have to remember to do it.

  2. We implemented Envers auditing on several of our tables and turned on modifiedFlags for a couple of them. It seems that when Hibernate gets an empty collection where it originally had a null, it flips the modified flag to true. This then shows up on modification reports as a change where none actually took place. The solution seems to be to ensure that empty collections are converted to nulls before being persisted.

The original question was me trying to solve both these problems in one fell swoop. If there is a better solution to these problems, even individually, I'd like to hear it. If my original idea was the best solution, I need some help getting it to work.

Thanks.

  • Do you have Hibernate configured to use field-based or property-based access for the persistent entities? Also, do you return persistent entities directly from endpoints, or are you using DTOs at the API layer? – E-Riz Mar 07 '23 at 16:48
  • @E-Riz Persistent entities are converted to Json via Spring's ResponseEntity class. I use mostly field-based but some of my classes require property based access. – Occams Stubble Mar 07 '23 at 18:54

1 Answers1

0

Both problems you're trying to solve can be addressed by returning DTOs (or, if you don't like that term, some lightweight POJO) from endpoints instead of the persistent entities themselves.

For example, if your persistent entity is Account, your endpoints (or a component they delegate to) would convert/transform Account objects to AccountDTO (or AccountResponse or whatever you want to call it). AccountDTO is a true POJO with no real logic or persistence mapping in it.

If you do that, it addresses the 2 problems:

  1. It can initialize collections internally, including substituting nulls in setter methods with calls to Collections.emptyList(), etc.
  2. Anything you do to message the DTO into a form you want to return from your endpoints is independent of the persistent entities, so the modified data isn't touched when it shouldn't be.

Here's an example:

public class Order {
    private UUID id;
    // ...more properties...
}

public class AccountDTO {

    private UUID id;
    private Set<Order> orders = new HashSet<>();
    
    public UUID getID() { return id; }
    
    public Set<Order> getOrders() {
        if (orders == null) {
            orders = Collections.emptySet();
        }
        
        return orders;
    }
}

An alternative to that getOrders() implementation would be to override the setter like this:

    public void setOrders(Set<Order> orders) {
        if (orders == null) {
            orders = Collections.emptySet();
        }
        
        this.orders = orders;
    }

Either way, getOrders() will never return null.

You'd use a transformer/converter with a signature something like this to change the persistent entities to the DTO(s):

public class Transformer {
    public AccountDTO toDTO(Account entity) {
        // There are several ways to implement this transformation
    }
}
E-Riz
  • 31,431
  • 9
  • 97
  • 134
  • That's pretty much what I do now. I create a separate set of getters and setters for the collections in my persistent objects. The JSon serializer works with one set and Hibernate works with the other. I'm trying to get myself out of that maintenance problem by getting the serializer to do the work for me. – Occams Stubble Mar 07 '23 at 22:21