How bad is a service circular reference? - java

I have a question and it is related to the error that I am getting. How bad is it really to have a circular reference in my service? I know very well what the error is due to and how to possibly solve it, only that in the company where I work a Senior recommended me that for transactional issues it is necessary to make such a circular reference and in fact it is a very recurrent practice there, but as I am starting a personal project from scratch is the first time I get the error and it triggered the doubt again. Thank you very much in advance!
Here is the code of the service
public class MedicalRecordServiceImpl implements MedicalRecordService {
private final MedicalRecordRepository medicalRecordRepository;
private final MedicalRecordService medicalRecordService;
private final PatientService patientService;
private final TutorService tutorService;
private final MedicalHistoryAnswerService medicalHistoryAnswerService;
private final DentalHistoryAnswerService dentalHistoryAnswerService;
public MedicalRecordServiceImpl(MedicalRecordRepository medicalRecordRepository, MedicalRecordService medicalRecordService, PatientService patientService, TutorService tutorService, MedicalHistoryAnswerService medicalHistoryAnswerService, DentalHistoryAnswerService dentalHistoryAnswerService) {
this.medicalRecordRepository = medicalRecordRepository;
this.medicalRecordService = medicalRecordService;
this.patientService = patientService;
this.tutorService = tutorService;
this.medicalHistoryAnswerService = medicalHistoryAnswerService;
this.dentalHistoryAnswerService = dentalHistoryAnswerService;
}
#Override
#Transactional(propagation = Propagation.REQUIRED)
public void saveMedicalRecord(MedicalRecordEntity medicalRecord) {
medicalRecordRepository.save(medicalRecord);
}
#Override
#Transactional(propagation = Propagation.REQUIRED)
public ResponseEntity<?> createNewMedicalRecord(MedicalRecordDTO medicalRecordDTO) {
PatientEntity patient = this.storeMedicalRecordIntoPatient(medicalRecordDTO);
TutorEntity tutor = this.storeMedicalRecordIntoTutor(medicalRecordDTO);
List<MedicalHistoryAnswerEntity> medicalHistoryAnswers = this.storeMedicalRecordIntoMedicalHisAns(medicalRecordDTO);
List<DentalHistoryAnswerEntity> dentalHistoryAnswers = this.storeMedicalRecordIntoDentalHisAns(medicalRecordDTO);
patientService.savePatient(patient);
tutor.setPatient(patient);
tutorService.saveTutor(tutor);
MedicalRecordEntity medicalRecord = this.createMedicalRecord(patient, tutor);
medicalRecordService.saveMedicalRecord(medicalRecord);
medicalHistoryAnswers.forEach(medicalHistoryAnswer -> {
medicalHistoryAnswer.setMedicalRecord(medicalRecord);
medicalHistoryAnswerService.saveMedicalHistoryAnswer(medicalHistoryAnswer);
});
dentalHistoryAnswers.forEach(dentalHistoryAnswer -> {
dentalHistoryAnswer.setMedicalRecord(medicalRecord);
dentalHistoryAnswerService.saveDentalHistoryAnswer(dentalHistoryAnswer);
});
return ResponseEntity.status(HttpStatus.OK).body("");
}
}

