Spring Boot CrudRepository.findOne not working as expected

I wrote the following Spring Boot program. Everything works correctly, except for the last line that calls findOne().

I know I am connecting to the CB cluster, since I can see my documents appear there. The exists() method works correctly, so my code is seeing the documents in the bucket. The delete() method works. If I try findOne() for a non-existent document, it works correctly (returns a null). But when I try findOne() for an existing doc the code crashes with a “source not found” error.

This is a simple key-value lookup. FindOne() should not need a backing view or index.

TIA for any ideas.

Chuck

+++++++++++++++++++++

package demo;

import java.util.Arrays;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {
	

	private final static String CRUD_BEAN = "personRepository";

    public static void main(String[] args) {
    	
    	// Run the application and get its handle.
    	ApplicationContext ctx = SpringApplication.run(Application.class, args);

        // Find all the Spring Boot beans.
    	System.out.println("Let's inspect the beans provided by Spring Boot:");
        String[] beanNames = ctx.getBeanDefinitionNames();
        Arrays.sort(beanNames);
        for (String beanName : beanNames) {
            System.out.println(beanName);
        }

        // Get the bean for the Couchbase CRUD repository.
        PersonRepository cb  = (PersonRepository) ctx.getBean(CRUD_BEAN);

        // Make some person records and save them to Couchbase. The save() operation may change the saved object. 
        Person p1 = new Person("001", "chuck", "connell");
        p1 = cb.save(p1);  
        Person p2 = new Person("002", "jane", "smith");
        p2 = cb.save(p2);  
            
        // Test the exists() method.
        System.out.println (cb.exists("002"));  // should be true
        System.out.println (cb.exists("999"));  // should be false

        // Test the delete() method.
        cb.delete("002");
        System.out.println (cb.exists("002"));  // should be false

        // Retrieve a record using plain key/value. Should not need an index or view.
        Person p3 = cb.findOne("001");  // !!!! THIS FAILS.  WHY??? 
        System.out.println (p3.getFirstname());


    }
    
}

+++++++++++++++++++

package demo;

import com.couchbase.client.java.repository.annotation.Id;
import com.couchbase.client.java.repository.annotation.Field;
import org.springframework.data.couchbase.core.mapping.Document;

@Document
public class Person {

    @Id
    private String id;

    @Field ("fname")
    private String firstName;

    @Field ("lname")
    private String lastName;

    public Person(String id, String firstname, String lastname) {
        this.id = id;
        this.firstName = firstname;
        this.lastName = lastname;
    }

    public String getId() {
        return id;
    }

    public String getFirstname() {
        return firstName;
    }

    public String getLastname() {
        return lastName;
    }
}

++++++++++++++++

package demo;

import org.springframework.data.repository.CrudRepository;

public interface PersonRepository extends CrudRepository<Person, String> {
	
	// custom methods here....
	
}

++++++++++++++++++++

package demo;

 
import java.util.Arrays;
import java.util.List;

import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;


@Configuration
@EnableAutoConfiguration
@EnableCouchbaseRepositories

public class Config extends AbstractCouchbaseConfiguration {

    @Override
    protected List<String> getBootstrapHosts() {
        return Arrays.asList("cb1");
    }

    @Override
    protected String getBucketName() {
        return "my-test";
    }

    @Override
    protected String getBucketPassword() {
        return "";
    }
}

+++++++++++++++++++++++++

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<artifactId>spring-boot-starters</artifactId>
		<groupId>org.springframework.boot</groupId>
		<version>1.4.0.BUILD-SNAPSHOT</version>
	</parent>
	<artifactId>spring-boot-starter-data-couchbase</artifactId>
	<name>Spring Boot Data Couchbase Starter</name>
	<description>Starter for using Couchbase document-oriented database and Spring Data
		Couchbase</description>
	<url>http://projects.spring.io/spring-boot/</url>
	<organization>
		<name>Pivotal Software, Inc.</name>
		<url>http://www.spring.io</url>
	</organization>
	<properties>
		<main.basedir>${basedir}/../..</main.basedir>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-couchbase</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.basepom.maven</groupId>
				<artifactId>duplicate-finder-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>duplicate-dependencies</id>
						<phase>validate</phase>
						<goals>
							<goal>check</goal>
						</goals>
						<configuration>
							<ignoredResourcePatterns>
								<ignoredResourcePattern>changelog.txt</ignoredResourcePattern>
							</ignoredResourcePatterns>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Hey! That is weird indeed. Can you provide more details about the exception you’re seeing? (stacktrace)

