CouchbaseRepositoryFactoryBean No Default Constructor error

Hi all,

We are trying to create a Spring Batch app reading from Oracle and writing into Couchbase and are encountering problems creating the ItemWriter object into Couchbase. The error we get is:

java.lang.IllegalStateException: Error processing condition on org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:64)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:102)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator.shouldSkip(ConfigurationClassBeanDefinitionReader.java:436)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:127)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:333)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:678)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:520)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:760)
at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174)
at com.cars.mlvrb.Application.main(Application.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘makeModelDocumentRepository’: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean.()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1109)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1054)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getSingletonFactoryBeanForTypeCheck(AbstractAutowireCapableBeanFactory.java:869)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:796)
at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:544)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:449)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:417)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:411)
at org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration$DevToolsDataSourceCondition.getMatchOutcome(DevToolsDataSourceAutoConfiguration.java:130)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
… 21 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean.()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1102)
… 30 common frames omitted
Caused by: java.lang.NoSuchMethodException: org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean.()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
… 31 common frames omitted

I’ve hunted around for a solution for this error, and the closest I came to an answer was an issue with the document constructor - however, correcting that did not make the problem go away.

To start, here is the gradle config:

dependencies {

compile("com.cars.framework:health-check:1.0")
compile("org.springframework.boot:spring-boot-devtools:1.3.8.RELEASE")
compile("org.springframework.boot:spring-boot-starter-batch")
compile('org.springframework.boot:spring-boot-starter-jdbc')
compile('org.springframework.data:spring-data-couchbase:2.2.0.RELEASE')
compile("com.cars.framework:cars-framework-config:2.1.2-RELEASE")
compile('com.oracle:ojdbc6:11.2.0.3')
compile localGroovy()

}

We have a CouchbaseConfig java class that has been annotated as below:

@EnableCouchbaseRepositories(basePackages = { "com.cars.mlvrb.repository" })
@Configuration
@EnableAutoConfiguration
public class CouchbaseConfig extends AbstractCouchbaseConfiguration {

private static Logger logger = LoggerFactory.getLogger(CouchbaseConfig.class);

@Value("#{'${spring.data.couchbase.bootstrap-hosts}'}")
private String bootstrapHosts;

@Value("#{'${spring.data.couchbase.bucket.name}'}")
private String bucketName;

@Value("#{'${spring.data.couchbase.bucket.password}'}")
private String bucketPassword;

@Override
protected List<String> getBootstrapHosts() {
    String rawPropertyValue = this.bootstrapHosts;

    if (StringUtils.isNotBlank(rawPropertyValue)) {
        StringTokenizer st = new StringTokenizer(rawPropertyValue, ",");
        List<String> returnValue = new ArrayList<>(st.countTokens());

        while (st.hasMoreTokens()) {
            returnValue.add(st.nextToken().trim());
        }

        return returnValue;
    }

    logger.error("Unable to process the bootstrapHosts property. Property value: " + this.bootstrapHosts);
    return Collections.emptyList();
}

@Override
protected String getBucketName() {
    if (StringUtils.isBlank(this.bucketName)) {
        logger.error("Unable to process the bucketName property. Property value: " + this.bucketName);
    }
    return this.bucketName;
}

@Override
protected String getBucketPassword() {
    if (StringUtils.isBlank(this.bucketPassword)) {
        logger.error("Unable to process the bucketPassword property. Property value: " + this.bucketPassword);
    }
    return this.bucketPassword;
}

}

The repository interface is:

package com.cars.mlvrb.repository;

import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.stereotype.Repository;

import com.cars.mlvrb.model.nosql.MakeModelDocument;

@Repository
public interface MakeModelDocumentRepository extends CouchbaseRepository<MakeModelDocument, String> {

}

The document structure is:

@Document
public class MakeModelDocument {
    @Id
    private String key;

    @Field
    private String type;
    
    @Field
    private Long createDateUtc;

    @Field
    private Long vehicleMakeId;

    @Field
    private Long vehicleModelId;
    
    @Field
    private Long vehicleYearId;
    
    public MakeModelDocument() {
    	
    }
    
