I need to #Autowire database services or repositores form "database" module in "game" module.
Already added those annotations in main "Application" class:
#Configuration
#EnableMethodSecurity
#SpringBootApplication
#EnableAutoConfiguration
#EntityScan(basePackages="com.rydzwr.tictactoe")
#ComponentScan(basePackages="com.rydzwr.tictactoe")
#EnableJpaRepositories(basePackages="com.rydzwr.tictactoe")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Adding them in constructor is much more difficult, becouse I'm need to create list of instances of those classes in StrategySelector:
#Service
public class GameStrategySelector {
private final List<BuildGameStrategy> strategyList = asList(
new LocalPlayerGameStrategy(),
new MultiPlayerGameStrategy()
);
public BuildGameStrategy chooseStrategy(GameDto gameDto) {
return strategyList
.stream()
.filter(strategy -> strategy.applies(gameDto))
.findFirst()
.orElse(new ErrorGameTypeStrategy());
}
}
Or, maybe someone has better idea, for StrategySelector logic?
Here is class with given problem:
#Component
public class LocalPlayerGameStrategy implements BuildGameStrategy {
#Autowired
private GameService gameService;
#Autowired
private UserService userService;
#Autowired
private PlayerService playerService;
#Override
#Transactional
public void buildGame(GameDto gameDto) {
Game game = new GameBuilder(gameDto.getGameSize(), gameDto.getGameDifficulty()).build();
gameService.save(game);
User caller = userService.findByName(SecurityContextHolder.getContext().getAuthentication().getName());
assert caller != null;
for (PlayerDto playerDto : gameDto.getPlayers()) {
Player player = new PlayerBuilder().setGame(game).setUser(caller).setPlayerDetails(playerDto).build();
playerService.save(player);
}
game.setState(GameState.IN_PROGRESS);
gameService.save(game);
}
#Override
public boolean applies(GameDto gameDto) {
return gameDto.getPlayers().stream().allMatch(p -> p.getPlayerType().equals(PlayerType.LOCAL.name()));
}
}
I tried to autowire repositores and services with implemented logic as well.
Every time all of them:
#Autowired
private GameService gameService;
#Autowired
private UserService userService;
#Autowired
private PlayerService playerService;
ARE NULL
I tried everything I found on google
You can't create new instances of LocalPlayerGameStrategy and MultiPlayerGameStrategy inside GameStrategySelector they won't be spring beans so they can't #Autowire other beans.
Modify your GameStrategySelector to inject all BuildGameStrategy instead of creating them manually
#Service
public class GameStrategySelector {
private final List<BuildGameStrategy> strategyList;
public GameStrategySelector(List<BuildGameStrategy> allStrategies){
strategyList = allStrategies;
}
public BuildGameStrategy chooseStrategy(GameDto gameDto) {
return strategyList
.stream()
.filter(strategy -> strategy.applies(gameDto))
.findFirst()
.orElse(new ErrorGameTypeStrategy());
}
}
Related
We have to test class, see below. Our question is how can we fill the dependencies, so that we can test the original class you see below.
public class FragenAntwortenDataprovider extends SortableDataProvider<FragenAntworten, String> {
#SpringBean
private IFragenAntwortenService service;
private IModel<FragenAntworten> filter;
public FragenAntwortenDataprovider(IModel<FragenAntworten> filter){
this.filter = filter;
Injector.get().inject(this);
setSort("id", SortOrder.DESCENDING); // absteigend sortieren
}
#Override
public Iterator<? extends FragenAntworten> iterator(long first, long count){
List<FragenAntworten> list = load();
List<FragenAntworten> sublist = list.subList((int) first, (int) (first+count));
return sublist.iterator();
}
#Override
public long size() {return getListSize();}
#Override
public IModel<FragenAntworten> model(FragenAntworten object) {
return Model.of(object);
}
private void sort(final List<FragenAntworten> list){
}
private long getListSize(){
List<FragenAntworten> list = service.ladeAlle(filter.getObject().getSystem());
return list.size();
}
private List<FragenAntworten> load(){
List<FragenAntworten> list = service.ladeAlle(filter.getObject().getSystem());
return list;
}
}
Since you use Spring you can use its ReflectionUtils helper class to inject the dependency:
IFragenAntwortenService service = mock(IFragenAntwortenService.class);
IModel<FragenAntworten> model = ...;
FragenAntwortenDataprovider provider = new FragenAntwortenDataprovider(model);
Field serviceField = ReflectionUtils.findField("service", provider);
ReflectionUtils.setField(serviceField, provider, service);
Another option is to introduce package-private setter for service field and avoid using reflection.
You should have your original class have the dependencies injected with #Autowired or #Inject. Actually you should not use field injection, but constructor injection. Then you should use the #ExtendWith(MockitoExtension.class) for the JUnit 5 test class. Every dependency you have to define as a #Mock and for the class you wish to test you use the #InjectMocks annotation.
This is the constructor injection to use:
public class FragenAntwortenDataprovider extends SortableDataProvider<FragenAntworten, String> {
private IFragenAntwortenService service;
private IModel<FragenAntworten> filter;
#Inject
public FragenAntwortenDataprovider(IFragenAntwortenService service, IModel<FragenAntworten> filter){
this.service = service;
this.filter = filter;
//I guess you don't need the injector anymore
//Injector.get().inject(this);
setSort("id", SortOrder.DESCENDING); // absteigend sortieren
}
//Rest of class
}
And this is then a test-class:
#ExtendWith(MockitoExtension.class)
public class testClass() {
#Mock
private IFragenAntwortenService service;
#Mock
private IModel<FragenAntworten> filter;
#InjectMocks
FragenAntwortenDataprovider sut; //System under Test
#Test
void test() {
//Testcode
// Control the mock with
when(service.anymethod()).thenReturn(result);
var result = sut.callMethodToTest();
// verify all calls
verify(service, times(1)).anymethod();
// and assert
assertNotNull(result);
}
}
I had already tried solutions mentioned in Why is my Spring #Autowired field null? yet the problem persists. I have tried annotating the class DevicePojo(code below) with #Configurable #Service.
Here are my beans
DistributionConfig.java
#Component
#Configuration
public class DistributionConfig {
#Qualifier("exponentialDistribution")
#Bean
#Scope("prototype")
public DistributionService exponentialDistribution() {
return new ExponentiallyDistribute();
}
#Qualifier("normalDistribution")
#Bean
#Scope("prototype")
public DistributionService normalDistribution() {
return new NormallyDistribute();
}
#Qualifier("uniformDistribution")
#Bean
#Scope("prototype")
public DistributionService uniformDistribution() {
return new UniformlyDistribute();
}
}
JsonFileConfig.java
#Configuration
public class JsonFileConfig {
private static ObjectMapper mapper=new ObjectMapper();
#Qualifier("devicesPojo")
#Bean
public DevicesPojo[] devicesPojo() throws Exception {
DevicesPojo[] devicePojo=mapper.readValue(new File(getClass().getClassLoader().getResource("Topo/esnet-devices.json").getFile()),DevicesPojo[].class);
return devicePojo;
}
#Qualifier("linksPojo")
#Bean
public LinksPojo[] linksPojo() throws Exception {
LinksPojo[] linksPojo=mapper.readValue(new File(getClass().getClassLoader().getResource("Topo/esnet-adjcies.json").getFile()),LinksPojo[].class);
return linksPojo;
}
}
Here is my DevicePojo where i get the null pointer exception.
#JsonDeserialize(using = DeviceDeserializer.class)
#Component
public class DevicesPojo {
private String device;
private List<String> ports;
private List<Integer> bandwidth;
#Autowired
#Qualifier("uniformDistribution")
private DistributionService uniformDistribution; // Here uniformDistribution is null
public DevicesPojo(String device, List<String> port, List<Integer> bandwidth) {
this.device = device;
this.ports= port;
this.bandwidth=bandwidth;
this.uniformDistribution.createUniformDistribution(1000,0,ports.size());
}
public String getDevice(){
return device;
}
public String getRandomPortForDevice()
{
return ports.get((int)uniformDistribution.getSample());
}
public List<String> getAllPorts(){
return ports;
}
public int getBandwidthForPort(String port){
return bandwidth.get(ports.indexOf(port));
}
}
However, if i replace private DistributionService uniformDistribution;with private DistributionService uniformDistribution=new UniformDistribution() the code is working fine.
There is a mix of problems here.
1. You create your DevicesPojo objects using JSON deserializer. Spring has no chance to interfere and inject the DistributionService.
2. Even if it could interfere, it would fail, since you are trying to use the 'distributionService' object in the constructor. Field injection would work only after an object is constructed.
Now regarding fixing the problems.
Long answer short - don't expect auto-injection in your POJOs.
Normally, dependencies like 'distributionService' in objects that are created on the fly, like your DevicesPojo are avoided altogether.
If you insist on having them, inject them manually at construction time:
class DevicesPojoFactory {
#Autowired #Qualifier("uniformDistribution")
private DistributionService uniformDistribution;
ObjectMapper mapper = new ObjectMapper();
DevicesPojo[] readFromFile(String path) {
DevicesPojo[] devicePojoArr = mapper.readValue(...);
for (DevicesPojo dp: devicePojoArr) {
dp.setDistribution(uniformDistribution);
}
}
}
I have a controller
#RestController
public class Create {
#Autowired
private ComponentThatDoesSomething something;
#RequestMapping("/greeting")
public String call() {
something.updateCounter();
return "Hello World " + something.getCounter();
}
}
I have a component for that controller
#Component
public class ComponentThatDoesSomething {
private int counter = 0;
public void updateCounter () {
counter++;
}
public int getCounter() {
return counter;
}
}
I also have a test for my controller.
#RunWith(SpringRunner.class)
#SpringBootTest
public class ForumsApplicationTests {
#Test
public void contextLoads() {
Create subject = new Create();
subject.call();
subject.call();
assertEquals(subject.call(), "Hello World 2");
}
}
The test fails when the controller calls something.updateCounter(). I get a NullPointerException. While I understand it's possible to add #Autowired to a constructor I would like to know if there is anyway to do this with an #Autowired field. How do I make sure the #Autowired field annotation works in my test?
Spring doesn't auto wire your component cause you instantiate your Controller with new not with Spring, so Component is not instatntiated
The SpringMockMvc test check it correct:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class CreateTest {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
#Test
public void testCall() throws Exception {
//increment first time
this.mvc.perform(get("/greeting"))
.andExpect(status().isOk());
//increment secont time and get response to check
String contentAsString = this.mvc.perform(get("/greeting"))
.andExpect(status().isOk()).andReturn()
.getResponse().getContentAsString();
assertEquals("Hello World 2", contentAsString);
}
}
The #Autowired class can be easily mocked and tested with MockitoJUnitRunner with the correct annotations.
With this you can do whatever you need to do with the mock object for the unit test.
Here is a quick example that will test the Create method call with mocked data from ComponentThatDoesSomething.
#RunWith(MockitoJUnitRunner.class)
public class CreateTest {
#InjectMocks
Create create;
#Mock
ComponentThatDoesSomething componentThatDoesSomething;
#Test
public void testCallWithCounterOf4() {
when(componentThatDoesSomething.getCounter()).thenReturn(4);
String result = create.call();
assertEquals("Hello World 4", result);
}
}
Use Mockito and inject a mock that you create. I would prefer constructor injection:
#RestController
public class Create {
private ComponentThatDoesSomething something;
#Autowired
public Create(ComponentThatDoesSomething c) {
this.something = c;
}
}
Don't use Spring in your Junit tests.
public CreateTest {
private Create create;
#Before
public void setUp() {
ComponentThatDoesSomething c = Mockito.mock(ComponentThatDoesSomething .class);
this.create = new Create(c);
}
}
I am working with Spring MVC application.
I want to create new event:
fill data at page > controller handle this info > saving new event to DB
I have already created DAO layer and repository layer. But at some places, it behaves very strangely. I have created Java configuration for all repositories in the same way.
Here is Repositories Configuration snippet:
#Configuration
#ComponentScan({ "net.lelyak.edu.repository", "net.lelyak.edu.service" })
#Import({ DatabaseDAOConfiguration.class })
public class ApplicationConfiguration {
#Autowired
private UserDAO userDAO;
#Autowired
private EventDAO eventDAO;
#Autowired
private TicketDAO ticketDAO;
#Autowired
private AuditoriumDAO auditoriumDAO;
#Bean
public AuditoriumRepository auditoriumRepository() {
AuditoriumRepository auditoriumRepository = new AuditoriumRepository();
auditoriumRepository.setDao(auditoriumDAO);
return auditoriumRepository;
}
#Bean
public EventRepository eventRepository() {
EventRepository eventRepository = new EventRepository();
eventRepository.setDao(eventDAO);
return eventRepository;
}
I have faced strange behavior at the controller level.
Here is controller code snippet:
#Controller
#RequestMapping("events")
public class EventsController {
#Autowired
private AuditoriumRepository auditoriumRepository;
#Autowired
private EventRepository eventRepository;
#RequestMapping(path = "add", method = RequestMethod.POST)
public String addEvent(#RequestParam Map<String, String> allRequestParams) {
Event newEvent = new Event();
// get auditorium id from request
String auditoryIdString = allRequestParams.get("auditorium");
Long auditoryId = Long.parseLong(auditoryIdString);
Auditorium auditorium = auditoriumRepository.getById(auditoryId);
newEvent.setAuditorium(auditorium);
AuditoriumRepository is auto-wired fine.
Here is snippet from debug view:
but EventRepository isn't:
Configuration is the same for both. One repository is auto-wired fine, second fails. I am newly at Spring. I can't get a clue why does this happen?
Here is snippet of code from EventRepository:
public class EventRepository extends BaseRepository<Event, EventDAO> {
#Autowired
private AuditoriumRepository auditoriumRepository;
#Override
public int put(Event entity) {
auditoriumRepository.put(entity.getAuditorium());
return super.put(entity);
}
AuditoriumRepository code snippet:
public class AuditoriumRepository extends BaseRepository<Auditorium, AuditoriumDAO> {
#Override
public Auditorium preSave(Auditorium entity) {
return entity;
}
For saving new event to DB I have to use exactly EventRepository. It fails, of course, with following stack trace:
java.lang.NullPointerException
at net.lelyak.edu.repository.BaseRepository.put(BaseRepository.java:23)
at net.lelyak.edu.repository.EventRepository.put(EventRepository.java:20)
at net.lelyak.edu.repository.EventRepository$$FastClassBySpringCGLIB$$5de8d2a5.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
I am using spring 4.2.4.RELEASE on Windows 10.
UPDATE:
BaseRepository code snippet:
public abstract class BaseRepository<T extends BaseEntity, E extends BaseDAO<T>> {
private E dao;
public E getDao() {
return dao;
}
public void setDao(E dao) {
this.dao = dao;
}
public int put(T entity) {
return dao.save(preSave(entity));
}
I can't understand why with the same configuration and repository structure. One instance is auto-wired by Spring fine, but the second one fails. How to find the root of this problem? And some solution.
UPDATE 2:
I have tried recommended solution, and added next setter to EventRepository:
public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository) {
System.out.println("EventRepository.setAuditoriumRepository");
this.auditoriumRepository = auditoriumRepository;
}
As log message show this setter is executed. But keep failing for the same reason.
How to solve this issue?
i saw your code and the problem is not related to Spring and autowiring process. The problem is in your save method in BaseDAO class:
#Override
public Integer save(ENTITY entity) {
if (entity.getId() == null) {
insert(entity);
} else {
update(entity);
}
return null;
}
if you change the metod to return newly inserted/updated entity id it will work fine.
try to hardcode it just for test :
#Override
public Integer save(ENTITY entity) {
if (entity.getId() == null) {
insert(entity);
} else {
update(entity);
}
return 1;
}
and the problem is raised when you return null from save method then you are doing assignment in the EventsController class which is:
int eventId = eventRepository.put(newEvent); //this is null and throws NullPointerException because you are trying to assign null to primitive variable.
Try to inject the dependencies yourself in the Java #Configuration class. Update your EventRepository so that it has a setter method for the AuditoriumRepository dependency as follows
public class EventRepository extends BaseRepository<Event, EventDAO> {
private AuditoriumRepository auditoriumRepository;
#Override
public int put(Event entity) {
auditoriumRepository.put(entity.getAuditorium());
return super.put(entity);
}
public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository){
this.auditoriumRepository=auditoriumRepository;
}
}
In your ApplicationConfiguration update as follow:
#Bean
public EventRepository eventRepository() {
EventRepository eventRepository = new EventRepository();
eventRepository.setDao(eventDAO);
eventRepository.setAuditoriumRepository(auditoriumRepository());
return eventRepository;
}
The null pointer exception is because auditoriumRepository is not set in the eventRepository bean.
So while creating the EventRepository bean in ApplicationConfiguration.java, we need to set auditoriumRepository as well.
For this I have updated ApplicationConfiguration as below:
public EventRepository eventRepository() {
EventRepository eventRepository = new EventRepository();
eventRepository.setDao(eventDAO);
eventRepository.setAuditoriumRepository(auditoriumRepository());
return eventRepository;
}
and added setter for auditoriumRepository in the EventRepository class
public AuditoriumRepository getAuditoriumRepository() {
return auditoriumRepository;
}
public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository) {
this.auditoriumRepository = auditoriumRepository;
}
This will ensure that the NPE you are seeing will be resolved.
But subsequently we will still get the NPE at a different point now and i.e., at BaseDAO class. The save method is returning a null object and that is causing this NPE.
To resolve this, I have updated the save method of BaseDAO to return a dummy value of 1. You may want to return an appropriate value as per you application needs.
public Integer save(ENTITY entity) {
if (entity.getId() == null) {
insert(entity);
} else {
update(entity);
}
return 1;
}
With these changes, we will able to save the event and proceed to the next screen.
I have a little problem. I think this is typical question. However, I can't find good example. My application is using Jersey. And I want to test controller by client as test. Controller has private field - StudentService. When I debug test I see, that field is null. This leads to error. And I need to inject this field. I tried this:
My Controller
#Path("/student")
#Component
public class StudentResourse {
#Autowired
private StrudentService service; // this field Spring does not set
#Path("/getStudent/{id}")
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(#PathParam("id") long id) {
return service.get(id);
}
}
My JUnit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:config.xml")
#TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
private static final String PACKAGE_NAME = "com.example.servlet";
private static final String FILE_DATASET = "/data.xml";
#Autowired
private StudentService service; // this field is setted by Spring, but I do not need this field for test
public StudentResourseTest() {
super(new WebAppDescriptor.Builder(PACKAGE_NAME).build());
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
#Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("restful.server.resource")
.contextParam("contextConfigLocation",
"classpath:/config.xml").contextPath("/")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build();
}
#Test
#DatabaseSetup(FILE_DATASET)
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource().path("student").path("getStudent")
.path("100500").accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
} }
I guees, that problem is in test class. Because, when I run my application not in test, I can directly request students and everything working fine. But when I test classes, internal field of Controller does not setted. How to fix this bug? Thanks for your answers.
This is in my config.xml
<context:component-scan base-package="com.example" />
<bean id="StudentResourse" class="com.example.servlet.StudentResourse">
<property name="service" ref="studentService" />
</bean>
<bean id="service" class="com.example.service.StudentServiceImpl" />
One issue may be that you're trying to configure your test application in constructor and in configure() method. Use one or another but not both because in this case your configure() method is not invoked and hence you may not be using SpringServlet and everything that is defined in this method.
Reference: https://github.com/jiunjiunma/spring-jersey-test and http://geek.riffpie.com/unit-testing-restful-jersey-services-glued-together-with-spring/
Idea is to get a hold of the application context inside jersey by using ApplicationContextAware interface. There after we can grab the exact bean already created by spring, in your case, StudentService. Below example shows a mocked version of the dependency, SampleService, used to test the resource layer apis.
Resource class delegating the processing to a service layer
#Component
#Path("/sample")
public class SampleResource {
#Autowired
private SampleService sampleService;
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path ("/{id}")
public Sample getSample(#PathParam("id") int id) {
Sample sample = sampleService.getSample(id);
if (sample == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return sample;
}
}
Service layer encapsulating business logic
#Service
public class SampleService {
private static final Map<Integer, Sample> samples = new HashMap<>();
static {
samples.put(1, new Sample(1, "sample1"));
samples.put(2, new Sample(2, "sample2"));
}
public Sample getSample(int id) {
return samples.get(id);
}
}
Unit test for the above resource
public class SampleResourceTest extends SpringContextAwareJerseyTest {
private SampleService mockSampleService;
// create mock object for our test
#Bean
static public SampleService sampleService() {
return Mockito.mock(SampleService.class);
}
/**
* Create our own resource here so only the test resource is loaded. If
* we use #ComponentScan, the whole package will be scanned and more
* resources may be loaded (which is usually NOT what we want in a test).
*/
#Bean
static public SampleResource sampleResource() {
return new SampleResource();
}
// get the mock objects from the internal servlet context, because
// the app context may get recreated for each test so we have to set
// it before each run
#Before
public void setupMocks() {
mockSampleService = getContext().getBean(SampleService.class);
}
#Test
public void testMock() {
Assert.assertNotNull(mockSampleService);
}
#Test
public void testGetSample() {
// see how the mock object hijack the sample service, now id 3 is valid
Sample sample3 = new Sample(3, "sample3");
Mockito.when(mockSampleService.getSample(3)).thenReturn(sample3);
expect().statusCode(200).get(SERVLET_PATH + "/sample/3");
String jsonStr = get(SERVLET_PATH + "/sample/3").asString();
Assert.assertNotNull(jsonStr);
}
}
SpringContextAwareJerseyTest
#Configuration
public class SpringContextAwareJerseyTest extends JerseyTest {
protected static String SERVLET_PATH = "/api";
final private static ThreadLocal<ApplicationContext> context =
new ThreadLocal<>();
protected String getResourceLocation() {
return "example.rest";
}
protected String getContextConfigLocation() {
return getClass().getName();
}
static private String getContextHolderConfigLocation() {
return SpringContextAwareJerseyTest.class.getName();
}
protected WebAppDescriptor configure() {
String contextConfigLocation = getContextConfigLocation() + " " +
getContextHolderConfigLocation();
Map<String, String> initParams = new HashMap<>();
initParams.put("com.sun.jersey.config.property.packages",
getResourceLocation());
initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true");
return new WebAppDescriptor.Builder(initParams)
.servletClass(SpringServlet.class)
.contextParam(
"contextClass",
"org.springframework.web.context.support.AnnotationConfigWebApplicationContext")
.contextParam("contextConfigLocation", contextConfigLocation)
.servletPath(SERVLET_PATH) // if not specified, it set to root resource
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
protected final ApplicationContext getContext() {
return context.get();
}
#Bean
public static ContextHolder contextHolder() {
return new ContextHolder();
}
private static class ContextHolder implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context.set(applicationContext);
}
}
}
Using the above with jersey 1.8