Issue with Quartz persistent jobs while using with Spring - java

I have configured a spring's method invoking job previously which is working fine. Now my requirement is to have this job as persistent which will run in a clustered environment.
After configuring the quartz as clustered and persistence, application is throwing the following exception at deployment:
java.io.NotSerializableException: Unable to serialize JobDataMap for
insertion into database because the value of property 'methodInvoker'
is not serializable:
org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
I am using the following versions:
Spring version 3.1.4.RELEASE
Quartz version 2.1.7
Update: As per the documentation of MethodInvokingJobDetailFactoryBean:
JobDetails created via this FactoryBean are not serializable.
So, looking for some alternative approach to configure a persistent job in spring.

I have solved the problem by replacing MethodInvokingJobDetailFactoryBean with JobDetailFactoryBean. Configuration for the same is as follows:
<bean name="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="mypackage.MyJob" />
<property name="group" value="MY_JOBS_GROUP" />
<property name="durability" value="true" />
</bean>
However, to Autowire the spring managed beans in my job class mypackage.MyJob, I have added the following as first line in my execute method:
class MyJob implements Job {
...
public void execute(final JobExecutionContext context) throws JobExecutionException {
// Process #Autowired injection for the given target object, based on the current web application context.
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
...
}
}
Hope it it will help someone else facing the same issue.

When you are using persistent quartz jobs, you should be setting the org.quartz.jobStore.useProperties property to true. That forces the job data to be saved as Strings instead of Java Serialized objects.
Doing so however may cause some problems with Spring, that are easily solvable.
Check these links for more details:
http://site.trimplement.com/using-spring-and-quartz-with-jobstore-properties/
http://forum.spring.io/forum/spring-projects/container/121806-quartz-error-ioexception

The other way to solve this problem is avoid using 'jobDataMap' property for 'JobDetailFactoryBean' bean. Instead, add the dependency (the bean containing method to run) in Scheudler with 'schedulerContextAsMap' property.
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
... (other properties)...
<property name="schedulerContextAsMap">
<map>
<entry key="executeProcessBean" value-ref="executeProcessBean" />
</map>
</property>
</bean>
Since, the documentation of schedulerContextAsMap in SchedulerFactoryBean mentions about the usage when you have Spring beans.
/**
* Register objects in the Scheduler context via a given Map.
* These objects will be available to any Job that runs in this Scheduler.
* <p>Note: When using persistent Jobs whose JobDetail will be kept in the
* database, do not put Spring-managed beans or an ApplicationContext
* reference into the JobDataMap but rather into the SchedulerContext.
* #param schedulerContextAsMap Map with String keys and any objects as
* values (for example Spring-managed beans)
* #see JobDetailFactoryBean#setJobDataAsMap
*/

just add implements Serializable

Related

Lazily initializing beans in a Spring Map

I'm trying to lazily initialize beans in a Spring map such that the beans inside are only initialized when they are retrieved via map.get. Consider the following code:
Spring config:
<bean class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="foo">
<bean class="Messager" lazy-init="true">
<constructor-arg index="0" value="bar" />
</bean>
</entry>
</map>
</constructor-arg>
</bean>
Test class:
public class Messager {
public Messager(String message) {
System.out.println(String.format("Initialized %s", message));
}
}
If you run the above code, the Messager bean in the map is initialized upon application startup. How can I defer bean initialization until the map entry is retrieved?
lazy-true simply defers the initialization till the first reference of this spring bean from other bean (or internal Spring infrastructure code as it happens in this case).
Here atmost the initialization of outer map can be deferred but once it is initialized the map passed via constructor would be completely initialized. The map element functionality is supported by Spring's MapFactoryBean and it does not looks like that it supports the feature you desire as it initializes the values in the map in one go. So
AFAIK , Spring does not have this support out of box - however you can try your own implmentation of a lazy map or use LazyMap of commons-collection.
Also you might need to write a FactoryBean to enable this class to be usable in Spring context.

#Cacheable not working

