Spring Boot 从数据库中删除枚举值的反序列化

huangapple go评论76阅读模式
英文:

Spring Boot deleted enum value deserialization from the database

问题

我们正在使用MongoDB。

我们有一个对象,其中有一个属性是SubscriptionFeature的集合,而SubscriptionFeature是一个枚举类型。

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

有时,我们会从SubscriptionFeature枚举中删除值(当然,我们也可以让它们保留在那里,但我们希望避免在我们的代码中保留垃圾)。

但是,这些值仍然保留在数据库中,而在反序列化期间,我们会收到众所周知的java.lang.IllegalArgumentException: No enum constant异常(当然,我们会收到 Spring Boot 从数据库中删除枚举值的反序列化 )。

为了避免这种错误,我们创建了一个转换器,它能够将String转换为SubscriptionFeature,如果SubscriptionFeature不包含该值,则返回null。

@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);
    }
}

这应该可以,但不是100%完美。因为Business类中的additionalFeatures字段是一个集合,这意味着这种方法会导致其中包含null值,这也不是一个好的做法。

我们还尝试创建了一个能够处理集合的转换器,但这会被应用于每个单独的枚举值,而不仅仅是SubscriptionFeature枚举值,这当然是不可接受的。

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);
    }
}

我们曾考虑过,也许我们可以确保在反序列化期间跳过集合中的null值,但我们没有找到任何解决方案。

是否有人能够帮助我们,也许有一种方法可以在反序列化期间避免集合中的null值,或者也许有另一种方法可以奏效 Spring Boot 从数据库中删除枚举值的反序列化

替代方案(我们不喜欢的)可能包括:

  1. 在SubscriptionFeature枚举中声明一个UNKNOWN值,然后我们就不会在集合中有null值。
  2. 我们可以创建一个集合实现,重写add方法以避免添加null值。

但我们希望有一个比这些更好的解决方案。

英文:

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&lt;SubscriptionFeature&gt; 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&lt;String, SubscriptionFeature&gt; {

  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&lt;Collection&lt;String&gt;, Set&lt;SubscriptionFeature&gt;&gt; {

  public static final SubscriptionFeaturesToListConverter INSTANCE = new SubscriptionFeaturesToListConverter();

  @Override
  public Set&lt;SubscriptionFeature&gt; convert(Collection&lt;String&gt; 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 Spring Boot 从数据库中删除枚举值的反序列化

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.

答案1

得分: 0

我们虽然没有找到另一种解决方案来解决提到的问题,但我们决定采取以下措施:

  1. 我们创建了一个名为StringToSubscriptionFeatureConverter的字符串到SubscriptionFeature的转换器,这也在问题中提到:
@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);
  }
}

这个转换器能够将字符串转换为SubscriptionFeature,并在遇到无法找到的枚举常量时返回null值,而不是抛出java.lang.IllegalArgumentException:No enum constant异常。

通过这种方式,我们将获得一个包含null值的集合,该集合将存储在我们的DAO对象中。

  1. 在使用Mapstruct将DAO转换为领域对象的过程中,我们确保领域对象的集合永远不会包含null值。
protected Set<SubscriptionFeature> normalizeFeatureList(Set<SubscriptionFeature> features) {
  if (features != null) {
    return features.stream().filter(Objects::nonNull).collect(toSet());
  }

  return null;
}
英文:

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<SubscriptionFeature> normalizeFeatureList(Set<SubscriptionFeature> features) {
    if (features != null) {
    return features.stream().filter(Objects::nonNull).collect(toSet());
    }

    return null;
    }

huangapple
  • 本文由 发表于 2023年7月7日 07:01:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76632995.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定