spring-bootenumsspring-datadeserializationspring-mongodb

Spring Boot deleted enum value deserialization from the database


We are working with MongoDB.

We have an object with an attribute which is a set of SubscriptionFeature, where the SubscriptionFeature is an enum.

public class Business {
...
private Set<SubscriptionFeature> additionalFeatures;
...
}

Sometimes we delete values from the SubscriptionFeature enum. (ofc we could let them there, but we would like to avoid keeping trash in our code)

But those values remains in the database and during the deserialization we get the well known java.lang.IllegalArgumentException: No enum constant exception. (ofc we get : ) )

To avoid such an error we created a Converter which is able to convert a String to SubscriptionFeature, which will return null if the SubscriptionFeature does not contain the value.

@ReadingConverter
public class StringToSubscriptionFeatureConverter implements Converter<String, SubscriptionFeature> {

  public static final StringToSubscriptionFeatureConverter INSTANCE = new StringToSubscriptionFeatureConverter();

  @Override
  public SubscriptionFeature convert(String source) {
    return SubscriptionFeature.valueOf(source, null);
  }
}

That should be fine, well not 100%. Because the additionalFeatures field into the Business class in a set, which means that this attitude leads to null values into it. Which is also not a good approach.

We also tried to create a converter which is able to deal with collections, but that was called for every single enums, not just for the SubscriptionFeature enum, which is ofc unacceptable.

public class SubscriptionFeaturesToListConverter implements Converter<Collection<String>, Set<SubscriptionFeature>> {

  public static final SubscriptionFeaturesToListConverter INSTANCE = new SubscriptionFeaturesToListConverter();

  @Override
  public Set<SubscriptionFeature> convert(Collection<String> source) {
    return SubscriptionFeature.getFeatures(source);
  }
}

Well, we though that maybe we could ensure somehow to skip the null values of a collection during deserialization, but we did not found any solution for that.

Could somebody help us please, maybe there is a solution to avoid null values into collections during deserializations, or maybe there is another attitude which would do the magic :)

Alternative solutions (which we dont like) could also be:

  1. declaring an UNKNOWN value into the SubscriptionFeature enum, then we would not have null values into the set.
  2. we could create a set implementation which would override the add method to avoid adding null values into it.

But we hope that there is a better solution then these.


Solution

  • While we did not found another solution for the mentioned problem, we decided the following:

    1. we created the String to SubscriptionFeature converter, which was mentioned in the question as well:

      @ReadingConverter public class StringToSubscriptionFeatureConverter implements Converter<String, SubscriptionFeature> {

      public static final StringToSubscriptionFeatureConverter INSTANCE = new StringToSubscriptionFeatureConverter();

      @Override public SubscriptionFeature convert(String source) { return SubscriptionFeature.valueOf(source, null); } }

    This converter is able to convert String to SubscriptionFeature by returning null values instead of throwing java.lang.IllegalArgumentException: No enum constant exceptions.

    By this attitutde we are going to get a set which contains nulls into our DAO object.

    1. During the conversion of the DAO to Domain objects with Mapstruct we make sure that the Domain object's set will never ever contain null values.

      protected Set normalizeFeatureList(Set features) { if (features != null) { return features.stream().filter(Objects::nonNull).collect(toSet()); }

      return null; }