Spring #EnableCaching with #Inject/#Autowired issue - spring

I found an issue when using #EnableCaching annotation together with #Inject/#Autowired in #Configuration class:
Simple example to reproduce:
Configuration class:
#Configuration
#EnableCaching
public class CacheConfig {
#Inject
private DataSource dataSource;
#Bean
public CacheManager cacheManager(){
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("books")));
return cacheManager;
}
#Configuration
static class DevProfileConfig {
#Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
EmbeddedDatabaseFactory factory = new EmbeddedDatabaseFactory();
factory.setDatabaseType(EmbeddedDatabaseType.HSQL);
return factory.getDatabase();
}
}
}
Application context launcher:
public class CacheConfigLauncher {
public static void main(String args[]){
ApplicationContext springAppContext = new AnnotationConfigApplicationContext(CacheConfig.class);
}
}
Error:
Caused by:
org.springframework.beans.factory.BeanDefinitionStoreException:
Factory method [public org.springframework.cache.CacheManager
spring.samples.config.CacheConfig.cacheManager()] threw exception;
nested exception is java.lang.IllegalArgumentException: Object of
class [null] must be an instance of interface
org.springframework.beans.factory.config.ConfigurableBeanFactory at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at
org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:573)
... 76 more
Caused by: java.lang.IllegalArgumentException: Object of class [null]
must be an instance of interface
org.springframework.beans.factory.config.ConfigurableBeanFactory at
org.springframework.util.Assert.isInstanceOf(Assert.java:339) at
org.springframework.util.Assert.isInstanceOf(Assert.java:319) at
org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.getBeanFactory(ConfigurationClassEnhancer.java:414)
at
org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:289)
at
spring.samples.config.CacheConfig$$EnhancerByCGLIB$$f6ceccea.cacheManager()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:491) at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 77 more
However if you comment out either #Inject'ed field or #EnableCaching annotation configuration will be bootstraped without errors!!!
It seams like a bug for me. Have someone faced the same issue or probably I'm missing smth?
Thank you,
Oleg

Issue has been fixed in Spring v4.0.0.M2!

Related

SpringBootTest, Testcontainers, container start up - Mapped port can only be obtained after the container is started

