Java circular references - java

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?

Related

How do I create multiple Spring beans of the same type without defining each one

I've seen a lot of workaround-looking things regarding what I'm trying to do using BeanDefinitionRegistryPostProcessor, but I wondered if there was a way to tap directly into Spring's bean creation API to override some behavior.
What I would like to see is something like this (note the 's' in #Components):
#Components(prefix="myBean-", numberOfInstances="${myapp.mybean.numberOfInstances}")
public class MyBean {
private final MyService myService;
public MyBean(final MyService myService) {
this.myService = myService;
}
#Scheduled(fixedDelayString = "${myapp.mybean.fixedDelay}")
public myJob() {
System.out.println("I'm working!");
}
}
I am basically looking for the same functionality of #Component where I can specify how many instances to make and just have the name generated.
As I mentioned before, the only way I have found to do this sort of thing (specifically for scheduled tasks now) is to use the BeanDefinitionRegistryPostProcessor to create the instances or create a custom SchedulingConfigurer to configure the tasks manually without using Spring beans, which means all the Runnable's dependencies have to be wired into the SchedulingConfigurer, and that just feels dirty.
Is this even possible--to add a new annotation to scan for and invoke some other way to create the beans?
Update
Thanks to #vince for helping me realize I don't need a separete bean for each job; I just have to configure the singleton multiple times into the FixedDelayTask.
#Component
public class MyBean {
private final MyService myService;
public MyBean(final MyService myService) {
this.myService = myService;
}
// Remove #Scheduled here since we have to configure multiple
// instances manually. This is where it would be nice to specify
// how many jobs of the same type you want.
// #Scheduled(fixedDelayString = "${myapp.mybean.fixedDelay}")
public myJob() {
System.out.println("I'm working!");
}
}
#Configuration
#EnableScheduling
public class MyBeanTaskConfiguration implements SchedulingConfigurer {
private final MyBean myBean;
public MyBeanTaskConfiguration(MyBean myBean) {
this.myBean = myBean;
}
#Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
for (int i = 0; i < numberOfWorkers; i++) {
taskRegistrar.scheduleFixedDelayTask(
new FixedDelayTask(
myBean,
repeatIntervalMs,
repeatIntervalMs / numberOfWorkers * i + startDelayMs
)
);
}
}
}
Actually I'm wondering why u wanna do this. According to the IOC philosophy, beans should be delegated to container and clients don't need to care about beans' lifecycles. That's why Spring provides #Scope to support different bean scopes like singleton/request/session. So I don't think it a good way to control the specific number of a certain bean, besides, beans should theoretically be non-stateful, thus a single instance is fairly enough.
Prototype scoped beans will be provided as a new instance for each request to the container.
#Component
#Scope("prototype")
public class MyBean {
private final MyService myService;
public MyBean(final MyService myService) {
this.myService = myService;
}
// ...
}
// Get two separate instances
MyBean bean1 = (MyBean)applicationContext.getBean("myBean");
MyBean bean2 = (MyBean)applicationContext.getBean("myBean");

How to create a test in Springt Boot that calls a service which includes constructor injection?

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.

How to inject the mock of an object which is declared as private static in the class under test in java?

I have a class ManageUser as below:
public class ManageUser {
private static UserBO gUserBO = new UserBO();
public String method1() {
gUserBO.callSomeFunction();
gUserBO.callSomeOtherFunction();
}
}
Now, I have a test class where I want to test method1() and since the methods callSomeFunction() and callSomeOtherFunction() end up making database calls I want to mock the calls to those methods. I am unable to do that by using mock since the object in ManageUser is static. How do I proceed? I am new to Junit and Mockito and can't seem to find relevant answers.
Try using Power Mockito:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ManageUser.class})
public class ClassInTest {
#Test
public void testStatic() {
ManageUser mUser = new ManageUser();
Field field = PowerMockito.field(ManageUser.class, "gUserBO");
field.set(ManageUser.class, mock(UserBO.class));
...
}
}
You are "unable to do that by using mock" because your class is badly designed. As a workaround, you could use PowerMock (as #S.K. suggested) to mock the static field but that will only suppress the real problem of your class.
Better take the chance and improve the code for better testability and evolvability:
Step 1: Create an interface for your class UserBO and let it implement it.
public interface UserService {
void callSomeFunction();
void callSomeOtherFunction();
}
public class UserBO implements UserService { ... }
Step 2: Change your class ManageUser to get any implementation of UserService through a constructor.
public class ManageUser {
private final UserService userService;
public ManageUser(UserService userService) {
this.userService = userService;
}
public String method1() {
userService.callSomeFunction();
userService.callSomeOtherFunction();
}
}
Step 3: Change the calling side of your class ManageUser to provide a UserService.
So instead of
ManageUser manager = new ManageUser();
use
ManageUser manager = new ManageUser(new UserBO());
Step 4: Now you can easily mock a UserService in your test and construct a ManageUser with the mock.
This design also enables DI frameworks (e.g. Spring) to inject (or autowire) the components.

how to mock autowire fields using mockito

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
}
}

Basic Google Guice injection. Playframework 2.1

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

Categories

Resources