你能阻止 spring-data 持久化超类中声明的字段吗?

Can you prevent spring-data from persisting fields declared in a superclass?

我有一个域对象,它扩展了一个基础 class,其中包含几个私有字段(标有 transient 关键字)。我想阻止 super class 字段被持久化。不幸的是,我无法控制基础 class(它位于第三方库中)。由于第三方库的机制,我也别无选择,只能使用继承。

有没有办法告诉 spring-data 到:

  1. 仅保留子class中声明的字段。

  2. 仅保留已针对该域对象使用 @Field 显式注释的字段?

  3. 忽略标有 transient 关键字的字段?

我已经尝试将 @AccessType(Type.PROPERTY) 与子class 中的@Override 方法一起用于 superclass 中我不想保留和注释的方法那些带有@Transient 的。但是它似乎仍然对 superclass.

中的某些字段使用字段访问

编辑:我想知道是否可以编写一个通用的 Converter 来反射性地找到 subclass 中的字段。但是,我不确定您如何配置 Spring 以将该转换器仅用于 classes 的固定集合。

是的,您可以为 class 编写和使用自定义转换器,甚至可以将不同的字段名称从对象映射到 mongodb 集合,就像这样:

@Configuration
public class MongoConfig extends AbstractMongoConfiguration {
    private final List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();

    public CustomConversions customConversions() {
        converters.add(new YourCustomConverter());
        return new CustomConversions(converters);
    }
}

和 YourCustomConverter class:

@WritingConverter 
public class CandidateConverter implements Converter<DBObject, YourClass> {

    @Override
    public DBObject convert(YourClass object) {
        DBObject dbo = new BasicDBObject();
        dbo.put("_id", object.get_id);
        dbo.put("iAmNotSomeField", object.getSomeField);
        return dbo;
    }
}

对于子对象字段,您需要创建 DBObject 并将其放在上层 DBObject 中。同样,如果你愿意,你也可以编写一个 readingConverter。您可以在第 6.3.6

节中找到更多信息 here

更新:

对于我在评论中提出的建议。 Spring 使用 MappingMongoConverter 在 class 中您可以搜索 convertconversionService

@barbakini 感谢您提出使用转换器的建议。我尝试了这个方法,但它似乎比预期的要复杂一些。

我有一个可行的解决方案是使用 AbstractMongoEventListener,它会过滤掉 onBeforeSave() 中不需要的字段:

public class ConfigurableFieldFilteringMongoSaveEventListener extends AbstractMongoEventListener<Object> {

  private final Map<Class<?>, Collection<String>> allowedFieldsByClass;

  public ConfigurableFieldFilteringMongoSaveEventListener(Map<Class<?>, Collection<String>> allowedFieldsByClass) {
    this.allowedFieldsByClass = allowedFieldsByClass;
  }

  @Override
  public void onBeforeSave(BeforeSaveEvent<Object> event) {
    super.onBeforeSave(event);
    final Object domainObject = event.getSource();
    final Collection<String> allowedFields = allowedFieldsByClass.get(domainObject.getClass());
    if (allowedFields == null) {
      return;
    }

    final DBObject dbObject = event.getDBObject();
    dbObject.keySet().retainAll(allowedFields);
  }
}