2017-02-01 4 views
0

Привет всем У меня возникли проблемы с добавлением простого пользовательского запроса с использованием шаблона couchbase в Spring Data Couchbase.Spring Data Couchbase custom repository method

Repository интерфейсы:

@RepositoryRestResource 
public interface EmployeeRepository extends CouchbasePagingAndSortingRepository<Employee, String>, EmployeeCustomRepository { 
} 

public interface EmployeeCustomRepository { 
    List<Employee> customMethod(String firstName, String lastName); 
} 

Реализация

public class EmployeeRepositoryImpl implements EmployeeCustomRepository, InitializingBean { 
    @Autowired 
    private RepositoryOperationsMapping templateProvider; 
    private CouchbaseOperations template; 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     template = templateProvider.resolve(EmployeeRepository.class, Employee.class); 
    } 

    @Override 
    public List<Employee> customMethod(String firstName, String lastName) { 
     N1qlQuery query = N1qlQuery.parameterized(
       "SELECT * FROM " + template.getCouchbaseBucket().name() + " WHERE firstName = $1 AND lastName = $2", 
       JsonArray.from(firstName, lastName)); 
     return template.findByN1QLProjection(query, Employee.class); 
    } 
} 

Модель

@Data 
@AllArgsConstructor 
@Document 
public class Employee { 
    @Id 
    private String id; 

    @Field 
    private String firstName; 

    @Field 
    private String lastName; 
} 

Основное применение

@SpringBootApplication 
public class SpringDataCouchbaseCustomExampleApplication implements CommandLineRunner { 

    public static void main(String[] args) { 
     SpringApplication.run(SpringDataCouchbaseCustomExampleApplication.class, args); 
    } 

    @Autowired 
    private EmployeeRepository repository; 

    @Override 
    public void run(String... strings) throws Exception { 
     String empId = "1"; 

     Employee employee = repository.findOne(empId); 

     if(employee == null) { 
      employee = new Employee(empId, "Joe", "Smith"); 
      repository.save(employee); 
     } 

     List<Employee> result = repository.customMethod("Joe", "Smith"); 

     System.out.println("correct result:" + result.size()); 


     result = repository.customMethod("Joe", "Wopa"); 
     System.out.println("no result:" + result.size()); 
    } 
} 

Стек трассировки

java.lang.IllegalStateException: Failed to execute CommandLineRunner 
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:784) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:771) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    at com.example.SpringDataCouchbaseCustomExampleApplication.main(SpringDataCouchbaseCustomExampleApplication.java:14) [classes/:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_77] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_77] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_77] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_77] 
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
Caused by: java.lang.RuntimeException: Cannot decode ad-hoc JSON 
    at org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService.decodeFragment(JacksonTranslationService.java:245) ~[spring-data-couchbase-2.1.6.RELEASE.jar:na] 
    at org.springframework.data.couchbase.core.CouchbaseTemplate.findByN1QLProjection(CouchbaseTemplate.java:466) ~[spring-data-couchbase-2.1.6.RELEASE.jar:na] 
    at com.example.EmployeeRepositoryImpl.customMethod(EmployeeRepositoryImpl.java:26) ~[classes/:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_77] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_77] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_77] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_77] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503) ~[spring-data-commons-1.12.6.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:478) ~[spring-data-commons-1.12.6.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460) ~[spring-data-commons-1.12.6.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.12.6.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.data.couchbase.repository.support.ViewPostProcessor$ViewInterceptor.invoke(ViewPostProcessor.java:87) ~[spring-data-couchbase-2.1.6.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] 
    at com.sun.proxy.$Proxy77.customMethod(Unknown Source) ~[na:na] 
    at com.example.SpringDataCouchbaseCustomExampleApplication.run(SpringDataCouchbaseCustomExampleApplication.java:31) [classes/:na] 
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE] 
    ... 11 common frames omitted 
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "default" (class com.example.Employee), not marked as ignorable (3 known properties: "lastName", "id", "firstName"]) 
at [Source: {"default":{"firstName":"Joe","lastName":"Smith","_class":"com.example.Employee"}}; line: 1, column: 83] (through reference chain: com.example.Employee["default"]) 
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1093) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1477) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperties(BeanDeserializerBase.java:1431) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:487) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1198) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:314) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842) ~[jackson-databind-2.8.5.jar:2.8.5] 
    at org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService.decodeFragment(JacksonTranslationService.java:242) ~[spring-data-couchbase-2.1.6.RELEASE.jar:na] 
    ... 33 common frames omitted 

ответ

2

Это связано с сочетанием того, как вы написали ваше утверждение запроса и какой метод используется на шаблоне

На первой ноте, вы пытаетесь при получении Employee с, которые являются полноправными субъектами. Этот findByN1QLProjection был предназначен для другого типа запроса, в котором вы выбираете только несколько полей, например запрос count(*).

Таким образом, вместо этого вы должны использовать findByN1ql. В любом случае, есть проблема: формат, возвращенный N1QL для простейшей (но и самой естественной) формы запросов, не приспособлен для десериализации Джексона.

Во-первых, N1QL переносит каждый результат в объект JSON с одним полем, названным в честь ведра, из которого поступают данные, здесь «по умолчанию»). Это вопрос, который вы видите :(

Во-вторых, для того, чтобы десериализации объект, весна-данных couchbase нуждается в вашей N1QL запрос, чтобы выбрать несколько конкретных вещей, которые SELECT(*) не распространяется: на мета- данные (а именно ID и CAS).

Мы предлагаем N1qlUtils класс, чтобы помочь немного с этим ... Обратите внимание, как section of the doc, которая занимается написанием собственных методов использует N1qlUtils класса на этапе 8, чтобы построить запрос?

Я согласен, что это немного вводит в заблуждение, поскольку он использует метод проецирования, поэтому вам придется немного его адаптировать, чтобы использовать N1qlUtils.createSelectFromForEntity и N1qlUtils. createWhereFilterForEntity. Что-то вроде этого:

// your own WHERE criteria: 
Expression where = x("firstName = $1 and lastName = $2"); 

Statement statement = 
    //this will produce the adequate SELECT..FROM.. clause: 
    N1qlUtils.createSelectFromForEntity(template.getCouchbaseBucket().name()) 
    //use the DSL to continue to the WHERE clause 
    .where(
     //this will produce the adequate WHERE criterias in addition to your own: 
     //(see doc snippet for getting converter and entityInfo) 
     N1qlUtils.createWhereFilterForEntity(where, converter, entityInfo)); 

вы можете создать N1qlQuery из этого заявления (а не строки) и выполнить его с помощью findByN1ql ...

быстрой альтернативой:

Вы могли бы используйте строковый запрос.

Для примера см. this test. Вы можете поместить подобную подпись с несколькими настройками в предложение WHERE в аннотации в вашем интерфейсе EmployeeRepository (там нет необходимости в специальной реализации).

+0

Simon Спасибо за ответ! Теперь он работает. Я думаю, что было бы полезно иметь раздел в справочных документах, который показывает запрос без учета. Я не нашел документы, которые были интуитивно понятны для нового пользователя. Еще раз спасибо за вашу помощь! –

+0

хорошее предложение, открытая проблема [DATACOUCH-280] (https://jira.spring.io/browse/DATACOUCH-280). Не стесняйтесь создавать дополнение к документам в PR (и сопровождающий может всегда повторять его позже) :) –

+0

Удивительное спасибо Саймону. Я посмотрю, смогу ли я добраться до этого в выходные. –