I have a problem, injecting a CDI Bean in a Quartz schedule Job. This is the Code of the Job-Class.
import javax.inject.Inject;
import lombok.extern.java.Log;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.example.controller.UserController;
#Log
public class SomethingNewScheduler implements Job {
#Inject
UserController userController;
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
userController.doSomething();
}
}
My UserController is defined as following:
import java.io.Serializable;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import lombok.extern.java.Log;
import de.example.dao.UserDao;
#Log
#ApplicationScoped
public class UserController implements Serializable {
private static final long serialVersionUID = 5922763136823308273L;
#EJB
private UserDao userDao;
public void example(){
userDao.getSomething();
}
}
When I try to access the userController in my SomethingNewScheduler, i get a NullPointerException. Implementing Serializable in SomethingNewScheduler didn't solve the problem.
I'm using Wildfly 8.2.0 for my Application. Accessing UserController in a RestService worked perfectly fine.
Has anyone a idea, why it doesn't work here?
Related
I am writing tests using Spring Cloud Contract.
In my configuration I am using for test an in memory DB that is created and destroyed at each test run.
In order to test successfully I need to put some data in the DB but it seems like the classic #Before annotation used in jUnit does not work (the code in it is never executed).
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.context.WebApplicationContext;
#ExtendWith(SpringExtension.class)
#SpringBootTest
public class BaseTestClass {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseTestClass.class);
#Autowired
EntityRepository entityRepository;
#Autowired
private WebApplicationContext context;
#Before
public void init() {
// This code never runs
LOGGER.info("Init started");
MyEntity entity1 = new MyEntity();
entityRepository.save(entity1);
}
#BeforeEach
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
}
What am I missing?
#Before belongs to JUnit4 and earlier while #BeforeEach belongs to JUnit5 as a replacement and clarification of #Before. If you are running with JUnit5, perhaps put all your initialization logic in #BeforeEach (or if it's a one-time init, in #BeforeAll)
I've found a solution that works.
I was adding the #TestInstance decorator incorrectly, here's my working solution:
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.context.WebApplicationContext;
#ExtendWith(SpringExtension.class)
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTestClass {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseTestClass.class);
#Autowired
EntityRepository entityRepository;
#Autowired
private WebApplicationContext context;
#BeforeAll
public void init() {
LOGGER.info("Init started");
MyEntity entity1 = new MyEntity();
entityRepository.save(entity1);
}
#BeforeEach
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
}
I have a Data Loader Class which is suppose to load data once the app starts.
My Error -
Could not autowire. No beans of 'OwnerService' Found.
However, my ownerService class is annotated as I have shown below -
This is the class whose supposed to do that -
DataLoader
import model.Owner;
import model.Vet;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import services.OwnerService;
import services.VetService;
import services.map.OwnerServiceMap;
import services.map.VetServiceMap;
#Component
public class DataLoader implements CommandLineRunner {
private final OwnerService ownerService;
private final VetService vetService;
public DataLoader(OwnerService ownerService, VetService vetService) {
this.ownerService = ownerService;
this.vetService = vetService;
}
OwnerServiceMap
package services.map;
import model.Owner;
import org.springframework.stereotype.Service;
import services.OwnerService;
import java.util.Set;
#Service
public class OwnerServiceMap extends AbstractMapService<Owner,Long> implements OwnerService
{//some code here}
The vetService is the same as ownerService.
My applcation class -
package petclinic;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class PetclinicApplication {
public static void main(String[] args) {
SpringApplication.run(PetclinicApplication.class, args);
}
}
Maybe I have hierarchy problems, as the application class doesn't search for beans in enough places in the project?
Thank you!
I try to use Springs own Dependency Injection in a Junit test case:
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.binarisinformatik.api.AppConfig;
import org.binarisinformatik.satzrechner.SatzRechner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=AppConfig.class)
//#SpringApplicationConfiguration(classes = {AppConfig.class})
public class SatzRechnerTest {
#Autowired
private SatzRechner satzRechner; //SUT
#Before
public void setUp() {
// AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SatzRechnerTest.class);
//satzRechner=context.getBean(SatzRechner.class);
}
#Test
public void addiere_satz_4komma6_zu_zahlwert_10() {
assertThat("Addition von \"4,6\" ergibt nicht 10!",
satzRechner.summe("4,6"), is(equalTo(10)));
}
Im testing a class names SatzRechner in which Spring should also autowire some variables. Here is my Class under test:
#Component
public class SatzRechner {
#Autowired //#Inject
private Rechner taschenRechner;
#Autowired
private Zahlenfabrik zahlenfabrik;
public Integer summe(String zeichenSatz) {
return taschenRechner.summe(zahlenfabrik.erzeugeZahlen(zeichenSatz));
}
}
And AppConfig.class which is using as Configurationfile looks like that:
#Configuration
#ComponentScan(value={"org.binarisinformatik"})
public class AppConfig {
}
What is here the problem?
If you want to use a Spring configuration class, this one must have beans definitions. Please find an example below :
Test class:
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.binarisinformatik.api.AppConfig;
import org.binarisinformatik.satzrechner.SatzRechner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=AppConfig.class)
public class SatzRechnerTest {
#Autowired
private SatzRechner satzRechner;
#Test
public void addiere_satz_4komma6_zu_zahlwert_10() {
assertThat("Addition von \"4,6\" ergibt nicht 10!",
satzRechner.summe("4,6"), is(equalTo(10)));
}
}
Configuration class :
You have to declare #Bean annotated methods. These beans are managed by Spring container.
#Configuration
public class AppConfig {
// Beans present here will be injected into the SatzRechnerTest class.
#Bean
public SatzRechner satzRechner() {
return new SatzRechner();
}
#Bean
public Rechner taschenRechner() {
return new TaschenRechner();
}
#Bean
public Zahlenfabrik zahlenfabrik() {
return new Zahlenfabrik();
}
}
Note : I let you properly handle returned types here and beans parameters (if present in your context).
There are two things you have to ensure before you run the test case successfully:
1) Classes SatzRechner, Rechner & Zahlenfabrik should be under "org.binarisinformatik" package
2) Classes Rechner & Zahlenfabrik should also be annotated with #Component as SatzRechner.
This test is failing but I don't know why or how to fix it. If I hit a break point and call mockingContext.getBean(Repository.class), it does return my mock object, but for some reason the ProductionCode returned in createProductionCodeWithMock still has the real Repository autowired into it. I can only suspect that I need to do something special/extra to have an effect on autowired beans, but I don't know what it is. Why isn't this test passing, and how can I make it pass?
For what it's worth, I'm well aware of all the answers to this question. I still want to know why this test isn't working. I am using Spring 3.x.
Here's the test:
package mavensnapshot;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class ProductionCodeTest {
#Test
public void testReplaceRepositoryWithMock() {
Repository mockRepository = mock(Repository.class);
ProductionCode productionCode = createProductionCodeWithMock(mockRepository);
productionCode.doSomething();
verify(mockRepository).save();
}
private ProductionCode createProductionCodeWithMock(Repository mockRepository) {
GenericApplicationContext mockingContext = new GenericApplicationContext();
mockingContext.getBeanFactory().registerSingleton(Repository.class.getName(), mockRepository);
mockingContext.setParent(new ClassPathXmlApplicationContext("/beans.xml"));
return mockingContext.getBean(ProductionCode.class);
}
}
Here's my production code:
package mavensnapshot;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/beans.xml");
ProductionCode productionCode = context.getBean(ProductionCode.class);
productionCode.doSomething();
}
}
package mavensnapshot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ProductionCode {
#Autowired
private Repository repository;
public void doSomething() {
repository.save();
}
}
package mavensnapshot;
import org.springframework.stereotype.Service;
#Service
public class Repository {
public void save() {
System.out.println("production code");
}
}
i'm absolutely baffled. I have a standard, old school EJB-CDI-JSF-Hibernate JavaEE Application, running on a JBoss AS 7.1. Furthermore my structure is an absolut standard structure. I have JSF-Sites, which access my CDI Beans. The CDI Beans are holding a reference to one of my entities, the EJBs are used as DAOs. One of my beans is this CommissionController. It works absolutely fine. Only one instance is created for one user.
package controller;
import java.io.Serializable;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import lombok.Data;
import lombok.extern.java.Log;
import entities.Commission;
#SessionScoped
#Data
#Log
#Named
public class CommissionController implements Serializable {
private static final long serialVersionUID = -8452887234021054225L;
#Inject
private UserController userController;
#Inject
private CartController cartController;
private Commission commission;
#PostConstruct
public void init() {
commission = new Commission();
log.info("new CommissionController instance");
}
public void makeNewCommission() {
commission.setCart(cartController.getCart());
commission.setOrderDate(new Date());
commission.setOrderer(userController.getUser());
cartController.clearCart();
log.info(commission.toString());
}
}
Now i have a different bean, but it think it's the excact same structure:
package controller;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import lombok.Data;
import lombok.extern.java.Log;
import entities.Article;
import entities.Cart;
#SessionScoped
#Data
#Log
#Named
public class CartController implements Serializable {
private static final long serialVersionUID = 649140288918816488L;
#Inject
private UserController userController;
#Inject
private ArticleController articleController;
private Cart cart;
public void addToCart(Article article) {
cart.getArticleList().add(article);
cart.setSum(cart.getSum() + article.getPrice());
}
public void clearCart() {
cart.getArticleList().clear();
cart.setSum(0.0);
}
#PreDestroy
public void destroy() {
log.info("bean destroyed");
}
#PostConstruct
public void init() {
cart = new Cart();
log.info("new CartController instance");
}
public void removeFromCart(Article article) {
cart.getArticleList().remove(article);
cart.setSum(cart.getSum() - article.getPrice());
}
}
I can't explain it to myself, but the second bean is instanciated again and again and I can't store anything in it, because it get always a reference to another bean.
Please, help me to bring light in this mystery. If you need additional information, I would love to give it to you. Maybe, I have a big lack of understanding but for now, I can't help myself.
Gimby gave me the answer to this question. In fact, JBoss AS 7.1.0 Community Edition is outdated. With WildFly 8.0.0 Final, everything worked perfectly fine. So, if you're working with the fantastic possibilities of CDI, try WildFly instead of JBoss AS 7.1.0 Final Community.