I am new to Spring, thank you for your help
My JUnit test class works very well :
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import junit.framework.TestCase;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/Spring-Test-Context.xml")
@Configuration
@EnableAutoConfiguration
public class TestConnexionJdbc extends TestCase {
/*@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/my_database");
dataSource.setUsername("my_cnx_role");
dataSource.setPassword("my_password");
return dataSource;
}*/
@Autowired
private DataSource dataSource;
private TaskletTruncateDonnees tasklet;
@Test
public void testTaskletInstanciation() throws Exception {
assertNotNull("datasource is not null OK",this.dataSource);
this.tasklet = new TaskletTruncateDonnees(this.dataSource);
assertNotNull("tasklet is not null OK",this.tasklet);
assertEquals("tasklet dataSource username OK",this.tasklet.getDataSourceUsername(), "my_cnx_role");
}
@Test
public void testTaskletTruncate() throws SQLException {
assertNotNull("datasource is not null OK",this.dataSource);
this.tasklet = new TaskletTruncateDonnees(this.dataSource);
assertNotNull("tasklet is not null OK",this.tasklet);
this.tasklet.truncateDonnees();
}
}
So I tried to run a similar Spring-Batch with Eclipse > run as an application : First the Launcher :
import org.springframework.boot.SpringApplication;
public class Main {
public static void main(String [] args) {
System.exit(SpringApplication.exit(SpringApplication.run(BatchConfiguration.class, args)));
}
}
And the Batch :
@ContextConfiguration("/Spring-Batch-Context.xml")
@Configuration
@EnableBatchProcessing
@EnableAutoConfiguration
public class BatchConfiguration {
private long initMillis;
/*@Bean
public static DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/my_database");
dataSource.setUsername("my_cnx_role");
dataSource.setPassword("my_password");
System.out.println("bean dataSource =");
System.out.println(dataSource);
return dataSource;
}*/
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource dataSource;
private TaskletTruncateDonnees taskletTruncate;
//tag::readerwriterprocessor[]
@Bean
public ItemReader<Donnee> reader() {
Collection<Donnee> collection = new ArrayList<Donnee>();
for(int i=0;i<1000;i++) {
Donnee donnee = new Donnee();
donnee.setNum_ligne(i);
donnee.setPrenom("Johnny_"+i);
donnee.setNom("Roll_over_The_Mountain_"+i);
donnee.setRue(i+" Main Avenue");
donnee.setVille("Los Angeles District num "+i);
donnee.setEtat("La_californie_"+i);
collection.add(donnee);
}
ItemReader<Donnee> reader = new IteratorItemReader<Donnee>(collection);
return reader;
}
@Bean
public ItemProcessor<Donnee, Donnee> processor() {
return new DonneeItemProcessor();
}
@Bean
public ItemWriter<Donnee> writer(DataSource dataSource) {
long deltaMillis = System.currentTimeMillis()-this.initMillis;
JdbcBatchItemWriter<Donnee> writer = new JdbcBatchItemWriter<Donnee>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Donnee>());
writer.setSql("insert into schema_batch_01.table_batch_donnees_massives values (:num_ligne,"+deltaMillis+",:prenom, :nom, :rue, :ville, :etat)");
writer.setDataSource(dataSource);
return writer;
}
// end::readerwriterprocessor[]
@Bean
public ItemWriter<Donnee> truncater(DataSource dataSource) {
long deltaMillis = System.currentTimeMillis()-this.initMillis;
JdbcBatchItemWriter<Donnee> writer = new JdbcBatchItemWriter<Donnee>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Donnee>());
writer.setSql("insert into schema_batch_01.table_batch_donnees_massives values (:num_ligne,"+deltaMillis+",:prenom, :nom, :rue, :ville, :etat)");
writer.setDataSource(dataSource);
return writer;
}
@Bean
public Job job(Step taskletTruncate,Step stepInserts) {
this.initMillis = System.currentTimeMillis();
Job job = jobBuilderFactory.get("job1")
.incrementer(new RunIdIncrementer())
.start(taskletTruncate).next(stepInserts)
.build();
return job;
}
@Bean
public Step taskletTruncate() {
this.taskletTruncate = new TaskletTruncateDonnees(this.dataSource);
return stepBuilderFactory.get("taskletTruncate")
.tasklet(this.taskletTruncate).build();
}
@Bean
public Step stepInserts(ItemReader<Donnee> reader,ItemWriter<Donnee> writer) {
Step insertSteps = stepBuilderFactory.get("stepInserts")
.<Donnee, Donnee> chunk(10)
.reader(reader)
.writer(writer)
.build();
return insertSteps;
}
// end::jobstep[1]
}
PROBLEM
When I use @ContextConfiguration("/Spring-Test-Context.xml"), test works !!
when I use @Bean in my BatchConfiguration, batch works !!
When I use @ContextConfiguration("/Spring-Batch-Context.xml") batch fails ...
Of course the xml are the same
Here is Eclispe output : the username is WRONG it is SA, why ?
The usernaeme is correct for the JUnit test and for the Batch using @Bean ...
2014-07-31 16:28:32.487 INFO 4300 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@786c4ad7: startup date [Thu Jul 31 16:28:32 CEST 2014]; root of context hierarchy
2014-07-31 16:28:33.673 WARN 4300 --- [ main] o.s.c.a.ConfigurationClassEnhancer : @Bean method ScopeConfiguration.stepScope is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details
2014-07-31 16:28:33.688 WARN 4300 --- [ main] o.s.c.a.ConfigurationClassEnhancer : @Bean method ScopeConfiguration.jobScope is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details
2014-07-31 16:28:33.939 INFO 4300 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Creating embedded database 'testdb'
2014-07-31 16:28:35.109 INFO 4300 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executing SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql]
2014-07-31 16:28:35.141 INFO 4300 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executed SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql] in 32 ms.
2014-07-31 16:28:35.328 INFO 4300 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2014-07-31 16:28:35.360 INFO 4300 --- [ main] o.s.b.a.b.JobLauncherCommandLineRunner : Running default command line with: []
2014-07-31 16:28:35.375 INFO 4300 --- [ main] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: HSQL
2014-07-31 16:28:35.547 INFO 4300 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2014-07-31 16:28:35.656 INFO 4300 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=job1]] launched with the following parameters: [{run.id=1}]
2014-07-31 16:28:35.687 INFO 4300 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [taskletTruncate]
truncateDonnees DataSource=
org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory$EmbeddedDataSourceProxy@3b54c1f8
Username=
SA
2014-07-31 16:28:35.718 INFO 4300 --- [ main] o.s.b.f.xml.XmlBeanDefinitionReader : Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
2014-07-31 16:28:35.859 INFO 4300 --- [ main] o.s.jdbc.support.SQLErrorCodesFactory : SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
2014-07-31 16:28:35.874 ERROR 4300 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step taskletTruncate in job job1
org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [truncate table "schema_batch_01"."table_batch_donnees_massives"]; SQL state [3F000]; error code [-4850]; invalid schema name: schema_batch_01; nested exception is java.sql.SQLException: invalid schema name: schema_batch_01
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
Any IDEA ?
Dont use @ContextConfiguration
for your main configuration files. It is for integration testing. That's why it's in the test jar. See the api
@ContextConfiguration
defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests.
Instead use @ImportResource
this annotation provides functionality similar to the element in Spring XML. It is typically used when designing
@Configuration
classes to be bootstrapped byAnnotationConfigApplicationContext
, but where some XML functionality such as namespaces is still necessary.
Doing this you also need to make sure you don't have a circular reference, meaning you don't have a component-scan in the xml file that points to the java config class. Also if you do have this, and you need to take it out, make sure you have a @ComponentScan
in the java config file that brings back any (if at all) component lost from taking out that xml component scan.
With all that said, I have a feeling this may be your issue, based on the three scenarios and which one failed and which one succeeded. I've done some simple testing where the same problem occurs - not the exact same, but problems with beans not being read.