The only reason why you may need circular dependency is the case when you want to access to "this" as to a bean to trigger annotated method logic.
For example if you have two methods "foo" (annotated with #Transactional) and "bar" (invokes "foo" within). You will have to use self injection to trigger transaction in case of invocation bar>foo (selfBean.foo() instead of this.foo()).
Also you can use #Lasy for self injection to avoid the circular dependency error.
But it's a pretty ugly solution and you should avoid it if it's possible. It depends on the situation, may be it's possible to split logic to different services or use TransactionTemplate.

As you said, I will assume that you know what the error is and how to resolve it. A circular reference is bad for the following reason:
Spring loads beans the moment you start the project, meaning it loads each bean in the correct order so it can load all beans and references them successfully. If you have a circular reference Spring won't know with which bean to start first, and so the error occurs. It's about how Spring works.
I also had this error in my current project and you are not limited to not making the circular reference, you just need to instruct Spring, so that it knows how to handle each bean in these cases.

Well, imagine this:
You get a new phone, you are all excited about it. You want to unlock it, but it protectd with password. The password is available inside the notes in the locked phone.
So, you want to use your phone, for it you need the pass. You want the pass, for it you need to unlock the phone. You want to use your phone, for it you need your pass... Etc.
The same happens when you have circular references, for A you need B, for B you need A, so you cannot create A and cannot create B either and cannot proceed.

Related

Simple Dependency injection not working

It's the first time I have to use Dependency Injection and I'm a little confused.
I don't really understand how it works.
I have tried on a simple example :
public class StockResponse extends Response
{
#Inject BrandService $brand;
public List<StockResponseItem> stock;
public StockThresholdResponse()
{
stock = new ArrayList<>();
}
public static StockThresholdResponse create(List<DataItem> data)
{
StockResponse stock= new StockResponse();
for (ThresholdCheckAggregate data: d)
{
StockResponseItem item = new StockResponseItem();
item.id = d.thresholdId;
item.brand = str.$brand.byId(d.brand);
str.stockThresholds.add(item);
}
return str;
}
}
But when I use my create() method, I get a null pointer exception for $brand.
I think I have misunderstood how DI works but I can't find my error.
I had similar difficulties to understand how DI (Guice out of Java EE) works. In simple words Guice must have chance to modify You object, for example:
assist by construction usually.
You ask Guice "can You create my object" injector.getInstance(cls), then Guice is creating object for You, solving field or constructor annotation
In normal (non Java EE) environment Yoy never call classic constructor, You ask by second hand.
other method.
Few library / frameworks have integration with Guice (Apache Wicket I personally like) with "creation listeners" on some types of objects. Hard work of DI is hidden for Your eyes, but is executed.
Java EE lets say better EE programmers than me :(
In consequence Yoy don't give chance to inject anything, is null
Professionals sorry that I say at blondie level. That is way like I discovered DI few years ago
Correction to code. Not
StockResponse stock= new StockResponse();
but
mod = .... // Module
injector = Guice.createInjector(mod); // global or almost global
...
injector.getInstance(StockResponse.class);
EDIT: intentionally I don't answer "how to write Guice module", assume this is other, long story
This could work, assuming BrandService is either a concrete class or if it's an interface, you have provided a binding for it to a concrete class elsewhere in your DI configuration (say a module in Guice or Spring #Configuration). I do see one obvious NullPointerException with str variable. Did you mean to do this?
item.brand = stock.$brand.byId(d.brand);

What is the most elegant way to choose what service implementation must be used?

in my controller, I need to choose what service implementation I need to use on spring. Before I was encapsulating this code in a factory, but I think that its not a good practice...
#Component
public class StoreServiceFactory {
#Autowired
private List<StoreService> storeServices;
public StoreService getService(){
if(isActiveSale){
return storeServices.get("PublicStoreService")
}
return storeServices.get("PrivateStoreService")
}
}
So I would like to encapsulate this behaviour to not care about inside my controller.. How can I get it??
If isActiveSale changes when the application is running, I think that what you got is a good solution. Since the Controller is a singleton you can't expect a different injection everytime this value changes.
If you get the value only on the startup of the application(e.g. from some property) you can use a profile.
There is nothing wrong with a factory, although as #R4J points out in the comments it is more of a provider, since it doesn't instantiate anything. I would consider the factory/provider a good choice if the 'isActiveSale' status changes based on things outside of the current control flow, like a configuration in a property file. A setting set in some adminstration screen, or maybe based on the time of day.

Picocontainer 2.14.3 and AOP

I'm trying to use AOP with picocontainer.
so far I found in the documentation:
http://picocontainer.codehaus.org/interception.html
pico = new DefaultPicoContainer();
pico.as(INTERCEPT).addComponent(Apple.class, BraeburnApple.class);
and then create the interceptor, but looking through the code, I cannot find the INTERCEPT property anywhere.
as receives a Properties value, which pico implements in Characteristics class.
anyone has a clue, or has implemented it before and knows how to keep with it?
Thanks
looks like the property for this Behavior is somehow missing in this pico version, check org.picocontainer.Characteristics in older versions, I really hope it was implemented somewhere :)
Also there's old styled way for interception in pico: http://www.markhneedham.com/blog/2008/11/11/logging-with-pico-container/
Since the 2.14.3 org.picocontainer.behaviors still have these classes, I suppose this way is ok
This worked for me. First, create a proxy by extending a bean:
public static class ChangeMapInfoEndpointInterceptor extends MapInfoRoutingManagementBean {
#Override
public void setEndpoint(String endpoint) {
System.out.println("setEndpoint called");
}
}
Then pass it to the intercepting-styled container:
MutablePicoContainer context = new PicoBuilder().withBehaviors(new Intercepting()).build();
context.addComponent(MapInfoRoutingManagement.class, MapInfoRoutingManagementBean.class);
Intercepted intercepted = context.getComponentAdapter(MapInfoRoutingManagement.class).findAdapterOfType(Intercepted.class);
intercepted.addPostInvocation(MapInfoRoutingManagement.class, new ChangeMapInfoEndpointInterceptor());

E4 EPartService findPart() throwing java.lang.Null Pointer Exception

New to Eclipse RCP (e4), am trying to get a handler to update a UI widget within a Part.
I have tried injecting the EPartService to first access the Part by ID, like so:
public class Example {
public static final String PART_ID = “au.org.example.app.part”;
#Inject
private EPartService partService;
public void eventOccured()
{
MPart part = partService.findPart(PART_ID); // exception thrown here
}
}
But this is throwing a NPE.
findPart() should at least safely return null if the ID were incorrect? So what am I missing?
Am also open to suggestions of relevant tutorials (have worked through some of Lars Vogella's great tutorials, but to no avail for this problem).
Any further info required please let me know.
EDIT : Looks like EPartService is not being injected? Have I not added it correctly?
Injection is only done automatically on objects which are known to the Application Model - things like parts and handlers.
For objects which you create you can do injection using the ContextInjectionFactory. You can create an object with:
#Inject
IEclipseContext context;
...
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
or you can do injection on an existing class instance with:
ContextInjectionFactory.inject(myClass, context);
in this case injection is not done on the class constructor.
There are other variants of make and inject which have a second context which allows additional values to be added to the context being injected.

I can't unit test my class without exposing private fields -- is there something wrong with my design?

I have written some code which I thought was quite well-designed, but then I started writing unit tests for it and stopped being so sure.
It turned out that in order to write some reasonable unit tests, I need to change some of my variables access modifiers from private to default, i.e. expose them (only within a package, but still...).
Here is some rough overview of my code in question. There is supposed to be some sort of address validation framework, that enables address validation by different means, e.g. validate them by some external webservice or by data in DB, or by any other source. So I have a notion of Module, which is just this: a separate way to validate addresses. I have an interface:
interface Module {
public void init(InitParams params);
public ValidationResponse validate(Address address);
}
There is some sort of factory, that based on a request or session state chooses a proper module:
class ModuleFactory {
Module selectModule(HttpRequest request) {
Module module = chooseModule(request);// analyze request and choose a module
module.init(createInitParams(request)); // init module
return module;
}
}
And then, I have written a Module that uses some external webservice for validation, and implemented it like that:
WebServiceModule {
private WebServiceFacade webservice;
public void init(InitParams params) {
webservice = new WebServiceFacade(createParamsForFacade(params));
}
public ValidationResponse validate(Address address) {
WebService wsResponse = webservice.validate(address);
ValidationResponse reponse = proccessWsResponse(wsResponse);
return response;
}
}
So basically I have this WebServiceFacade which is a wrapper over external web service, and my module calls this facade, processes its response and returns some framework-standard response.
I want to test if WebServiceModule processes reponses from external web service correctly. Obviously, I can't call real web service in unit tests, so I'm mocking it. But then again, in order for the module to use my mocked web service, the field webservice must be accessible from the outside. It breaks my design and I wonder if there is anything I could do about it. Obviously, the facade cannot be passed in init parameters, because ModuleFactory does not and should not know that it is needed.
I have read that dependency injection might be the answer to such problems, but I can't see how? I have not used any DI frameworks before, like Guice, so I don't know if it could be easily used in this situation. But maybe it could?
Or maybe I should just change my design?
Or screw it and make this unfortunate field package private (but leaving a sad comment like // default visibility to allow testing (oh well...) doesn't feel right)?
Bah! While I was writing this, it occurred to me, that I could create a WebServiceProcessor which takes a WebServiceFacade as a constructor argument and then test just the WebServiceProcessor. This would be one of the solutions to my problem. What do you think about it? I have one problem with that, because then my WebServiceModule would be sort of useless, just delegating all its work to another components, I would say: one layer of abstraction too far.
Yes, your design is wrong. You should do dependency injection instead of new ... inside your class (which is also called "hardcoded dependency"). Inability to easily write a test is a perfect indicator of a wrong design (read about "Listen to your tests" paradigm in Growing Object-Oriented Software Guided by Tests).
BTW, using reflection or dependency breaking framework like PowerMock is a very bad practice in this case and should be your last resort.
I agree with what yegor256 said and would like to suggest that the reason why you ended up in this situation is that you have assigned multiple responsibilities to your modules: creation and validation. This goes against the Single responsibility principle and effectively limits your ability to test creation separately from validation.
Consider constraining the responsibility of your "modules" to creation alone. When they only have this responsibility, the naming can be improved as well:
interface ValidatorFactory {
public Validator createValidator(InitParams params);
}
The validation interface becomes separate:
interface Validator {
public ValidationResponse validate(Address address);
}
You can then start by implementing the factory:
class WebServiceValidatorFactory implements ValidatorFactory {
public Validator createValidator(InitParams params) {
return new WebServiceValidator(new ProdWebServiceFacade(createParamsForFacade(params)));
}
}
This factory code becomes hard to unit-test, since it is explicitly referencing prod code, so keep this impl very concise. Put any logic (like createParamsForFacade) on the side, so that you can test it separately.
The web service validator itself only gets the responsibility of validation, and takes in the façade as a dependency, following the Inversion of Control (IoC) principle:
class WebServiceValidator implements Validator {
private final WebServiceFacade facade;
public WebServiceValidator(WebServiceFacade facade) {
this.facade = facade;
}
public ValidationResponse validate(Address address) {
WebService wsResponse = webservice.validate(address);
ValidationResponse reponse = proccessWsResponse(wsResponse);
return response;
}
}
Since WebServiceValidator is not controlling the creation of its dependencies anymore, testing becomes a breeze:
#Test
public void aTest() {
WebServiceValidator validator = new WebServiceValidator(new MockWebServiceFacade());
...
}
This way you have effectively inverted the control of the creation of the dependencies: Inversion of Control (IoC)!
Oh, and by the way, write your tests first. This way you will naturally gravitate towards a testable solution, which is usually also the best design. I think that this is due to the fact that testing requires modularity, and modularity is coincidentally the hallmark of good design.

Categories

Resources