7

有没有一种简单的方法可以将 spring data couchbase 与没有_class属性的文档一起使用?在沙发上,我的sampledata桶里有这样的东西:

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

现在,有什么方法可以定义从这种文档结构到 Java 对象的映射(注意_class缺少属性并且无法添加),反之亦然,以便我从 spring couchbase 数据中获取所有(或大部分)自动功能?

类似于:如果type字段的值为“mydata”,则使用类 MyData.java。因此,当执行 find 而不是自动添加AND _class = "mydata"到生成的查询时 add AND type = "mydata"

4

4 回答 4

7

Spring Data 通常需要该_class字段知道在反序列化时要实例化回什么。

在 Spring Data Couchbase 中,_class通过覆盖.typeKey()AbsctractCouchbaseDataConfiguration

但是默认情况下它仍然需要一个完全限定的类名

解决这个问题需要更多的工作:

  1. 您需要CouchbaseTypeMapper按照DefaultCouchbaseTypeMapper. 在super(...)构造函数中,您需要提供一个附加参数:一个TypeInformationMapper. 默认实现没有明确提供一个,所以SimpleTypeInformationMapper使用了 a,它是放置 FQN 的那个。
  2. 有一个可配置的替代实现,因此您可以通过以下方式将特定类别名为更短的名称MapConfigurableTypeInformationMapper...
  3. 因此,通过在列表中将 aConfigurableTypeInformationMapper与您想要的特定类的别名 + aSimpleTypeInformationMapper放在它之后(如果您序列化一个您没有为其提供别名的类),您可以实现您的目标。
  4. typeMapper中使用MappingCouchbaseConverter,不幸的是您还需要扩展它(只是为了实例化您的typeMapper而不是默认的。
  5. 一旦你有了它,再次覆盖配置以返回MappingCouchbaseConverter使用你的自定义CouchbaseTypeMappermappingCouchbaseConverter()方法)的自定义实例。
于 2016-08-19T11:04:19.367 回答
5

您可以通过创建自定义注释来实现这一点@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;
    }
}
于 2019-08-12T17:21:19.207 回答
3

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

@Override
public String typeKey() {
    return "type";
}

不幸的是,对于查询派生(n1ql),_class 或 type 仍在使用类名。尝试过 spring couch 2.2.6,它是这里的减号。@Simon,您是否知道某些事情发生了变化,并且支持有可能在下一个版本中拥有自定义 _class/type 值?

于 2017-08-22T06:45:52.520 回答
2

@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 进行注释。

于 2019-03-04T17:39:30.940 回答