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;
}
}