Maybe you can try to get a Bucket bean from the context (should be only one with the default boot autoconfiguration) and see if doing a bucket.get("001") works as well?

Another way of doing that is by making your repository interface extend CouchbaseRepository instead of CrudRepository, which will give you access to the underlying template through getCouchbaseOperations(). Then from there you can get a reference to the Bucket through getCouchbaseBucket().

Thanks. I will try those ideas. But is my code basically correct – extending the crud interface, then casting the crud bean with that new interface??

Yes it is correct and should work, that’s why I’m interested in knowing more about this exception that you see.
This is a Spring Boot application and you are using the Couchbase starter, right?
Could you maybe share your pom, or at least the dependencies part of it + version properties if any? (doesn’t look like the last snippet is your pom)

The last snippet is indeed my pom. Maybe that’s the problem?? I took it from some sample on the web. If you want to post a better pom, I will swap mine out.

I changed my code to extend CouchbaseRepository, instead of CrudRepository. Same bad behavior.

Yes, Bucket works. I added these two lines, and they correctly print the whole “001” document.

CouchbaseBucket b = ctx.getBean(CouchbaseBucket.class);
System.out.println (b.get("001"));

The pom is that of spring-boot-starter-data-couchbase, which is kind of a module for Spring Boot, to integrate Spring Data Couchbase into your Spring Boot application. You usually would depend on it, not have it as your own pom.xml.

So a very minimal pom should start with something like:

Are you building a Spring Boot application? Please note that Spring Boot integration is only available in Spring Boot 1.4.0 (which is currently only in M3). I would recommend you use http://start.spring.io and choose Spring Boot 1.4 and search for Couchbase then let it build a skeleton project with pom for you.

If you’re not building such an application, then follow the instructions on the main Spring Data project on how to use the BOM. The minimal pom would look like:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

  <!-- REPLACE WITH YOUR OWN group/artifact -->
    <groupId>org.springframework</groupId>
    <artifactId>gs-maven</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>

    <!-- This imports the Spring Data BOM, importing all correct set of dependencies, including Spring Data Couchbase 2.x -->
    <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-releasetrain</artifactId>
            <version>Hopper-SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
    </dependencyManagement>
    
</project>

Yes, I am building Spring Boot. I will use start.spring.io. Thanks very much for your help with this. I really appreciate it.

no problem, start.spring.io should help you greatly in getting started :wink:

I re-create the whole app, starting from the shell made for me by start.spring.io. The POM, main code, and stack trace are below. Same problem. I am starting to suspect that the findOne() method is missing in the spring/boot/couchbase glue??

package com.uptodate.microservice.core;

import java.util.Arrays;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class CouchbaseSpringbootSampleApplication {

	public static void main(String[] args) {

		ApplicationContext ctx = SpringApplication.run(CouchbaseSpringbootSampleApplication.class, args);
	
	      // Find all the Spring Boot beans.
	    	System.out.println("Let's inspect the beans provided by Spring Boot:");
	        String[] beanNames = ctx.getBeanDefinitionNames();
	        Arrays.sort(beanNames);
	        for (String beanName : beanNames) {
	            System.out.println(beanName);
	        }

	        // Get the bean for the Couchbase repository.
	        PersonRepository cb  =  ctx.getBean(PersonRepository.class);

	        // Make some person records and save them to Couchbase. The save() operation may change the saved object. 
	        Person p1 = new Person("003", "chuck", "connell");
	        p1 = cb.save(p1);  
	        Person p2 = new Person("004", "jane", "smith");
	        p2 = cb.save(p2);  
	            
	        // Test the exists() method.
	        System.out.println (cb.exists("004"));  // should be true
	        System.out.println (cb.exists("999"));  // should be false

	        // Test the delete() method.
	        cb.delete("004");
	        System.out.println (cb.exists("004"));  // should be false

	        // Retrieve a record using plain key/value. Should not need an index or view.
	        Person p3 = cb.findOne("003");  // !!!! THIS FAILS.  WHY??? 
	        System.out.println (p3.getFirstname());

	
	}
}

