Dependency injeection at runtime in Java - java

I have read through the dependency capabilities through Java CDI but could not figure out so far how to inject a class by runtime. Let me explain the scenario first.
Lets assume I have a JSF web app with a central Email service.
I am defining an interface
public interface EmailService {
public String sendEmail(Email email);
}
Then next I have a concrete implementation of the EmailService using Smtp:
public class SmtpEmailServiceImpl implements EmailService {
#Override
public String sendEmail(Email email) {
// concrete implementation using Smtp
}
}
Now in my web app I am having a JSF backing bean that should get the EmailService injected in order to sende the e-mail
public class JSFBackingBean {
// This is the EmailService to be injected
private EmailService emailService;
public String sendEmail(){
emailService.sendEmail(new Email());
}
}
Now lets assume the Smtp-Server is down for maintenance. In this scenario I would like to spool all the Emails in a Database and process them later when the Smtp server is up and running. In this case I would like to have a second implementation of the EmailService:
public class DatabaseEmailService implements EmailService {
#Override
public String sendEmail(Email email) {
// concrete implementation writing the email to a database
}
}
Now I understand from CDI that I can use Annotations to inject the proper service implementation but that would mean that I would have to re-build and deploy my classes in case I would like to change the appropriate service. Is there a better solution where I can use e.g. a configuration file in order to change the injection at runtime of the application?
Thanks for your answers in advance
Pred

In cases like this, you could write a custom Producer and Qualifier. Instead of injecting the EmailService, inject for example a "#Failsafe EmailService".
Then write a producer
#Produces
#Failsafe
private EmailService failsafeEmailService() {
// here you can check if the Mail Server is available and then decide
// to return the "real" Service or the DB-Queue.
}
Instead of creating/looking up the Services inside the method body, you could also let CDI inject both alternatives (directly or via Instance<>) and then decide which one to propagate.
#Produces
#Failsafe
private EmailService failsafeEmailService(MailServiceBean bean, DBQueue queue) {
return (check_if_mail_server_is_running) ? bean : queue
}
(of course both DBQueue and Bean have to implement EmailService).

Well, I doubt you want to make it so that every client to this email service is aware that the mail service needs to be switched out, even if you used annotations and instance selectors, e.g.:
#Inject
private Instance<EmailService> emailServiceInstance;
// few lines down
emailServiceInstance.select(new SmtpLiteral()).get();
Which is how you would do it in a CDI fashion. What I would recommend is that this logic belongs in your EmailService and itself injects a reference to some DB class that persist the message to the database until the SMTP server is back online.

Related

How is dependency injection helpful when we have multiple implementing classes?