I am using docker/testcontainers to run a postgresql db for testing. I have effectively done this for unit testing that is just testing the database access. However, I have now brought springboot testing into the mix so I can test with an embedded web service and I am having problems.
The issue seems to be that the dataSource bean is being requested before the container starts.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/myproject/integrationtests/IntegrationDataService.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: Mapped port can only be obtained after the container is started
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: Mapped port can only be obtained after the container is started
Caused by: java.lang.IllegalStateException: Mapped port can only be obtained after the container is started
Here is my SpringBootTest:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = {IntegrationDataService.class, TestApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringBootTestControllerTesterIT
{
#Autowired
private MyController myController;
#LocalServerPort
private int port;
#Autowired
private TestRestTemplate restTemplate;
#Test
public void testRestControllerHello()
{
String url = "http://localhost:" + port + "/mycontroller/hello";
ResponseEntity<String> result =
restTemplate.getForEntity(url, String.class);
assertEquals(result.getStatusCode(), HttpStatus.OK);
assertEquals(result.getBody(), "hello");
}
}
Here is my spring boot application referenced from the test:
#SpringBootApplication
public class TestApplication
{
public static void main(String[] args)
{
SpringApplication.run(TestApplication.class, args);
}
}
Here is the IntegrationDataService class which is intended to startup the container and provide the sessionfactory/datasource for everything else
#Testcontainers
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#EnableTransactionManagement
#Configuration
public class IntegrationDataService
{
#Container
public static PostgreSQLContainer postgreSQLContainer = (PostgreSQLContainer) new PostgreSQLContainer("postgres:9.6")
.withDatabaseName("test")
.withUsername("sa")
.withPassword("sa")
.withInitScript("db/postgresql/schema.sql");
#Bean
public Properties hibernateProperties()
{
Properties hibernateProp = new Properties();
hibernateProp.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
hibernateProp.put("hibernate.format_sql", true);
hibernateProp.put("hibernate.use_sql_comments", true);
// hibernateProp.put("hibernate.show_sql", true);
hibernateProp.put("hibernate.max_fetch_depth", 3);
hibernateProp.put("hibernate.jdbc.batch_size", 10);
hibernateProp.put("hibernate.jdbc.fetch_size", 50);
hibernateProp.put("hibernate.id.new_generator_mappings", false);
// hibernateProp.put("hibernate.hbm2ddl.auto", "create-drop");
// hibernateProp.put("hibernate.jdbc.lob.non_contextual_creation", true);
return hibernateProp;
}
#Bean
public SessionFactory sessionFactory() throws IOException
{
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setHibernateProperties(hibernateProperties());
sessionFactoryBean.setPackagesToScan("com.myproject.model.entities");
sessionFactoryBean.afterPropertiesSet();
return sessionFactoryBean.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() throws IOException
{
return new HibernateTransactionManager(sessionFactory());
}
#Bean
public DataSource dataSource()
{
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(postgreSQLContainer.getDriverClassName());
dataSource.setUrl(postgreSQLContainer.getJdbcUrl());
dataSource.setUsername(postgreSQLContainer.getUsername());
dataSource.setPassword(postgreSQLContainer.getPassword());
return dataSource;
}
}
The error occurs on requesting the datasource bean from the sessionFactory from one of the Dao classes before the container starts up.
What the heck am I doing wrong?
Thanks!!!
The reason for your java.lang.IllegalStateException: Mapped port can only be obtained after the container is started exception is that when the Spring Context now gets created during your test with #SpringBootTest it tries to connect to the database on application startup.
As you only launch your PostgreSQL inside your IntegrationDataService class, there is a timing issue as you can't obtain the JDBC URL or create a connection on application startup as this bean is not yet properly created.
In general, you should NOT use any test-related code inside your IntegrationDataService class. Starting/stopping the database should be done inside your test setup.
This ensures to first start the database container, wait until it's up- and running, and only then launch the actual test and create the Spring Context.
I've summarized the required setup mechanism for JUnit 4/5 with Testcontainers and Spring Boot, that help you get the setup right.
In the end, this can look like the following
// JUnit 5 example with Spring Boot >= 2.2.6
#Testcontainers
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class ApplicationIT {
#Container
public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer()
.withPassword("inmemory")
.withUsername("inmemory");
#DynamicPropertySource
static void postgresqlProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
}
#Test
public void contextLoads() {
}
}

After migrating to Spring Boot 2.1.7 RELEASE-initializeBean not working

After migrating spring4.1.7 to spring boot2.1.7 Release.Its showing an error for bean creation while initializing application context.
Error Log
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'localConfig' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:771)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1221)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:307)
... 25 more
ServiceConfiguration Class
#Configuration
#Profile(ContextProfileNames.SERVICE)
#EnableWebMvc
#ComponentScan(basePackages = "com.get.services")
#Import(ControllerConfiguration.class)
public class ServiceConfiguration implements InitializingBean
{
#Autowired
private ApplicationContext context;
#Bean(name = "localConfig")
#DependsOn(BeanNames.CONFIGURATION_FACTORY)
#Scope("singleton")
public LocalDataSourceConfiguration getLocalDataSourceConfiguration() throws XEDecryptionException
{
ConfigurationFactory configurationFactory = (ConfigurationFactory) context
.getBean(BeanNames.CONFIGURATION_FACTORY);
LocalDataSourceConfig localDataSourceConfig = configurationFactory.getLocalDataSourceConfiguration();
LocalDataSourceConfiguration localDataSourceConfiguration = new LocalDataSourceConfiguration(
localDataSourceConfig.isMsSqlConfigured(), localDataSourceConfig.isSybaseConfigured(),
localDataSourceConfig.getServiceConfigurationMode(), getLocalDBConfigurationInfo(
localDataSourceConfig.getDbConfigurations().getDbConfigInfo(), configurationFactory));
localDataSourceConfiguration
.setUseRisExamIdAsAccession(Boolean.parseBoolean(localDataSourceConfig.getUseRisExamIdAsAccession()));
localDataSourceConfiguration.setCpacsNameFormat(localDataSourceConfig.getCpacsNameFormat());
localDataSourceConfiguration.setTableCacheRefreshInterval(localDataSourceConfig.getTableCacheRefreshInterval());
localDataSourceConfiguration.setAuthorityMatchingMode(localDataSourceConfig.getAuthorityMatchingMode());
return localDataSourceConfiguration;
}
}
How can i resolve this issue?.did i miss anything?
Added #profile in main class.Issue resolved

Spring Batch Multiple DataSource Session/Entitymanager Closed

