while creating a spring batch job that reads data from one table using a reader class and then writes into another table in the same db.
while running the application getting "datasource must be provided" error
The code looks like this
ApplicationConfiguration.java ( configuration class)
#Configuration
#Log4j2
public class ApplicationConfiguration {
#Bean(name="mysqlDS", destroyMethod = "close")
#Qualifier("mysqlDS")
public DataSource getDataSource(#Autowired DBConfiguration dbProperties) {
log.info("Inside getDataSource method");
HikariConfig jdbcConfig = new HikariConfig();
jdbcConfig.setJdbcUrl(dbProperties.getDbURL());
jdbcConfig.setDriverClassName(dbProperties.getDriverClass());
jdbcConfig.setPoolName(dbProperties.getJdbcPoolName());
jdbcConfig.setMaximumPoolSize(dbProperties.getMaxPoolSize());
jdbcConfig.setIdleTimeout(dbProperties.getIdleTimeout());
jdbcConfig.setMinimumIdle(dbProperties.getMinIdle());
jdbcConfig.setConnectionTimeout(dbProperties.getConnectionTimeout());
jdbcConfig.setUsername(dbProperties.getClientKey());
jdbcConfig.setPassword(dbProperties.getClientSecret());
return new HikariDataSource(jdbcConfig);
}
#Bean(name = "jdbcDS")
public JdbcTemplate getJdbcTemplate(#Autowired DBConfiguration dbProperties) {
return new JdbcTemplate(getDataSource(dbProperties));
}
}
DBConfiguration.java ( getting config properties from service)
#Component
#Getter
#Setter
#Configuration
#ConfigurationProperties("some service")
public class DBConfiguration {
private String dbURL;
private String driverClass;
private String jdbcPoolName;
private int maxPoolSize;
private long idleTimeout;
private int minIdle;
private long connectionTimeout;
private String clientKey;
private String clientSecret;
}
BatchConfig.java ( for creating job)
#Configuration
#EnableBatchProcessing
#Log4j2
public class BatchConfig {
#Autowired
DBConfiguration dbProperties;
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
SWItemReader itemReader ;
#Autowired
SWItemWriter itemWriter;
#Autowired
SWItemProcessor batchProcessor;
#Bean
public Job Job() {
return jobBuilderFactory.get("batch-job")
.incrementer(new RunIdIncrementer())
.flow(Step())
.end()
.build();
}
#Bean
public Step Step() {
return stepBuilderFactory.get("step")
.<Users,Managers>chunk(1)
.reader(itemReader)
.processor(batchProcessor)
.writer(itemWriter)
.build();
}
SWItemReader.java ( reader to read from db)
#Log4j2
public class SWItemReader extends JdbcCursorItemReader<Users> implements ItemReader<Manager> {
#Autowired
DBConfiguration dbProperties;
public ApplicationConfiguration applicationConfiguration;
private static final String QUERY_SELECT_PARTNERS ="select query"
public SWItemReader getItemReader() {
SWItemReader swItemReader = new SWItemReader();
swItemReader.setDataSource(applicationConfiguration.getDataSource(dbProperties));
swItemReader.setSql(QUERY_SELECT_USERS);
swItemReader.setFetchSize(100);
swItemReader.setRowMapper(new UsersRowMapper());
return swItemReader;
}
}
ERROR
Error creating bean with name 'BatchConfig': Unsatisfied dependency expressed through field 'swItemReader'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'SWItemReader' defined in file [D:\\git\SWItemReader.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: DataSource must be provided"}
seems like the datasource is not being set properly .
What am i doing wrong here .
Related
I'm using springboot and rabbitmq to receive a message.
The first consumer i created works, declared as below:
#Component
public class UserConsumer {
#Autowired
private RabbitTemplate template;
#RabbitListener(queues = MessagingConfig.CONSUME_QUEUE)
public void consumeMessageFromQueue(MassTransitRequest userRequest) {
...
}
}
I then needed a second consumer so i duplicated the above and called it another name:
#Component
public class PackConsumer {
#Autowired
private RabbitTemplate template;
#RabbitListener(queues = MessagingConfig.CONSUME_QUEUE_CREATE_PACK)
public void consumeMessageFromQueue(MassTransitRequest fileRequest) {
...
}
}
Everything works locally on my machine, however when i deploy it the new queue does not process messages because there is no consumer connected to it. The UserConsumer continues to work.
Is there something else i should be doing in order to connect to the new queue at the same time as the original?
During my learning i did add a "MessagingConfig" class as below, however i believe it relates to sending messages and not receiving them or an alternative configuration:
#Configuration
public class MessagingConfig {
public static final String CONSUME_QUEUE = "merge-document-request";
public static final String CONSUME_EXCHANGE = "merge-document-request";
public static final String CONSUME_ROUTING_KEY = "";
public static final String PUBLISH_QUEUE = "merge-document-response";
public static final String PUBLISH_EXCHANGE = "merge-document-response";
public static final String PUBLISH_ROUTING_KEY = "";
public static final String CONSUME_QUEUE_CREATE_PACK = "create-pack-request";
public static final String CONSUME_EXCHANGE_CREATE_PACK = "create-pack-request";
public static final String CONSUME_ROUTING_KEY_CREATE_PACK = "";
public static final String PUBLISH_QUEUE_CREATE_PACK = "create-pack-response";
public static final String PUBLISH_EXCHANGE_CREATE_PACK = "create-pack-response";
public static final String PUBLISH_ROUTING_KEY_CREATE_PACK = "";
#Bean
public Queue queue() {
return new Queue(CONSUME_QUEUE);
}
#Bean
public TopicExchange exchange() {
return new TopicExchange(CONSUME_EXCHANGE);
}
#Bean
public Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(CONSUME_ROUTING_KEY);
}
#Bean
public MessageConverter converter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public AmqpTemplate template(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(converter());
return rabbitTemplate;
}
}
Thanks in advance
I'm trying to make CDI work on JBeret SE.
This is my code:
SampleBatchlet class
#Named
public class SampleBatchlet extends AbstractBatchlet
{
#Inject
#BatchProperty(name = "foo")
String foo;
#Inject
StepContext stepContext;
#Inject
Logger logger;
#Override
public String process() throws Exception {
final String say = stepContext.getProperties().getProperty("say");
System.out.println("hello foolish");
return null;
}
}
SampleBatchletTest class
#EnableWeld
class SampleBatchletTest {
#Inject
Logger logger;
#WeldSetup
public WeldInitiator weld = WeldInitiator
.from(
LoggerProducer.class
)
.activate(
RequestScoped.class,
ApplicationScoped.class
)
.build();
#Test
void app() throws InterruptedException {
final JobOperator jobOperator = BatchRuntime.getJobOperator();
long id = jobOperator.start("simplebatchlet", null);
final JobExecutionImpl jobExecution = (JobExecutionImpl) jobOperator.getJobExecution(id);
jobExecution.awaitTermination(5, TimeUnit.SECONDS);
Assertions.assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus());
}
}
Server class
#ApplicationScoped
public class Server {
#Inject
private Logger logger;
public void init(#Observes #Initialized(ApplicationScoped.class) Object init) throws InterruptedException {
logger.info("init");
}
LoggerProducer class
public class LoggerProducer {
#Produces
public Logger produceLogger(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
}
The issue is Logger instance is not injected on SampleBatchlet, whereas is correctly injected either on test and server class above.
Any hints?
LITTLE UPDATE
By reading this reference
https://jberet.gitbooks.io/jberet-user-guide/content/batch_properties/
I discovered java.util.logging.Logger can be injected.
Therefore I added
<batchlet ref="it.infocert.shop.main.SampleBatchlet" >
<properties>
<property name="logger" value="java.util.logging.Logger" />
</properties>
</batchlet>
where value can be actually anything..
On SampleBatchlet I added
#Inject
#BatchProperty
Logger logger;
and now it is injected. I'm a bit perplexed by the way, because I wish to use another logger implementation..
When injecting via #BatchProperty, JBeret tries to check the type of injection field and match it up with the injection value, and instantiate an instance for injection. That's why the logger created by JBeret, instead of your own logger, is injected. For details, see JBeret BatchBeanProducer.java
To inject your own logger via a producer method, you may need to add a qualifier to disambuiguise it. For example,
public class LoggerProducer {
#Produces
#Named("myLogger")
public Logger produceLogger(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
}
#Inject
#Named("myLogger")
Logger logger;
I changed batchet ref on my xml from:
<batchlet ref="it.infocert.shop.main.SampleBatchlet">
to:
<batchlet ref="sampleBatchlet">
now it works
I'm new to Java, Neo4j and Spring Data and I'm experiencing some difficulties with the latter.
I'm currently using Spring Data Neo4j 4.1.6. and I have a basic class Person, which is marked with #NodeEntity. It has no-argument constructor and one constructor with String name just for tests.
After a lot of errors I managed to get to the point, where I have a Neo4jTemplate. THE PROBLEM is that when I try to save the Objects of the class Person in the database I get a warning that these are not instances of a persistable class.
e.g. WARN org.neo4j.ogm.session.Neo4jSession - Thread 1:xtractor.Person is not an instance of a persistable class
Here is my Configuration class and Thanks in advance.
package xtractor;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.neo4j.template.Neo4jTemplate;
#Configuration
public class Neo4jConfig extends Neo4jConfiguration{
#Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config =
new org.neo4j.ogm.config.Configuration();
config.driverConfiguration().
setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver")
.setURI("file:///" + Console.dbLocation + ".db");
return config;
}
#Override
#Bean
public SessionFactory getSessionFactory() {
// with domain entity base package(s)
return new SessionFactory(getConfiguration(), "xtractor.*");//tried everything here
}
#Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService() {
return Console.db; //thats the DatabaseService I use.
}
#Bean
//#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception{
return super.getSession();
}
#Bean
public Neo4jOperations neo4jTemplate() throws Exception{
return new Neo4jTemplate(getSession());
}
}
Edit: Person.class
I think the problem is that I can't make Neo4j scan for these #NodeEntities
package xtractor;
import org.neo4j.ogm.annotation.*;
#NodeEntity
public class Person {
#GraphId
private Long graphId;
private String firstName;
private String lastName;
private int birthdate;
private String birthplace;
public Person(){
}
public Person(String firstName){
this.firstName = firstName;
System.out.println("Person created");
}
//getters and setters
}
Hello i use spring boot 1.3.2 version. I have a custom argument resolver which's name is ActiveCustomerArgumentResolver. Everything is great, resolveArgument method works fine but i can't initialize my service component which is of my custom arg. resolver. Is there a problem with lifecycle process? Here is my code:
import org.springframework.beans.factory.annotation.Autowired;
//other import statements
public class ActiveCustomerArgumentResolver implements HandlerMethodArgumentResolver {
#Autowired
private CustomerService customerService;
#Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(ActiveCustomer.class) && parameter.getParameterType().equals(Customer.class))
return true;
else
return false;
}
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Principal userPrincipal = webRequest.getUserPrincipal();
if (userPrincipal != null) {
Long customerId = Long.parseLong(userPrincipal.getName());
return customerService.getCustomerById(customerId).orNull(); //customerService is still NULL here, it keeps me getting NullPointerEx.
} else {
throw new IllegalArgumentException("No user principal is associated with the current request, yet parameter is annotated with #ActiveUser");
}
}
}
Let the Spring create the resolver for you by making it a Component:
#Component
public class ActiveCustomerArgumentResolver implements HandlerMethodArgumentResolver {...}
Then inject the resolver into your WebConfig instead of simply using the new, like following:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired private ActiveCustomerArgumentResolver activeCustomerArgumentResolver;
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(activeCustomerArgumentResolver);
}
}
This is how i've solved the problem, not a generic one but helps me a lot:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends WebMvcConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(activeCustomerArgumentResolver());
}
#Bean
public ActiveCustomerArgumentResolver activeCustomerArgumentResolver() {
return new ActiveCustomerArgumentResolver();
}
}
I'm trying to write a "Hello, World" with Spring Data Neo4j in a standalone app. It runs and actually creates the Neo4j database, but my #Autowired repo is not being initialized. I suspect the problem is in my main class, but I don't know what to try. Unsurprisingly, almost all the Spring tutorials I've found are about web apps.
What am I doing wrong?
config bean:
#Configuration
#EnableNeo4jRepositories(basePackages = "test2")
public class ConfigBean extends Neo4jConfiguration {
private static final String DB_PATH = "/home/kevin/tmp/hello-spring-data-neo4j/";
public ConfigBean() {
setBasePackage("test2");
}
#Bean
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
}
}
node entity:
#NodeEntity
public class Foo {
#GraphId
private Long id;
}
repository:
public interface FooRepository extends GraphRepository<Foo> { }
main class:
#Component
public class Test2 {
#Autowired
FooRepository repo;
public void doStuff() {
System.out.println("repo: " + repo); // null!
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("test2");
new Test2().doStuff();
}
}
It logs about 350 lines of output. These are the last few lines. I searched for this error message, but the impression I got is that it's unrelated to my problem.
20:44:30.630 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
20:44:30.631 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
20:44:30.635 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
repo: null
Via the magical "ask a question, find the answer" effect, my main class now looks like this, and the repo is being assigned:
#Component
public class Test2 {
#Autowired
FooRepository repo;
public void doStuff() {
System.out.println("repo: " + repo);
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("test2");
Test2 test2 = context.getBean(Test2.class);
test2.doStuff();
}
}