I have been using dependency injection using #Autowired in Spring boot. From all the articles that I have read about dependency injection, they mention that dependency injection is very useful when we (if) decide to change the implementing class in the future.
For example, let us deal with a Car class and a Wheel interface. The Car class requires an implementation of the Wheel interface for it to work. So, we go ahead and use dependency injection in this scenario
// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}
// Wheel interface implementation
public class MRF impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Car class
public class Car {
#Autowired
Wheel wheel;
}
Now in the above scenario, ApplicationContext will figure out that there is an implementation of the Wheel interface and thus bind it to the Car class. In the future, if we change the implementation to say, XYZWheel implementing class and remove the MRF implementation, then the same should work.
However, if we decide to keep both the implementations of Wheel interface in our application, then we will need to specifically mention the dependency we are interested in while Autowiring it. So, the changes would be as follows -
// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}
#Qualifier("MRF")
// Wheel interface implementation
public class MRF impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Wheel interface implementation
#Qualifier("XYZWheel")
public class XYZWheel impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Car class
public class Car {
#Autowired
#Qualifier("XYZWheel")
Wheel wheel;
}
So, now I have to manually define the specific implementation that I want to Autowire. So, how does dependency injection help here ? I can very well use the new operator to actually instantiate the implementing class that I need instead of relying on Spring to autowire it for me.
So my question is, what are the benefit of autowiring/dependency injection when I have multiple implementing classes and thus I need to manually specify the type I am interested in ?
You don't have to necessarily hard-wire an implementation if you selectively use the qualifier for #Primary and #Conditional for setting up your beans.
A real-world example for this applies to implementation of authentication. For our application, we have a real auth service that integrates to another system, and a mocked one for when we want to do local testing without depending on that system.
This is the base user details service for auth. We do not specify any qualifiers for it, even though there are potentially two #Service targets for it, Mock and Real.
#Autowired
BaseUserDetailsService userDetailsService;
This base service is abstract and has all the implementations of methods that are shared between mock and real auth, and two methods related specifically to mock that throw exceptions by default, so our Real auth service can't accidentally be used to mock.
public abstract class BaseUserDetailsService implements UserDetailsService {
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
throw new AuthException("Default service cannot mock users!");
}
public UserDetails getMockedUser() {
throw new AuthException("Default service cannot fetch mock users!");
}
//... other methods related to user details
}
From there, we have the real auth service extending this base class, and being #Primary.
#Service
#Primary
#ConditionalOnProperty(
value="app.mockAuthenticationEnabled",
havingValue = "false",
matchIfMissing = true)
public class RealUserDetailsService extends BaseUserDetailsService {
}
This class may seem sparse, because it is. The base service this implements was originally the only authentication service at one point, and we extended it to support mock auth, and have an extended class become the "real" auth. Real auth is the primary auth and is always enabled unless mock auth is enabled.
We also have the mocked auth service, which has a few overrides to actually mock, and a warning:
#Slf4j
#Service
#ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockUserDetailsService extends BaseUserDetailsService {
private User mockedUser;
#PostConstruct
public void sendMessage() {
log.warn("!!! Mock user authentication is enabled !!!");
}
#Override
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
log.warn("Mocked user is being created: " + authorizedUserPrincipal.toString());
user = authorizedUserPrincipal;
}
#Override
public UserDetails getMockedUser() {
log.warn("Mocked user is being fetched from the system! ");
return mockedUser;
}
}
We use these methods in an endpoint dedicated to mocking, which is also conditional:
#RestController
#RequestMapping("/api/mockUser")
#ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockAuthController {
//...
}
In our application settings, we can toggle mock auth with a simple property.
app:
mockAuthenticationEnabled: true
With the conditional properties, we should never have more than one auth service ready, but even if we do, we don't have any conflicts.
Something went horribly wrong: no Real, no Mock - Application fails to start, no bean.
mockAuthEnabled = true: no Real, Mock - Application uses Mock.
mockAuthEnabled = false: Real, no Mock - Application uses Real.
Something went horribly wrong: Real AND Mock both - Application uses Real bean.
The best way (I think) to understand Dependency Injection (DI) is like this :
DI is a mecanism that allows you to dynamically replace your
#autowired interface by your implementation at run time. This is the
role of your DI framework (Spring, Guice etc...) to perform this
action.
In your Car example, you create an instance of your Wheel as an interface, but during the execution, Spring creates an instance of your implementation such as MRF or XYZWheel.
To answer your question:
I think it depends on the logic you want to implement. This is not the
role of your DI framework to choose which kind of Wheel you want for
your Car. Somehow you will have to define the interfaces you want to
inject as dependencies.
Please any other answer will be useful, because DI is sometimes source of confusion. Thanks in advance.

Dependency injection according to conditions

My controller:
#RestController
#RequestMapping("/mypath")
public class MyController {
#Autowired
MyServiceInterface service;
#PostMapping("/{source}")
void myControllerFunc(#PathVariable String source, #RequestBody MyObject obj) {
...
Object myServiceObj = service.myServiceFunc(param);
...
}
}
My Service Interface:
public interface MyServiceInterface {
Object myServiceFunc(String param);
}
My Service Implemantations:
#Service
public class MyServiceOne {
Object myServiceFunc(String param) {
...
}
}
#Service
public class MyServiceTwo {
void myServiceFunc(String param) {
...
}
}
My spring-boot version : 1.5.7
I want to inject the service according to my path variable ("source") . If source = one, inject MyServiceOne or if source = two, inject MyServiceTwo.
Is this possible?
It sounds like you need both of these to be available and each method invocation on the controller can choose a different one. So wire up both implementations, with a qualifier to distinguish them. Use the path variable in the controller method and let it decide programmatically which service to call.
I don't think it's possible and reasonable.
A #RestControllers is by nature a singleton. It gets configured at startup and remains the same for every request.
The expression /{source} is being evaluated during a request at runtime, when the controller has already been set up.
The options to consider:
Inject both services and, in the method, decide which one to pick.
Create two separate controllers for each service.
Utilise the application context and extract beans from there.
As described in Get bean from ApplicationContext by qualifier, you could add qualifiers to each service implementations and have something like this in the myControllerFunc:
BeanFactoryAnnotationUtils.qualifiedBeanOfType(ctx.getBeanFactory(), MyServiceInterface.class, source)