I am using #Cacheable for caching the result of a method at Service layer in Spring 3.2. following method code is used inside service Class:
#Cacheable("questions")
public List<ABClassObject> getSecutityQuestionsList(){
List<ABClassObject> list = new ArrayList<ABClassObject>();
----------------
list = ----[DAO call]
return list;
}
xml Configuration
<cache:annotation-driven />
<!-- Generic cache manager based on the JDK ConcurrentMap -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="questions" />
</set>
</property>
</bean>
Can't use EhCache because of using jdk 1.6.
By using the above code pattern i am unable to cache the List result.DAO is called all the time when i call the above method.
So, Suggest me whats wrong with the code.
Thanks in advance.
Some things you should check:
The class of getSecutityQuestionsList method is a spring bean, i.e, you donĀ“t use a new operator anyway.
The method getSecutityQuestionsList is called from another bean
In your xml configuration put a context:component-scan base-package="xxxxx"
Put a break point inside your method. In the stack trace you should see some spring proxy stuff. When you call this method of your service, you should actually be calling a spring proxy.

Spring: run code before a persistence context is loaded

I have spring based multimodule application. And in my DAO module the DB (embedded derby) is started and created by the class the implements ApplicationListener.
Problem that in the logs the huge stacktrace from Spring which say that there is no db(couldn't get connection).
Still, my application works without any problems. This stacktrace appeared before the ApplicationListener invoked and the db is created. Actually, I see it only when I am starting the application the first time on the machine, because the db created only this time, than it just used.
So my question is whow to avoid this exception in logs? Maybe there is spring or hibenate setup not connect to the db before the application context fully loaded? Or invoke the code that creates db by some other listener?
Well here is the way I do : the ROOT context contains the datasource, the dao, the service and the transaction manager. In XML config, the declaration of the database is :
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:url="jdbc:derby:/path/to/database;create=TRUE"
p:username="user" p:password="pwd"
p:driverClassName="org.apache.derby.jdbc.EmbeddedDriver"/>
it can then be used to declare a session factory for hibernate and an associated DAO as :
<bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
id="sessionFactory" p:dataSource-ref="datasource">
<!-- hibernate config -->
...
</bean>
<bean class="org.springframework.orm.hibernate4.HibernateTransactionManager"
name="transactionManager" p:sessionFactory-ref="sessionFactory"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="myDao" class="... .myDaoImpl" p:sessionFactory-ref="sessionFactory" .../>
That way all is created by spring, that ensures that the creation order is correct. Of course the same is possible in Java config with the same logic.
I suppose you are fetching some data from database from inside spring beans that are being created. Perhaps thru #PostConstruct or other way. Remember that until spring context is fully loaded some beans can have injected uninitialized beans.
So do not use DB, do not call any DAOs until you are sure that spring context is fully initialized.
To do such initial calls to DAOs try such patter that guarantees spring context completness:
#Component
public class SpringContextMonitor implements ApplicationListener<ApplicationEvent> {
#Autowired
private SomeDao dao;
...
#Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
onStart((ContextRefreshedEvent) event);
}
}
private void onStart(ContextRefreshedEvent event) {
// do your initialization here
dao.getSomething();
dao2.getSomething();
...
}
...
}
The onStart method in above example is place where you are sure that all beans are fully initialized

Spring injecting or autowiring datasource bean to class