I am trying to Pull Records from SQLServer Database to Persist into Mysql Using Spring Boot and Sprin Batch(JpaPagingItemReader and JpaItemWriter).
I have configured Multiple Datasources.
How ever i am facing with below error.
org.springframework.batch.item.ItemStreamException: Error while closing item reader
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close(AbstractItemCountingItemStreamItemReader.java:138)
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:498)
at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:337)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:271)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:957)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:964)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1041)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1017)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:967)
at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:377)
at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:597)
at net.com.org.batch.MyApplication.main(MyApplication.java:15)
Caused by: java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:344)
at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:137)
at org.hibernate.internal.AbstractSharedSessionContract.checkOpenOrWaitingForAutoClose(AbstractSharedSessionContract.java:350)
at org.hibernate.internal.SessionImpl.close(SessionImpl.java:413)
at org.springframework.batch.item.database.JpaPagingItemReader.doClose(JpaPagingItemReader.java:232)
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close(AbstractItemCountingItemStreamItemReader.java:135)
... 17 common frames omitted
20:10:55.875 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'jpaMappingContext': [mySqljobRepository, sqlServerLogsRepository]
Below is my Batch,Step Configuration
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
#Qualifier("mysqlEntityManager")
private LocalContainerEntityManagerFactoryBean mysqlLocalContainerEntityManagerFactoryBean;
#Autowired
#Qualifier("secondarySqlEntityManager")
private LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean;
#Autowired
#Qualifier("mysqlTransactionManager")
private PlatformTransactionManager mySqlplatformTransactionManager;
#Autowired
#Qualifier("secondaryTransactionManager")
private PlatformTransactionManager secondaryTransactionManager;
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Bean
public JpaPagingItemReader itemReader(PlatformTransactionManager secondaryTransactionManager) {
JpaPagingItemReader<SqlServerJobLogs> serverJobLogsJpaPagingItemReader = new JpaPagingItemReader<>();
serverJobLogsJpaPagingItemReader.setMaxItemCount(1000);
serverJobLogsJpaPagingItemReader.setPageSize(100);
serverJobLogsJpaPagingItemReader.setEntityManagerFactory(localContainerEntityManagerFactoryBean.getNativeEntityManagerFactory());
serverJobLogsJpaPagingItemReader.setQueryString("select p from SqlServerJobLogs p");
return serverJobLogsJpaPagingItemReader;
}
#Bean
public ItemProcessor itemProcessor() {
return new DataItemProcessor();
}
#Bean
public ItemWriter itemWriter(PlatformTransactionManager mySqlplatformTransactionManager) {
DataWriter dataWriter = new DataWriter();
return dataWriter;
}
#Bean
public Step step() {
return stepBuilderFactory.get("myJob").chunk(100).reader(itemReader(secondaryTransactionManager)).processor(itemProcessor()).writer(itemWriter(mySqlplatformTransactionManager)).build();
}
#Bean(name = "myJob")
public Job myJob() throws Exception {
return jobBuilderFactory.get("myJob").start(step()).build();
}
#Bean
public ResourcelessTransactionManager resourcelessTransactionManager(){
return new ResourcelessTransactionManager();
}
#Bean
public JobRepository jobRepository() throws Exception{
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(resourcelessTransactionManager());
return mapJobRepositoryFactoryBean.getObject();
}
#Bean
public SimpleJobLauncher jobLauncher() throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository());
return simpleJobLauncher;
}
I have Tried to Configure BatchConfigurer.But No luck.
Please let me know if i need to configure anything else apart from the above mentioned details
Thanks in Advance
I would like to answer the question.
A big thanks to #MahmoudBenHassine
Providing a custom transaction manager by overriding
DefaultBatchConfigurer#getTransactionManager works only with Spring
Batch v4.1+ as said in comments. We need to use Spring Boot v2.1 to
have Spring Batch 4.1

Spring Data: inject 2 repositories with same name but in 2 different packages