REST API Autowire remote or local implementation of a service automatically

I have a REST API built on Spring Boot consisting of 2 seperate web services. I don't know if those two web services will be hosted on the same machine so I want to make remote and local implementation for all services. Example below:
Local service implementation:
public class LocalExampleService implements ExampleService{
public Item getItem(long id){
//Get item using implementation from another local project
}
}
Remote service implementation:
public class RemoteExampleService implements ExampleService{
#Value("${serviceURL}")
private String serviceURL;
public Item getItem(long id){
//Get item calling remote service
}
}
Controller:
public class MyController{
#Autowired
private ExampleService exampleService;
}
Web service has many services with local and remote implementation and I want to let Spring know which type of implementation it should choose for all services.
I've been thinking about putting url in properties file and during intialization the app would check whether properties contain url and then autowire service approprietly. But then I would have to write logic for every service autowiring.
What's the best option to autowire correct service implementation automatically?
You can use Spring profiles to control which version of implementation should be used via spring properties.
In spring properties add below entry
spring.profiles.active=NAME_OF_ACTIVE_PROFILE
Every service implementation needs profile annotation. That's how your services implementation should look like:
#Component
#Profile("local")
public class LocalExampleService implements ExampleService{}
#Component
#Profile("remote")
public class RemoteExampleService implements ExampleService{}
If your project needs to use local implementation of a service then in properties instead of NAME_OF_ACTIVE_PROFILE insert local otherwise remote.
For fully automatic auto-wiring you need to add method running at the startup that checks whether local implementation class exists and then set profile properly. To do this you need to modify code in spring boot main method:
public static void main(String[] args){
String profile = checkCurrentProfile(); //Method that decides which profile should be used
System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, profile);
SpringApplication.run(MyApplication.class, args);
}
If you choose this approach then you don't need previous entry in properties file.
My attempt to implement something like this https://github.com/StanislavLapitsky/SpringSOAProxy
The idea is to check if a spring bean cannot be found locally then automatically create a Proxy which uses RestTemplate internally to call the same service remotely.
You need to define contract - services interfaces plus DTO and define URL resolver to specify which URL should be used for each service.

#EJB workflowDao is null in service layer

I'm trying to figure out how to setup a Service/Dao layer in my application. I've found a few dozen resources all with different ways on how to do it and decided to follow the model found here: How should EntityManager be used in a nicely decoupled service layer and data access layer?
I can't figure out what I'm missing that's causing this NPE.
Usage:
#Path("/helloworld")
public class MyController {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
WorkflowService workflowService = new WorkflowService();
workflowService.save(workflow);
return "Workflow ID:";
}
}
My Dao:
#Stateless
public class WorkflowDao {
#PersistenceContext(unitName = "unit")
private EntityManager entityManager;
public int save(Workflow workflow) {
entityManager.persist(workflow);
return workflow.getId();
}
}
My Service:
#Stateless
public class WorkflowService {
#EJB
WorkflowDao workflowDao;
public int save(Workflow workflow) {
int id = workflowDao.save(workflow); //throws NullPointerException because workflowDao is null
return id;
}
}
This is my first time setting up a Java project (only have worked on 1 before and it used Spring) so please keep that in mind if this looks horribly wrong.
WorkflowDao is not an EJB, it's a POJO with a#Stateless annotation. So naturally, injecting it with #EJB fails, creating a null workflowDao attribute and eventually producing a NullPointerException.
To make WorkflowDao into a full-fledged EJB, besides having a #Stateless or #Stateful annotation it needs to implement a local, remote or both interfaces, and those interfaces must be annotated respectively with #Local and #Remote. Please refer to the tutorial for details.
Also, quite possibly (this can be application server-dependent) you'll have to register the EJB in the application's xml descriptor files - for instance, in web.xml's <ejb-local-ref> element.
As a side note - it's not a good idea to use an EJB as a DAO, an EJB is typically used for implementing business logic (true, persist/merge operations can be called from here) but the actual persistence layer nowadays is implemented using JPA. In other words, WorkflowService should be the EJB service, there's no need to inject an EJB into it, and there's no need for a separate DAO layer - JPA entities fulfill this role.
If you instantiate your WorkflowService manually, the container wont perform any injection, since your WorkflowService is not managed by the Container.
I suggest you:
Annotate your Jax-RS Resource #Stateless
Inject your WorkfloService via #EJB as a member
Implementing a Local or Remote Interface is not necessary anymore
#Path("workflows")
#Stateless
public class WorkFlowResource{
#EJB
WorkflowService workflowService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
workflowService.save(workflow);
return "Workflow ID:";
}
}