    public MakeModelDocument(String key, String type, Long createDateUtc, Long vehicleMakeId, Long vehicleModelId, Long vehicleYearId) {
        this.key = key;
        this.type = type;
        this.createDateUtc = createDateUtc;
        this.vehicleMakeId = vehicleMakeId;
        this.vehicleModelId = vehicleModelId;
        this.vehicleYearId = vehicleYearId;
    }

    public String getKey() {
        return this.key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getType() {
        return this.type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Long getCreateDateUtc() {
        return this.createDateUtc;
    }

    public void setCreateDateUtc(Long createDateUtc) {
        this.createDateUtc = createDateUtc;
    }

    public Long getVehicleMakeId() {
		return this.vehicleMakeId;
	}

	public void setVehicleMakeId(Long vehicleMakeId) {
		this.vehicleMakeId = vehicleMakeId;
	}

	public Long getVehicleModelId() {
		return this.vehicleModelId;
	}

	public void setVehicleModelId(Long vehicleModelId) {
		this.vehicleModelId = vehicleModelId;
	}

	public Long getVehicleYearId() {
		return this.vehicleYearId;
	}

	public void setVehicleYearId(Long vehicleYearId) {
		this.vehicleYearId = vehicleYearId;
	}

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("key", this.key).append("type", this.type)
        		.append("createDateUtc", this.createDateUtc).append("vehicleMakeId", this.vehicleMakeId)
        		.append("vehicleModelId", this.vehicleModelId).append("vehicleYearId", this.vehicleYearId).toString();
    }
}

The batch config class:

package com.cars.mlvrb.config;

import static com.cars.mlvrb.constants.Constants.CPO_CAR_QUERY;

import javax.sql.DataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.data.RepositoryItemWriter;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.cars.mlvrb.model.mapper.MakeModelRowMapper;
import com.cars.mlvrb.model.nosql.MakeModelDocument;
import com.cars.mlvrb.model.oracle.MakeModelRecord;
import com.cars.mlvrb.processor.MakeModelItemProcessor;
import com.cars.mlvrb.repository.MakeModelDocumentRepository;

@Configuration
@EnableBatchProcessing
public class ModelListingVehicleReferenceBatchConfig {

    @Autowired
    private MakeModelDocumentRepository repository;
    
    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Autowired
    @Qualifier("oracleDataSource")
    private DataSource dataSource;

    @Bean
    public Job job(@Qualifier("step") Step step) {
        return jobs.get("myJob").start(step).build();
    }

    @Bean
    protected Step step(ItemReader<MakeModelRecord> makeModelReader, ItemProcessor<MakeModelRecord, MakeModelDocument> makeModelItemProcessor, ItemWriter<MakeModelDocument> writer) {
        return steps.get("step")
                .<MakeModelRecord, MakeModelDocument> chunk(10)
                .reader(makeModelReader)
                .processor(makeModelItemProcessor)
                .writer(writer)
                .build();
    }

    @Bean
    protected ItemProcessor<MakeModelRecord, MakeModelDocument> makeModelItemProcessor() {
        return new MakeModelItemProcessor("new", "trucks");
    }

    @Bean
    protected ItemReader<MakeModelRecord> makeModelReader() {
        JdbcCursorItemReader<MakeModelRecord> itemReader = new JdbcCursorItemReader<MakeModelRecord>();
        itemReader.setDataSource(dataSource);
        itemReader.setSql(CPO_CAR_QUERY);
        itemReader.setRowMapper(new MakeModelRowMapper());
        return itemReader;
    }
    
    @Bean
    protected ItemWriter<MakeModelDocument> makeModelWriter() {
		RepositoryItemWriter<MakeModelDocument> writer = new RepositoryItemWriter<>();
		writer.setRepository(repository);
    	writer.setMethodName("save");
    	return writer;
    }
}

Hi @cchong,

I am not familiar with Spring-batch and if the auto-configuration happens-before couchbase configuration or not. Can you try creating a more simpler bean like CouchbaseBucket or CouchbaseTemplate.

Hi @subhashni ,

Thank you for your response. I was able to resolve the problem by downgrading the couchbase dependency to 2.1.7 instead.