The specific reason I know is because the QuartzJob class is instantiated, but I know that the constructor with no arguments is used, and then the execute method is called to report the exception. #Inject does not work.
Printed error message:
org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: java.lang.NullPointerException
at org.openscoring.service.quartz.QuartzJob.execute(QuartzJob.java:36)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
... 1 more
QuartzJob implements the Job interface
#Service
#Singleton
public class QuartzJob implements Job {
#Inject
private SynchronousCache synchronousCache;
#Override
public void execute(JobExecutionContext content) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+ "★★★★★★★★★★★");
synchronousCache.synchronizationModel();
}
}
QuartzManager.addJob("test", QuartzJob.class, "10/59 * * * * ? *");
Add a timed task
Related
I have been working on a spring boot application where the application works fine. When i tried to introduce the following code
#Component
#Slf4j
#Getter
#Setter
public class EmployeeDbCreateWriter extends JdbcBatchItemWriter<Employee> {
#Autowired
DataSource datasource;
#Override
public void write(List<? extends Employee> employeeList) throws Exception {
.....
....
}
}
i end up with the following error
Caused by: java.lang.IllegalArgumentException: A DataSource or a NamedParameterJdbcTemplate is
required.
at org.springframework.util.Assert.notNull(Assert.java:201)
at
org.springframework.batch.item.database.JdbcBatchItemWriter.afterPropertiesSet
(JdbcBatchItemWriter.java:143)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
initializeBean(AbstractAutowireCapableBeanFactory.java:1782)
... 57 more
Configure and component scan is given is working fine before introducing the above class
#Configuration
#EnableWebMvc
#EnableJpaRepositories(basePackages =
{"com.emp.repositories","com.emp2.repositories"})
#EnableAsync(proxyTargetClass = true)
#ComponentScan(basePackages = {"com.emp","com.emp2"})
#EntityScan(basePackages = {"com.emp.models","com.emp2.models"})
#EnableCaching
#EnableBatchProcessing
#Slf4j
public class EmpConfig implements WebMvcConfigurer{
Where am I going wrong?
Per what I see in the JdbcBatchItemWriter it requires Datasource or JdbcTemplate to be provided and it is not aware of the autowired datasource in the child class.
You could try something like this and provide datasource manually in the PostConstruct method
#Component
#Slf4j
#Getter
#Setter
public class EmployeeDbCreateWriter extends JdbcBatchItemWriter<Employee> {
#Autowired
DataSource dataSource;
#PostConstruct
public void initialize() {
super.setDataSource(dataSource);
}
....
}
However per #M.Deinum comments is it doubtful that there is a good reasons to extend JdbcBatchItemWriter and that this class was meant to be extended.
Module 1 Server Side
public interface BaseInterface{
Customer createCustomer(Profile profile);
}
public interface InterfaceA extends BaseInterface{
}
public class ServiceProducer {
#EJB(lookup = "java:global/path/ClassA")
#Produces
private InterfaceA interfaceA;
}
#Remote(ClassA.class)
public class ClassA implements InterfaceA{
BaseInterface base;
#Inject
public ClassA(#Named BaseInterface base){
this.base = base;
}
#Override
createCustomer implementation ...
}
Module 2 Client
public class Api{
#Inject
InterfaceA intA;
#Override
Customer createCustomer(arg){
intA.createCustomer
}
}
Hi I am getting the below error when running the above
StatelessEJBLocator for "ClassA", view is interface InterfaceA, affinity is Local
WFLYEJB0034: EJB Invocation failed on component WorkflowManager for method public abstract Customer BaseInterface.createCustomer(Profile): javax.ejb.EJBTransactionRolledbackException: WFLYEE0042: Failed to construct component instance
Error:
Exception 1 :
org.jboss.weld.exceptions.DefinitionException: WELD-001451: javax.transaction.UserTransaction cannot be injected into an enterprise bean with container-managed transactions: [BackedAnnotatedField] #Inject com.evry.integrator.snow.model.dao.impl.GenericDaoImpl.userTransaction
at com.evry.integrator.snow.model.dao.impl.GenericDaoImpl.userTransaction(GenericDaoImpl.java:0)
StackTrace
at org.jboss.weld.module.ejb.WeldEjbValidator.validateInjectionPointForDefinitionErrors(WeldEjbValidator.java:40)
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDefinitionErrors(Validator.java:336)
Code:
public abstract class GenericDaoImpl<T, PK> implements GenericDao<T, PK> {
private static final Logger LOG = Logger.getLogger(GenericDaoImpl.class.getName());
#PersistenceContext(unitName = "IntegratorMasterdataDS")
protected EntityManager em;
#Inject
UserTransaction userTransaction
Scrutiny Class
#Stateless
public class Scrutiny {
private static final Logger log = Logger.getLogger(Scrutiny.class.getName());
public Scrutiny() {
System.out.println("Scrutiny");
}
#Inject
StatusDao statusDao;
public JobStatus insertNewRecord(JobName jName) {
log.info("insertNewRecord:" + jName);
try {
statusDao.beginUserTransaction(); <--- Here i want to begin
statusDao.create(js);
statusDao.flush();
statusDao.commitUserTransaction(); <--- Here i want to Commit
} catch (Exception e) {
log.warning("insertNewRecord:" + e);
}
Status Dao:
public interface StatusDao extends GenericDao<JobStatus, String> {
List<JobStatus> checkExistingRecordToday(JobName jName);
}
Job Status Dao:
#Stateless
public class JobStatusDaoImpl extends GenericDaoImpl<JobStatus, String> implements StatusDao {
private static final Logger LOG = Logger.getLogger(JobStatusDaoImpl.class.getName());
#Override
public List<JobStatus> checkExistingRecordToday(JobName jName) {
As of now whole process is handled by JTA but i want to commit Scrutiny class instantantly which suggest job has just started and at end want to update the same.
You should remove the UserTransaction injection from your DAO generic object and handle the transaction within Scrutiny bean, annotating it with TransactionManagement.
Your bean code should become this:
#Stateless
#TransactionManagement(value=TransactionManagementType.BEAN)
public class Scrutiny {
private static final Logger log = Logger.getLogger(Scrutiny.class.getName());
#Inject
private UserTransaction utx;
public Scrutiny() {
System.out.println("Scrutiny");
}
#Inject
StatusDao statusDao;
public JobStatus insertNewRecord(JobName jName) {
log.info("insertNewRecord:" + jName);
try {
utx.begin(); <--- Here i want to begin
statusDao.create(js);
utx.flush();
utxcommit(); <--- Here i want to Commit
} catch (Exception e) {
log.warning("insertNewRecord:" + e);
}
}
With these changes, your DAO should continue to work using container managed transactions, while your specific bean can control the transaction as desired.
I Have an Spring Boot Application (1.5.10.RELEASE) which contains a main (SpringBootApplication) like this:
#SpringBootApplication
#Configuration
#EntityScan(basePackages = { "db.modell", "db.modell.base" })
#ComponentScan(basePackages = { "de.gui.test" })
public class SpringBootConsoleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
}
and two REST controllers like the following:
#RestController
#RequestMapping("/as")
public class AController {
#Autowired
private ARepository aRepository;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Collection<A>> getAs() {
return new ResponseEntity<>(orgtFarbeRepository.findAll(), HttpStatus.OK);
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<A> getA(#PathVariable long id) {
A a = ARepository.findOne(id);
if (party != null) {
return new ResponseEntity<>(ARepository.findOne(id), HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
}
}
Furthermore I have a single test like this:
#RunWith(SpringRunner.class)
#WebMvcTest(AController.class)
public class AControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private ARepository ARepository;
#Test
public void firstTest() throws Exception {
A a = new aFarbe();
a.set....
when(ARepository.findAll()).thenReturn(Collections.singleton(a));
mvc.perform(
get("/as")
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
)
.andExpect(status().isOk());
}
}
The repositories look like this:
public interface ARepository extends CrudRepository<A, Long>
{
Collection<A> findAll();
}
public interface BRepository extends CrudRepository<B, Long>
{
Collection<B> findAll();
}
A and B them self are JPA annotated classes. The whole application contains access to a database..
Furthermore I have a Service like this:
#Service
public class XService {
private static final Logger LOGGER = LoggerFactory.getLogger(XService.class);
#Autowired
private ARepository aRepository;
#Autowired
private BRepository bRepository;
...
}
The XService is not used via #Autowire or so (Just need to remove that):
So I try to run the AControllerTest I get the following error:
java.lang.IllegalStateException: Failed to load ApplicationContext at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
.. .. at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'XService': Unsatisfied dependency
expressed through field 'BRepository'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'BRepository' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
.. .. at
org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 26 more Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'BRepository' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 44 more
My assumption is that during the test more context is started than it should. The question is how can I prevent that? Which means only to start the context for the AControler and nothing more? I thought that based on the #WebMvcTest(AController.class) it should be limited already which looks like that it was not the case...
The referenced answer does not really answered my question but a in the context a hint gave me the solution. This means in consequence to add the following to my test:
so I have to add #OverrideAutoConfiguration(enabled=true):
#RunWith(SpringRunner.class)
#WebMvcTest(OrgtFarbenController.class)
#OverrideAutoConfiguration(enabled=true)
public class AControllerTest {
...
}
there's a session scoped bean 'Identity' which I injected in a #Stateless bean which implements Runnable:
#Stateless
#LocalBean
public class Test implements Runnable {
#Inject
Identity identity;
#Inject
Logger log;
#Override
public void run() {
log.warn("Test: " + this + " " + identity.getAccount().getId());
}
}
There's also a bean which invokes the above Runnable asynchronously:
#Stateless
#LocalBean
public class BeanContextExecutor implements Executor {
#Asynchronous
#Override
public void execute(Runnable command) {
command.run();
}
}
and finally, the invocation looks like this:
#Stateless
public class OtherBean {
#Inject
BeanContextExecutor executor;
...
executor.execute(command);
...
}
When running this I'm getting the following error:
...
Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
...
Is there any way to propagate the SessionContext to the background thread?
I also tried to submit this Runnable to ManagedExecutorService and even to create a proxy for it with a ContextService and submit a proxy but still getting the same error.
Thanks for any help with this!
As a workaround in BeanContextExecutor I used BoundSessionContext to create a dummy session context for a new thread and also had to manually copy the required session bean to make its state available in the background thread:
#Inject
BoundSessionContext boundSessionContext;
// Backed by a ConcurrentHashMap<Runnable, Identity> which stores the state of the session scoped bean before spawning a new thread
#Inject
GlobalExecutionContext globalExecutionContext;
#Inject
Instance<Identity> identityInstance;
#Inject
Cloner cloner;
#Inject
private BeanManager beanManager;
#Asynchronous
#Override
public void execute(Runnable command) {
HashMap<String, Object> storage = new HashMap<>();
boundSessionContext.associate(storage);
boundSessionContext.activate();
Identity identity = globalExecutionContext.remove(command);
Bean<Identity> bean = (Bean<Identity>) beanManager.resolve(beanManager.getBeans(Identity.class));
Identity localIdentity = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
cloner.copyPropertiesOfInheritedClass(identity, localIdentity);
command.run();
boundSessionContext.invalidate();
boundSessionContext.deactivate();
boundSessionContext.dissociate(storage);
}
The example is intended to demonstrate the approach, it's possible to improve it like support passing beans of an arbitrary type. But I don't like this approach at all. There should be a better solution for context propagation problem.
Update:
I'd like to keep the caller identity in a background thread even if initial session is expired, it looks like the above solution is suitable for this.