Best way to interact with EJBs in Java EE

I have a moderate sized Java EE 6 project that uses several EJBs, including one which sole purpose is managing database calls through JPA. My question is what is the best way to add a new class that does some random bit of functionality and then calls the database access EJB to persist the data from this class.
Does this new class have to be an EJB if it needs access to annotations and injections? Does it have to be an EJB if it has to be deployed with the rest of the project?
I was told that if you want to add a new logic class to the project it either has to be an EJB or you can remotely integrate it using JNDI to access EJB elements and create some kind of client interface. Right now my new class is just a POJO but it's not able to access the EJB functionality.
What should I do in general?
EDIT: Please note my question IS NOT about database access. That's just an example I'm using. My guestion is more broad. I want to know how to access EJB methods from other classes I create. From one EJB to another you can simply inject the other EJB since they're both container managed. But say I create another class in the same package as the EJBs how might How can I access those methods? Is it possbile? What is the best practices here.
Right now I have a class that is taking twitter feed data from a URL it then parses the JSON and returns a string of the top 10 entries. I want to call my EJB that manages database access and pass that string to its corresponding method but I cannot do that because my class is not also an EJB.
EJBs are generally used to implement services of any kind. They integrate really well with JPA so are often used for DB access, but that's not their only usage.
What EJBs are typically not suited for is modeling data. I.e. they should be the verbs in your application, not the nouns. The following is thus wrong:
#Stateless
#Entity
public class CreditCard { // silly, don't do this!
#Id
Long id; + getters/setters
Data expiration date; + getters/setters
}
The following is better, it's a service that when your application starts up fetches some quote data from somewhere:
#Singleton
#Startup
public class QuoteFetcher {
private List<Quote> quotes; // + getter
#PostConstruct
public fetchQuote()
quotes = SomeUrlBuilder.someUrl().getQuotes();
}
}
The following is the obligatory DAO example:
#Stateless
public class JPAInvoiceDAO implements InvoiceDAO {
#PersistenceContext
private EntityManager entityManager;
public Invoice getById(Long invoiceId) {
return entityManager.find(invoiceId, Invoice.class);
}
// More DAO methods
}
The following shows how declarative security is used, and how a bean looks up something that has been externally mapped into its private context (ENC):
#Stateless
public class TokenFetcher
#Resource
private SessionContext sessionContext;
#RolesAllowed("SYSTEM")
public Token getToken() {
return (Token) sessionContext.lookup("token");
}
}
The second part of the question seems to be how to use these beans in your code. There are basically four methods:
Injection in managed beans
Bootstrapping via JNDI
Automatically called at startup
Automatically via a timer
Injection is the easiest way, but only managed beans are injection candidates (basically meaning the Java EE framework creates the bean, and you don't use new() to instantiate it).
E.g. Injection:
#ManagedBean
public class InvoiceBacking {
private Long invoiceId; // + getter/setter
private Invoice invoice; // + getter
#EJB
private InvoiceDAO invoiceDAO;
#PostConstruct
public void init() {
invoice = invoiceDAO.getById(invoiceId);
}
}
(also see Communication in JSF 2.0#Processing GET request parameters)
Bootstrapping via JNDI:
public class SomeQuartzJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
InvoiceDAO invoiceDAO = (InvoiceDAO) new InitialContext().lookup("java:global/myApp/myEJB/InvoiceDAO");
List<Invoice> openInvoices = invoiceDAO.getAllByOpenStatus();
// verbose exception handling and closing JNDI context omitted for brevity
}
}
The #Singleton bean showed earlier was an example of how the Java EE framework calls your code itself at startup. For the automatic timer you would use the #Schedule annotation on a bean's method.

Categories