Context
I want to use in the same Spring context two different databases that have entities that share the same name, but not the same structure. I rely on Spring Data MongoDB and JPA/JDBC. I have two packages, containing among others the following files:
com.bar.entity
Car.class
com.bar.repository
CarRepository.class
RepoBarMarker.class
com.bar.config
MongoConfiguration.class
com.foo.entity
Car.class
com.foo.repository
CarRepository.class
RepoFooMarker.class
com.foo.config
JPAConfiguration.class
SpecEntityManagerFactory.class
The content of each Car.class is different, I cannot reuse them. bar uses Spring-Mongo and foo uses Spring-JPA, and repositories are initialised via #EnableMongoRepositories and #EnableJpaRepositories annotations. When in one of my application component I try to access the foo version of the repository:
#Resource
private com.foo.repository.CarRepository carRepository;
I have the following exception when the class containing the #Resource field is created:
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'carRepository' must be of type [com.foo.repository.CarRepository], but was actually of type [com.sun.proxy.$Proxy31]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:374)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:446)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:420)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:545)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:155)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:305)
... 26 more
It appears that Spring tries to convert a bar repository to a foo repository, instead of creating a new bean, as in the same stack I also have the following exception:
Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy31 implementing com.bar.repository.CarRepository,org.springframework.data.repository.Repository,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.foo.repository.CarRepository]: no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:267)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:93)
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:64)
... 35 more
If I try instead to autowire the repository:
#Autowire
private com.foo.repository.CarRepository carRepository;
I get the following exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.foo.CarRepository com.shell.ShellApp.carRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.foo.CarRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:509)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:290)
... 26 more
Spring-data configuration
In foo (JPA) package, JPAConfigration.class:
#Configuration
#EnableJpaRepositories(basePackageClasses = RepoFooMarker.class)
public class JPAConfiguration {
#Autowired
public DataSource dataSource;
#Autowired
public EntityManagerFactory entityManagerFactory;
#Bean
public EntityManager entityManager(final EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
#Bean
public Session session(final EntityManager entityManager)
{
return entityManager.unwrap(Session.class);
}
#Bean
public PlatformTransactionManager transactionManager() throws SQLException {
final JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
}
SpecEntityManagerFactory.class:
#Configuration
public class SpecEntityManagerFactory {
#Bean
public EntityManagerFactory entityManagerFactory(final DataSource dataSource) throws SQLException {
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setDatabase(Database.POSTGRESQL);
final LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.foo.entity");
factory.setJpaProperties(getHibernateProperties());
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
private Properties getHibernateProperties()
{
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false");
return hibernateProperties;
}
}
In bar (MongoDB) package, MongoConfiguration.class:
#Configuration
#EnableMongoRepositories(basePackageClasses = RepoBarMarker.class)
public class MongoConfiguration extends AbstractRepoConfig {
#Override
#Bean
public MongoOperations mongoTemplate() {
final MongoClient mongo = this.getMongoClient();
final MongoClientURI mongoUri = this.getMongoClientUri();
final MongoTemplate mongoTemplate = new MongoTemplate(mongo, mongoUri.getDatabase());
mongoTemplate.setReadPreference(ReadPreference.secondaryPreferred());
mongoTemplate.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
return mongoTemplate;
}
}
Question
If I change in foo repository the entity name to CarFoo.class and the repository to CarFooRepository.class, then everything works. But is there away to avoid renaming them and still have a real wiring per type, instead of name (as it is what seems to be done here), for Spring Data repositories?
In your case, you can use
#Repository("fooCarRepository")
on the interface declaration of
com.foo.repository.CarRepository
Although when using Spring Data #Repository is not generally needed on the interface, however in your case you need to supply it. That's because you need to make Spring register the implementation of the bean with a custom name (in this case fooCarRepository) in order to avoid the name collision.

java.lang.IllegalArgumentException: Environment must not be null

I try to setup a basic SolrRepository app and Have this error during ApplicationContext load :
Caused by: java.lang.IllegalArgumentException: Environment must not be null!
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.data.repository.config.RepositoryConfigurationSourceSupport.<init>(RepositoryConfigurationSourceSupport.java:50)
at org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource.<init>(AnnotationRepositoryConfigurationSource.java:74)
at org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport.registerBeanDefinitions(RepositoryBeanDefinitionRegistrarSupport.java:74)
at org.springframework.context.annotation.ConfigurationClassParser.processImport(ConfigurationClassParser.java:394)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:204)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:163)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:138)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:284)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:225)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:630)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 28 more
Here is my ConfigClass :
#Configuration
#PropertySource("classpath:sandbox.properties")
#ComponentScan("sandbox.solr")
#EnableSolrRepositories(basePackages = { "sandbox.solr.repository" }, multicoreSupport = true)
public class StreamingSolrConf {
#Resource
private Environment env;
#Bean
public SolrServer solrServer() {
return new HttpSolrServer(env.getRequiredProperty("solr.server.url"));
}
#Bean
public SolrTemplate solrTemplate() {
return new SolrTemplate(solrServer());
}
}
And my repository interface :
package sandbox.solr.repository;
import org.springframework.data.solr.repository.SolrCrudRepository;
public interface SandboxRepository extends SolrCrudRepository<Document, String> {
}
Can't figure why the Environment is not injected at the right time inside the spring context.
What did I miss ?
Regards.
Just to solve this Question (see comments on original question):
He was using the spring-data-solr-1.2.1.RELEASE with spring-3.2.8.RELEASE either.
Downgrading to spring-data-solr-1.1.3-RELEASE and stay with spring-3.2.8.RELEASE or upgrade to spring-3.2.9.RELEASE to keep spring-data-solr-1.2.1.RELEASE will solve the issue.

Resources