this may be a very novice question, but I have searched and either I have a large gap in my understanding or am doing something incorrectly that I cannot figure out.
In my context file here is an excerpt
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${datasource.driverClassName}" />
<property name="url" value="${datasource.url}" />
<property name="username" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
</bean>
<bean id="myBeanOne" class="a.b.c.myBeanOne">
<property name="dataSource" ref="dataSource" />
</bean>
Now in myBeanOne I have:
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource (DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void myMethod() {
String sql = "'My generic SQL update query'";
try {
this.jdbcTemplate.update(sql);
} catch (org.springframework.dao.EmptyResultDataAccessException ex) {
}
System.exit(0);
}
when I try to execute this on the line where setDataSource is invoked I get this error:
ERROR org.springframework.integration.handler.LoggingHandler
org.springframework.integration.MessageHandlingException:
java.lang.NullPointerException
on the line: this.jdbcTemplate.update(sql);
I have tried maybe ten different configurations to get this to work, but I cannot seem to do it. Any assistance is appreciated, thank you.
Edit: as per Luiggi's comment:
//in yet another classes run method
myBeanOne bOne = SomeOtherClass.create(); //just returns new myBeanOne
bOne.myMethod();
Neither SomeOtherClass or this class are classified as beans in the context or have any presence in the context.
I know that this is a very basic question but I am struggling with it.
Thank you for your patience.
As noted in comments, the problem is that you're manually creating the bean instead of letting Spring container create it. Basically, you're doing this:
new MyBeanOne()
So Spring container can't inject any of the fields you have configured thus being null e.g. jdbcTemplate field. There are some solutions to this:
Convert your SomeOtherClass into a bean managed by Spring container and let it inject the MyBeanOne instance (probably using #Autowired annotation).
If latter approach can't be done since you need to manually create the bean, you can create the bean manually as shown here: How to create spring beans dynamically?
But this implementation makes you hardcode somewhere the spring config file name and use it in your code. So, a better approach would be option 3.
Look at this solution: Creating New Spring Beans on Demand, where you create a client abstract class with a method that Spring will implement to retrieve a new instance of your Spring managed bean.
I found another way to handle this by using #Configurable annotation. By decorating your bean with this annotation, you can create a new instance of the bean on demand and Spring will manage the injection of Spring managed beans for you. But to achieve this, Spring needs to use aspects behind the scenes and you should activate usage of aspects for your project. The explanation is quite long, so I provide links that explain in depth this solution:
Spring Framework: 7.8 Using AspectJ with Spring applications
Using Spring's #Configurable in three easy steps
Note that in order to enable this feature, you have to add a java agent when starting the JVM that will weave the class at runtime using aspects.
NullPointerException on the line: this.jdbcTemplate.update(sql);
If the NPE is actually on that line, then this.jdbcTemplate is obviously null. If this is true then either:
The setDataSource(...) method is not being called in Spring, possibly because the #Autowired is not right somehow. It would be easy to add a System.out.println(...) or put a debugging breakpoint in setDataSource to see if it is being called.
If it is being called then maybe there are more than one instance of a.b.c.myBeanOne? Are you for sure getting the instance being called from another class from the Spring context? Put a breakpoint in setDataSource and notice the this object reference id. Then put a breakpoint on the this.jdbcTemplate.update(...) line and make sure that the this reference-id is the same.

Spring Config file consisting of List of Implementations

I Am very new to Spring. I have an Interface (MessageHandler ) which has a get method, this method returns a list of Implementations of another interface (messageChecker).
public interface MessageHandler {
public void process(BufferedReader br);
public void setMessageCheckerList(List mcList);
[B]public List getMessageCheckerList();[/B]
}
In my Spring XML configuration , i have something like this ,along with other beans
<bean id="messageHandler" class="com.XXX.messagereceiver.MessageHandlerImpl">
<property name="messageCheckerList" ref="checkerList"/>
</bean>
<bean id="checkerList" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="HL7Checker"/>
</list>
</constructor-arg>
</bean>
<bean id="HL7Checker" class="com.XXX.messagereceiver.HL7CheckerImpl">
<property name="messageExecutor" ref="kahootzExecutor"/>
</bean>
Here i am passing a checkerlist - which is a list of Implementations ( For now i have only 1) of the Interface (messageChecker)
Checkerlist is containing references to Bean Id's which are actual implementaions.
HL7Checker is an implementation of an Interface messageChecker.
But when i run the main program, When i inject the bean "messageHandler" and call the getMessageCheckerList, It returns a null value. These getter and setter methods are working fine without using spring.
I am not sure what seems to be the problem.
I don't know the answer for you troubles, but I would check:
is the setter setMessageCheckerList(List) in messageHandler bean called? (either using some debugger or some trace output like System.out...). If it's not, there's probably something wrong with your Spring XML configuration setup. The bean definition you posted requires the property to be set and Spring wouldn't create the messageHandler bean without setting the property.
who calls the setMessageCheckerList(List) setter? Or even more precise, what code writes to the field which stores the value of the property? Maybe the field is initialized properly by Spring but gets overwritten to null later on?
are you sure you call the getMessageCheckerList on the very same object Spring has configured for you (that is, the messageHandler bean). The definition you have posted clearly states an instance of MessageHandlerImpl is created by Spring, but it doesn't prevent other instances to be created in other ways. So maybe the instance created by Spring holds the proper value, but you run the get... on a wrong instance?

Categories