I'm very new to Google Guice and I'm having troubles to get UserService instanced.
In my Playframework application, I have a service called UserService which looks like this:
public class UserService { // Note it doesn't implement an interface
private UserDao userDao;
private Email email;
#Inject
public UserService(UserDao userDao, Email email) {
this.userDao = userDao;
this.email = email;
}
...
}
I have this controller:
public class UserController extends Controller {
#Inject
private UserService userService;
...
}
I have this configure() definition for my UserModule:
protected void configure() {
bind(UserDao.class).to(UserDaoJpa.class);
bind(Email.class).to(EmailHtml.class);
bind(UserController.class);
}
I get the injector on Playframework Global object which looks similar to the example provided by Guillaume Bort about getting a controller instance, which in this case fits perfectly for getting the injector (the method getControllerInstance is a new feature in Play 2.1, but this is not relevant here). See here if interested:
public class Global extends GlobalSettings {
private static final Injector injector = createInjector();
#Override
public <A> A getControllerInstance(Class<A> controllerClass) throws Exception {
return injector.getInstance(controllerClass);
}
private static Injector createInjector() {
return Guice.createInjector(new UsuarioModule());
}
}
At this point, everything works perfectly, the service is correctly instantiated with its parameters resolved. The controller gets the object graph as expected.
But, when I try to do #Inject UserService userService somewhere else in the application I get null for userService. For example:
public class EmailAvailableValidator {
#Inject
private static UserService userService; // This is not resolved :(
public static Map<String, List<ValidationError>> validateEmailAndGetErrorsIfAny(String email, String emailField) {
Map<String, List<ValidationError>> errors = new HashMap<String, List<ValidationError>>();
if (!userService.isEmailAvailable(email)) {
List<ValidationError> list = new ArrayList<ValidationError>();
list.add(new ValidationError("", UsuarioResource.getMessageEmailTaken()));
errors.put(emailField, list);
}
return errors;
}
}
The question is, what is correct way to get an instance of an object that doesn't implement an interface? Is it always necessary to implement an interface?
Isn't it supposed that guice knows how to solved UserDao and Email? Why it is not able to instantiate it except in UserController?
I need this instance with its dependencies resolved, I mean with UserDao and Email into it.
The official guice docs were not very helpful for me.
Thanks for your help!
Two things:
You need to use a Guice Injector to instantiate EmailAvailableValidator. Your "Global" class is doing that already. Using the injector creates an instance and then sets all of its injected fields.
You might have to use the static injection to fill a static field. For example, in your configure() method add:
requestStaticInjection(UserService.class);
However, I haven't personally used it so YMMV.
Reference:
http://code.google.com/p/google-guice/wiki/Injections
Related
I'm trying to write a test in a Spring-Boot project. My problem is that I can't use my service that includes a constructor injection.
Depending on what I try I get errors like java.lang.IllegalStateException: Failed to load ApplicationContexts or NullPointerExceptions.
My first try was to change the constructor injection in my service to a field injection. But after reading this post I decided to change it back to the previous way.
Then I searched for examples but couldn't find something that was helpful.
Following are the relevant code snippets. If more code is needed I would provide it.
The service class with the constructor injection:
PlayerServiceImpl.java
#Service
public class PlayerServiceImpl implements PlayerService {
private PlayerRepository playerRepository;
private CompanyService companyService;
private CompanyResourceService companyResourceService;
#Autowired
public PlayerServiceImpl(PlayerRepository thePlayerRepository, CompanyService theCompanyService,
CompanyResourceService theCompanyResourceService) {
this.playerRepository = thePlayerRepository;
this.companyService = theCompanyService;
this.companyResourceService = theCompanyResourceService;
}
...
}
The test class im trying to create:
PlayerServiceImplIntegrationTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
public class PlayerServiceImplIntegrationTest {
#TestConfiguration
static class PlayerServiceImplTestContextConfiguration {
private PlayerRepository playerRepository;
private CompanyService companyService;
private CompanyResourceService companyResourceService;
#Bean
public PlayerService playerService() {
return new PlayerServiceImpl(playerRepository, companyService, companyResourceService);
}
}
#Autowired
private PlayerService playerService;
#MockBean
private PlayerRepository playerRepository;
#Before
public void setUp() {
Player max = new Player("MaxMustang", "test123", "MaxMustang",
"max.mustang#test.com", new Date(System.currentTimeMillis()), 1, 0,
new BigDecimal("0.00"), new BigDecimal("0.00"), 0, 0);
Mockito.when(playerRepository.findByUserName(max.getUserName()))
.thenReturn(max);
}
#Test
public void whenFindById_thenReturnPlayer() {
String userName = "MaxMustang";
Player found = playerService.findByUserName(userName);
assertThat(found.getUserName()).isEqualTo(userName);
}
}
In my test, I'm trying to create a player object and receive it. It's just my first test in Spring Boot. And my main goal was to just get the test running.
And the original test is from Baeldung from "5. Mocking with #MockBean". But while experimenting around, I added or changed a few things.
If I missed a post pointing at the same problem I would be glad to be informed about that.
Also, I would appreciate it if someone can tell me if the arguments in the constructor of my service are too much or still in an "ok" range.
You have to make the configuration bean primary and also use constructor injection on that method:
#TestConfiguration
static class PlayerServiceImplTestContextConfiguration {
#Bean
#Primary
public PlayerService playerService(PlayerRepository playerRepository,
CompanyService companyService, CompanyResourceService companyResourceService) {
return new PlayerServiceImpl(playerRepository, companyService, companyResourceService);
}
}
Without primary you will have two beans of same type floating around and you dont use #Qualifier here. Also you cannot #Autowire beans in a configuration class thats why you need to use constructor injection.
Here I am trying to mock autowire fields ServiceHelper of Service class TestServiceImpl , I am not able to call method through mock object of ServiceHelper class.
This is my class files:
#Service
public class TestServiceImpl implements TestService {
#Autowired
private TestDAO testDAO;
#Autowired
private ServiceHelper serviceHelper;
#Override
public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
return serviceHelper.getResults(map);
}
2nd Class:
#Repository
public class ServiceHelper {
private static Logger logger = Logger.getLogger(ServiceHelper.class.getName());
#Autowired
ResponseHeader responseHeader;
public void setResponseHeader(ResponseHeader responseHeader) {
this.responseHeader = responseHeader;
}
public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
....
}
And Test class:
#RunWith(MockitoJUnitRunner.class)
public class MockitoTester {
#InjectMocks
private TestServiceImpl serviceImpl = new TestServiceImpl();
#Mock
private TestDAO testDAO;
#Mock
private ServiceHelper sHelper;
#Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testResult() throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("TestId", "test123");
map.put("lang", "en");
map.put("cntry", "USA");
ResultsModel results = new ResultsModel();
when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
Assert.assertEquals(results.getStatus(), "Success");
}
Here in my test class:
results = serviceImpl.getResults(map);
It goes to TestServiceImpl class to method :
public ResultsModel getResults(Map<String, Object> map) throws webServiceException_Exception {
return serviceHelper.getResults(map);
}
but at point :
serviceHelper.getResults(map);
it is not going inside serviceHelper.getResults(map) and return all values as Null.
Please suggest where I need to do changes.
You have three choices here:
Do actual Spring autowiring in your tests
Use injection methods that can legitimately be performed by your tests (constructor parameters, public setters, public fields - in order of preference)
Use reflection to inject your mocks
Option 1 is really integration testing -- you can annotate your test class with #RunWith(SpringRunner.class) and use more Spring annotations to control dependency injection. It's too big a subject to cover in a SO answer, but there are plenty of examples if you Google for "spring integration test mockito".
But for unit testing, I think it's better not to involve Spring. A good Spring bean doesn't need Spring to function. Option 2 just says, write your class so that unit tests (and anything else) can inject the dependency (be it a mock, or anything else) through normal Java means.
Constructor injection is cleanest in my opinion:
private final ServiceHelper serviceHelper; // note: not annotated
#Autowired
public TestService(ServiceHelper serviceHelper) {
this.serviceHelper = serviceHelper;
}
But you can also do this with a public void setServiceHelper(ServiceHelper helper) -- this is less good because the field can't be final.
Or by making the field public -- I assume you know the reasons this is bad.
If you're determined to have a private field that's not set by a public constructor or setter, you could use Spring's ReflectionUtils.setField() from within your test:
#Mock
private ServiceHelper serviceHelper;
private TestService service;
#Before
public void configureService() {
service = new TestService();
Field field = ReflectionUtils.findField(TestService.class, "serviceHelper");
ReflectionUtils.setField(field, service, serviceHelper);
}
(Or, equally, use JDK's reflection classes directly, or reflection utils from elsewhere)
This is explicitly using reflection to subvert the access rules you've coded into the class. I thoroughly recommend option 2.
I think the issue may be that you are stubbing your method to return the same object which you then assign the result of the method under test. i.e. (the results object here):
ResultsModel results = new ResultsModel();
when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
This will probably cause some sort of cyclic confusion when it tries to stub the method in Mockito, and it certainly won't make your assertation pass:
Assert.assertEquals(results.getStatus(), "Success");
Since the status on results is never set anywhere.
I think you need to make separate objects for your stubbing and your returned value from the method under test and make sure you set your stubbed one to have a status of "Success":
ResultsModel results = new ResultsModel();
results.setStatus("Success");
when(sHelper.getResults(map)).thenReturn(results);
ResultsModel returnedResults = serviceImpl.getResults(map);
Assert.assertEquals(returnedResults.getStatus(), "Success");
Try using constructor injection it'd be easier to mock the classes for testing... here's an example on how I would structure my classes to get you going. When you write your tests you now have to pass the Mocked object into the instance you're creating of these classes:
#Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
private ServiceHelper serviceHelper;
#Autowired
public TestServiceImpl(TestDAO testDAO, ServiceHelper serviceHelper) {
this.testDAO = testDAO;
this.serviceHelper = serviceHelper;
}
}
#Repository
public class ServiceHelper {
private ResponseHeader responseHeader;
#Autowired
public ServiceHelper(ResponseHeader responseHeader) {
this.responseHeader = responseHeader
}
}
I need to create objects with user defined data at runtime.TO do that i have used
google guice assisted inject.But when i run my test it throws null pointer exception.Please let me know where i made the mistake.
IArtifacts Interface
public interface IArtifacts {
MavenMetaDataXMLDTO getArtifactsVersions();
}
ArtifactsService.java
public class ArtifactsService implements IArtifacts {
private ProductProfile productProfile;
#Inject
public ArtifactsService(#Assisted ProductProfile productProfile){
System.out.println(productProfile.getArtifactManagementURL());
this.productProfile=productProfile;
}
#Override
public MavenMetaDataXMLDTO getArtifactsVersions() {
System.out.println(productProfile.getArtifactManagementURL());
return null;
}
}
ArtifactsFactory Interface
public interface ArtifactsFactory {
IArtifacts create(ProductProfile productProfile);
}
Module Class
#Override
protected void configure() {
install(new FactoryModuleBuilder().implement(IArtifacts.class,ArtifactsService.class).build(ArtifactsFactory.class));
}
TestArtifacts.java
public class TestArtifacts {
#Inject // this obj is null
private ArtifactsFactory artifactsFactory;
private IArtifacts s;
public TestArtifacts(){
}
public void getdata(){
//Pass custom data to factory
this.s=artifactsFactory.create(Products.QA.get());
System.out.println(s.getArtifactsVersions());
}
}
REST ENDPOINT
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String getartifacts(){
new TestArtifacts().getdata();
}
you created an Instance of the class TestArtifacts on your own in your Rest Endpoint class but all of your classes need to be created by the Guice Framework and not by you.
So how should the Guice Framework inject something into your class when you create them with new? You also need to inject the class TestArtifacts into your Rest Endpoint and your Rest Endpoint has to be created by Guice too.
Update:
Maybe this link will help you
https://sites.google.com/a/athaydes.com/renato-athaydes/posts/jersey_guice_rest_api
I was able to fix it adding following code snippet to below TestArtifacts.java class
TestArtifacts.java
private Injector injector=Guice.createInjector(new MYModule());//where implemented configuration
#Inject
private ArtifactsFactory artifactsFactory=injector.getInstance(ArtifactsFactory.class);
In the project im working on, people wrote services class to access DAO.
Almost every business object has it's own service which use it's own DAO.
On some services, we are using references to other services.
At the moment, people are instantiating needed services inside the constructor.
But now, I have trouble because service A needs service B and service B needs service A so a call to either constructor results in stack overflow ...
Example (pseudo-code) :
//Constructor of OrderService
public OrderService() {
orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
itemService = new ItemService();
}
//Constructor of ItemService
public ItemService() {
itemDAO = DAOFactory.getDAOFactory().getItemDAO();
orderService = new OrderService();
}
How would you solve this ? using singleton pattern ?
Thanks
The Spring Framework solves this problem by using dependency injection. In short, what it does is to instantiate all the DAOs, and then set the dao-dependencies after instantiation, but before main business logic.
If you have to do this manually, here's an example:
/*
OrderService
*/
public OrderService ()
{
orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
}
public setItemService (ItemService service)
{
itemService = service;
}
/*
ItemService
*/
public ItemService ()
{
itemDAO = DAOFactory.getDAOFactory().getItemDAO();
}
public setOrderService (OrderService service)
{
orderService = service;
}
/*
Bring it together in some other class
*/
...
// instantiate singletons
orderService = new OrderService ();
itemService = new ItemService ();
// inject dependencies
orderService.setItemService (itemService);
itemService.setOrderService (orderService);
Let the OrderService just do things with orders. Let the ItemService just do things with items. Then create a OrderItemService which combines the two.
Yes, the "singleton pattern" along with lazy initialisation will do. Don't initialise services in the constructor, but in static getters:
class OrderService {
private static OrderService instance;
private OrderDAO orderDAO;
public OrderService() {
orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
}
public static synchronized OrderService getInstance() {
if (instance == null) {
instance = new OrderService();
}
return instance;
}
}
As Jonathan stated, you can also inject services to other services, but that might not be needed. If synchronisation is prone to lead to a memory issue, you can resolve this using volatile. See also this answer here, elaborating on the "double-checked locking pattern" (be careful though, to get this right!)
Can you separate out the "service" from the Constructor?
Or in other words, lets say you have an OrderService and it needs to consult its own personal copy of an ItemService. Will this ItemService instance need it's own copy of the OrderService to fulfill the request from the OrderService calling it?
Thus, it would be a sort of lazy initialization--don't create the new item unless and until you actually need it. And don't link up the additional service unless and until you need it.
Second idea: can you pass a copy as part of the Constructor?
e.g.:
//Constructor of OrderService public OrderService()
{ orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
itemService = new ItemService(this);
}
//Constructor of ItemService public ItemService(OrderService orderService)
{ itemDAO = DAOFactory.getDAOFactory().getItemDAO();
this.orderService = orderService;
}
Or possibly in the reverse direction?
I've got a page with a form in Wicket where the form requires a collaborator to get its job done. The collaborator is injected (for which I'm using Guice) and looks something like:
public class RegistrationPage extends WebPage {
#Inject
public RegistrationPage(RegistrationService service) {
this.service = service;
add(new RegistrationForm());
}
private class RegistrationForm extends Form {
public RegistrationForm() {
// setup
}
protected void onSubmit() {
service.doSomething();
}
}
}
I don't like the idea that the RegistrationService is injected into the RegistrationPage when it's just the RegistrationForm that needs it. I could change the RegistrationForm to receive the RegistrationService:
public RegistrationForm(RegistrationService service) {
this.service = service;
}
and remove the field from the RegistrationPage, but the RegistrationPage is still being used to do the pass-through.
I guess what I'm asking is what the best-practise is for doing this? Is this ok to do, or would it perhaps be better to inject the RegistrationForm itself into the Page:
public class RegistrationPage extends WebPage {
#Inject
public RegistrationPage(RegistrationForm form) {
add(form);
}
}
---
private class RegistrationForm extends Form {
private RegistrationService service;
#Inject
public RegistrationForm(RegistrationService service) {
this.service = service;
}
protected void onSubmit() {
service.doSomething();
}
}
I'd prefer this as I'd like to have the RegistrationForm in a separate class/file. I'm quite new to Wicket so unsure of what the norm is - can someone show me the guiding light? :)
the basic paradigm with wicket+ioc is: most dependencies should be injected via setter injection. constructor injection is impossible for WebPages.
components/panels/forms/pages should only be on the recieving end.
so, inject the dependency to RegistrationService happily into the RegistrationForm , then create it in the RegistrationPage with add(new RegistrationForm());
wicket has IComponentInstantiationListener - one of them is guice. they get notified during the constructor of each component/webpage. so your RegistrationForm will have its dependencies injected before any part of your code can execute.
the way i would do it:
(of course RegistrationForm can be in another file)
public class RegistrationPage extends WebPage {
#Inject
public RegistrationPage() {
add(new RegistrationForm());
}
---
private static class RegistrationForm extends Form {
RegistrationService service;
#Inject
public void setRegistrationService (RegistrationService service){
this.service = service;
}
public RegistrationForm() {
// setup
}
protected void onSubmit() {
service.doSomething();
}
}
}
if you decide to put the RegistrationForm inside the Page as inner class, remember to declare it static! you will most likely not need any references to the enclosing class.
In my opinion DI on Wicket has one confusing element, is done automagically on Components or Pages but not in Models. In my opinion exactly Model (but not page) should have dependency to JPA etc.
Official doc say to use InjectorHolder.getInjector().inject(this)