如何在没有_class属性的情况下使用带有couchbase的spring数据

时间:2016-08-09 09:57:53

标签: java spring-data couchbase spring-data-couchbase

是否有一种简单的方法可以将spring数据沙发基础与没有_class属性的文档一起使用? 在沙发基地,我在sampledata桶中有这样的东西:

{
  "username" : "alice", 
  "created" : 1473292800000,
  "data" : { "a": 1, "b" : "2"},
  "type" : "mydata"
}

现在,有没有办法定义从这个文档结构到Java对象的映射(请注意_class属性缺失且无法添加),反之亦然,以便我获得所有(或大多数)自动化功能从spring couchbase数据?

像: 如果type字段的值为“mydata”,则使用类MyData.java。 因此,执行查找时,不会自动将AND _class = "mydata"添加到生成的查询添加AND type = "mydata"

4 个答案:

答案 0 :(得分:5)

Spring数据通常需要_class字段来知道反序列化时要实例化的内容。

通过覆盖_class中的typeKey()方法,Spring Data Couchbase使用与AbsctractCouchbaseDataConfiguration不同的字段名称相当容易。

但它仍然会在默认情况下期望完全限定的类名

绕过这将需要更多的工作:

  1. 您需要按照CouchbaseTypeMapper的模型实施自己的DefaultCouchbaseTypeMapper。在super(...)构造函数中,您需要提供一个额外的参数: TypeInformationMapper 的列表。默认实现没有明确提供一个,因此使用SimpleTypeInformationMapper,这是放置FQN的那个。
  2. 有一个可配置的替代实现,因此您可以通过Map将特定类别名为较短的名称:ConfigurableTypeInformationMapper ...
  3. 因此,在列表中添加一个ConfigurableTypeInformationMapper,其中包含您想要的特定类别的别名+ SimpleTypeInformationMapper(对于这种情况,您序列化了一个您没有为其提供别名的类别),你可以实现你的目标。
  4. typeMapper用于MappingCouchbaseConverter,您还需要进行扩展(仅用于实例化typeMapper而不是默认值。
  5. 完成后,再次覆盖配置以返回使用自定义MappingCouchbaseConverterCouchbaseTypeMapper方法)的自定义mappingCouchbaseConverter()实例。

答案 1 :(得分:2)

例如,您可以实现通过创建自定义注释@DocumentType

@DocumentType("billing")
@Document
public class BillingRecordDocument {
    String name;
    // ...
}

文档外观如下:

{
    "type" : "billing"
    "name" : "..."
}

只需创建以下类: 创建自定义AbstractReactiveCouchbaseConfigurationAbstractCouchbaseConfiguration(取决于您使用的瓦里安)

@Configuration
@EnableReactiveCouchbaseRepositories
public class CustomReactiveCouchbaseConfiguration extends AbstractReactiveCouchbaseConfiguration {
     // implement abstract methods
     // and configure custom mapping convereter
    @Bean(name = BeanNames.COUCHBASE_MAPPING_CONVERTER)
    public MappingCouchbaseConverter mappingCouchbaseConverter() throws Exception {
        MappingCouchbaseConverter converter = new CustomMappingCouchbaseConverter(couchbaseMappingContext(), typeKey());
        converter.setCustomConversions(customConversions());
        return converter;
    }

    @Override
    public String typeKey() {
        return "type"; // this will owerride '_class'
    }
}

创建自定义MappingCouchbaseConverter

public class CustomMappingCouchbaseConverter extends MappingCouchbaseConverter {

    public CustomMappingCouchbaseConverter(final MappingContext<? extends CouchbasePersistentEntity<?>,
            CouchbasePersistentProperty> mappingContext, final String typeKey) {
        super(mappingContext, typeKey);
        this.typeMapper = new TypeBasedCouchbaseTypeMapper(typeKey);
    }
}

和自定义注释@DocumentType

@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface DocumentType {

    String value();

}

然后创建TypeAwareTypeInformationMapper,它将仅检查实体是否被@DocumentType注释,如果是,则使用该注释中的值,否则使用默认值(标准类名)

public class TypeAwareTypeInformationMapper extends SimpleTypeInformationMapper {

    @Override
    public Alias createAliasFor(TypeInformation<?> type) {
        DocumentType[] documentType = type.getType().getAnnotationsByType(DocumentType.class);

        if (documentType.length == 1) {
            return Alias.of(documentType[0].value());
        }

        return super.createAliasFor(type);
    }
}

然后将其注册如下

public class TypeBasedCouchbaseTypeMapper extends DefaultTypeMapper<CouchbaseDocument> implements CouchbaseTypeMapper {

    private final String typeKey;

    public TypeBasedCouchbaseTypeMapper(final String typeKey) {
        super(new DefaultCouchbaseTypeMapper.CouchbaseDocumentTypeAliasAccessor(typeKey),
              Collections.singletonList(new TypeAwareTypeInformationMapper()));
        this.typeKey = typeKey;
    }

    @Override
    public String getTypeKey() {
        return typeKey;
    }
}

答案 2 :(得分:1)

在您的couchbase配置类中,您只需要:

composer.navigationBar.barTintColor

不幸的是,对于查询派生(n1ql),_class或类型仍在使用类名.Tried spring couch 2.2.6及其在此处的减号。 @Simon,您是否知道某些内容已发生变化,并支持在下一个版本中拥有自定义_class / type值?

答案 3 :(得分:1)

@SimonBasle 在类N1qlUtils和方法createWhereFilterForEntity中,我们可以访问CouchbaseConverter。在线:

String typeValue = entityInformation.getJavaType().getName();

当我们要避免使用类名时,为什么不使用转换器中的typeMapper获取实体的名称呢?否则,您必须注释存储库中的每个方法,如下所示:

@Query("#{#n1ql.selectEntity} WHERE `type`='airport' AND airportname = $1")
List<Airport> findAirportByAirportname(String airportName);

如果createWhereFilterForEntity使用了CouchbaseConverter,我们可以避免使用@Query进行注释。