+++++++++++++++++++++++++++++++++++++++++++++++++++++

CouchbaseSpringbootSampleApplication [Java Application]	
	com.uptodate.microservice.core.CouchbaseSpringbootSampleApplication at localhost:53677	
		Thread [main] (Suspended (exception MappingException))	
			$Proxy60.findOne(Serializable) line: not available	
			CouchbaseSpringbootSampleApplication.main(String[]) line: 42	
		Daemon Thread [cb-computations-1] (Running)	
		Daemon Thread [Thread-1] (Running)	
		Daemon Thread [SimplePauseDetectorThread_0] (Running)	
		Daemon Thread [SimplePauseDetectorThread_1] (Running)	
		Daemon Thread [SimplePauseDetectorThread_2] (Running)	
		Daemon Thread [cb-computations-2] (Running)	
		Daemon Thread [RxCachedWorkerPoolEvictor-1] (Running)	
		Daemon Thread [RxComputationThreadPool-1] (Running)	
		Daemon Thread [RxComputationThreadPool-2] (Running)	
		Daemon Thread [cb-computations-3] (Running)	
		Daemon Thread [cb-computations-4] (Running)	
		Daemon Thread [cb-core-3-1] (Running)	
		Daemon Thread [cb-core-3-2] (Running)	
		Daemon Thread [cb-computations-5] (Running)	
		Daemon Thread [cb-computations-6] (Running)	
		Daemon Thread [cb-computations-7] (Running)	
		Daemon Thread [cb-io-1-1] (Running)	
		Daemon Thread [threadDeathWatcher-4-1] (Running)	
		Daemon Thread [cb-computations-8] (Running)	
		Daemon Thread [cb-io-1-2] (Running)	
		Daemon Thread [cb-io-1-4] (Running)	
		Daemon Thread [cb-io-1-3] (Running)	
	C:\Program Files\Java\jdk1.8.0_91\bin\javaw.exe (Jun 28, 2016, 3:42:15 PM)	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.uptodate.microservice.core</groupId>
	<artifactId>couchbase-springboot-sample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>couchbase-springboot-sample</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.0.M3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-couchbase</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	
	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>

</project>

I was able to make it work with your pom and main class, with a few adjustments:

  1. I reused your Person and PersonRepository classes, but not the Config class.
  2. Instead for configuration, I just used a application.properties file in the main/resources
  3. This file is picked up by Spring Boot to autoconfigure, it just needs the following entry: spring.couchbase.bootstrap-hosts=127.0.0.1 (or replace IP with a valid couchbase node IP)
  4. I moved the PersonRepository in the same package as the main class
  5. I had an error with the Person class, where I had to change the constructor’s signature to this:
public Person(String id, String firstName, String lastName) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
}

It was otherwise complaining that it couldn’t find a proper constructor, because the parameter’s name didn’t match the attributes case…

In retrospect that was probably your main problem. See this SO answer: http://stackoverflow.com/questions/13832188/persistenceconstructor-argument-variable-name-doesnt-match-instance-variable-na/13834796#13834796

Yes! The Person class constructor was the problem. That change alone did the trick. I will also use application.properties as you said. Thanks!

1 Like

Sorry for bringing this thread back to life, but as a lot of people still come to this page looking for answers, I would like to add a more recent tutorial showing how Spring Data works with Couchbase:

https://blog.couchbase.com/couchbase-spring-boot-spring-data/

2 Likes