What is the way one inject property value from property placeholder into CDI bean?
In Spring one write:
#org.springframework.beans.factory.annotation.Value("${webservice.user}")
private String webserviceUser;
what sets the webserviceUser field to property webservice.user from property file/property placeholder.
How to do that with CDI? I've tried to find some answer, but I couldn't find any equivalent. However, people write, you can use CDI as Spring substitute on application servers, and that use case is very basic, so surely there must be an easy way, unfortunately I've failed to find it.
CDI is a specification about Dependecy Injection and Context so it doesn't have such configuration things out of the box. But it also provides a very powerful extension mechanism that allows third party projects to add new portable features (i.e that works with all CDI implementation and that are not tied to a server).
The most important project providing CDI extensions is Apache Deltaspike and good news, it provides what you need.
So you need to add deltaspike-core in your project. If you use Maven, you need to add this dependencies to your pom.xml
<dependency>
<groupId>org.apache.deltaspike.core</groupId>
<artifactId>deltaspike-core-api</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.core</groupId>
<artifactId>deltaspike-core-impl</artifactId>
<version>0.4</version>
</dependency>
After that if you don't care about your properties filename, just add META-INF/apache-deltaspike.properties to your project and put your properties in it. If you need more than one file or want to choose the name you'll have to implement PropertyFileConfig interface for each file like this :
public class MyCustomPropertyFileConfig implements PropertyFileConfig
{
#Override
public String getPropertyFileName()
{
return "myconfig.properties";
}
}
After that you'll be able to inject values like this
#ApplicationScoped
public class SomeRandomService
{
#Inject
#ConfigProperty(name = "endpoint.poll.interval")
private Integer pollInterval;
#Inject
#ConfigProperty(name = "endpoint.poll.servername")
private String pollUrl;
...
}
As you see in this example taken from Deltaspike documentation, you can inject your value in String but also in Integer, Long, Float, Boolean fields. You could provide your own type if you need something more specific.
Deltaspike config documentation can be found here.
Related
I have an interface like:
public interface DateTimeService {
ZonedDateTime now();
void fixTo(ZonedDateTime date);
void forget();
}
and I have two implementations of it. One for production where fixTo and forget throws exceptions and one for testing where we control time. Then I have a CDI config that depending on a flag instantiate the right type.
#ApplicationScoped
public class Configuration {
#Produces
#ApplicationScoped
public DateTimeService dateTimeService(Configuration config) {
if (config.isFakeDateTimeServiceEnabled()) {
return new FakeDateTimeService();
} else {
return new DefaultDateTimeService();
}
}
}
However, I wanted to remove fixTo and forget from DateTimeService as they are only there so we can control time in tests. I made a new interface like:
public interface FakeDateTimeService extends DateTimeService {
// fixto and forget is moved from DateTimeService to here
}
I have a few injection points. Some is in production code, some is in test code. In production code I would like to only be able to access DateTimeSerice, in test code I want be able to get a handle on the extended service.
In prod code:
#Inject
private DateTimeService dateTimeService;
In test code:
#Inject
private FakeDateTimeService dateTimeService;
If I leave the config unchanged, then the test code will never find my extended service (as CDI seems to ignore the run-time type of the instance produced by the producer method).
If I update the config to instantiate both (in this case I can even inject the genuine service into the fake one), then production cannot wire together as fake also implements the DateTimeService interface and it causes ambiguity. At this point I could probably just use a qualifier, but I neither want to change my production code because of this nor have to have a fake date time service exist in production context.
I tried to veto bean creation but I failed to do so.
What I thought would/should work is instantiate the right type and programmatically add it to the bean context but examples I found was for CDI 2.0 while for now, relevant part of my code is stuck on CDI 1.2.
Probably at this point you can tell, that I'm not a CDI expert. So I'm opened for suggestion on good CDI read materials as well as concrete suggestions on this problem.
Otherwise, I'm about to give up and just live with a DateTimeService that have fixTo and forget methods.
Depending on how you are doing it, you could use the following approaches, whereby some of them have already be mentioned in the comments.
With alternatives
For testing you provide an own beans.xml, which defines the alternative for testing, which replaces the production one. You will have to keep them in sync, whereby the test beans.xml contains changes necessary for testing. Depending on the CDI implementation the beans.xml can be left out and #Alternative will be enough.
https://docs.oracle.com/javaee/6/tutorial/doc/gjsdf.html
interface DateTimeService { ... }
// Active during production, beans.xml does not define alternative
class DefaultDateTimeService implements DateTimeService { ... }
// Active during test, beans.xml defines alternative
#Alternative
class FakeDateTimeService implements DateTimeService { ... }
// Injection point stays the same.
#Inject
DateTimeService dateTimeService;
// Used in test environment
<beans ... >
<alternatives>
<class>FakeDateTimeService</class>
</alternatives>
</beans>
With Arquillian
With Aarquillian you can assemble the deployment yourself and exclude the DefaultDateTimeService implementation and replace it with the FakeDateTimeService implementation. With this approach you don't need to hack anything because during test, only FakeDateTimeService implementation will be visible to the CDI container.
http://arquillian.org/guides/getting_started/
With CDI Extension
For testing you could provide an CDI extension and the FakeDateTimeService implementation in the test code, whereby the CDI Extension does veto the DefaultDateTimeService implementation.
package test.extension
public class VetoExtension implements Extension {
public <T> void disableBeans(#Observes ProcessAnnotatedType<T> pat) {
// type matching
if (DefaultDateTimeService.class.isAssignableFrom(pat.getAnnotatedType().getJavaClass())) {
pat.veto();
}
}
}
// Define SPI provider file, assuming test/resources is on CDI classpath
src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
// Single line you put in there
test.extension.VetoExtension
Deltaspike #Exclude
Deltaspike is a CDI extension library which provides some useful utilities for CDI development and testing, also a CDITestRunner is provided. The #Exclude annotation is used by an extension which does the same as the example above but already implemented for you.
https://deltaspike.apache.org/
https://deltaspike.apache.org/documentation/test-control.html
https://deltaspike.apache.org/documentation/projectstage.html
You should choose an approach which doesn't pollute your source code and forces you to hack to much to get it running for testing.
I would prefer Arquillian because here you have full control about what is in the deployment and nothing in your production code has to change or be specially implemented so its testable.
With Deltaspike you can exclude production code for testing and replace them with test implementations.
If no additional library or framework can be used I would prefer the alternative approach, because its the least complicated one to use.
I used to integrate Service and DAO beans in Jersey REST resources by annotating them with #Path following Java EE tutorial
In general, for JAX-RS to work with enterprise beans, you need to annotate the class of a bean with #Path to convert it to a root resource class. You can use the #Path annotation with stateless session beans and singleton POJO beans.
So my code used to be something like this:
#Path("/")
public class ServiceResource {
#Inject
private AccountService accountService;
#GET
#Path("/account/get")
public Account getAccount(#QueryParam("id") String id) {
return accountService.get(id);
}
}
#javax.inject.Singleton
#Path("")
public class AccountService {
public Account get(String id){...}
}
Now, I started integrating a Quartz Job into my application, and I wanted to find a way to inject my AccountService inside a job like this
public class AccountJob implements Job {
#Inject
private AccountService accountService;
#Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
accountService.updateAllAccounts();
}
}
I found this answer that tells to use DeltaSpike to do the Job, so I added the following dependencies to my pom.xml, and without adding any more lines of code to any class the inejection of accountService to my Job works fine
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-scheduler-module-api</artifactId>
<version>1.7.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-scheduler-module-impl</artifactId>
<version>1.7.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-api</artifactId>
<version>1.7.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-weld</artifactId>
<version>1.7.2</version>
<scope>runtime</scope>
</dependency>
However, I realized that when I remove the #Path("") from AccountService, its instance is still injected fine inside ServiceResource, so my questions are the following:
Why adding DeltaSpike dependencies made it possible to inject my beans without using #Path on them?
By searching more, I understood that DeltaSpike internally uses Weld to do the injection, and since I am already using GlassFish 4.0, I know that Weld is already there, so why the injection is not working by default in my Job class and in ServiceResource class without adding #Path on my beans? Actually why adding #Path is even suggested in the Java tutorial?
Is there any bad side effects that I don't see in my code, because I think that I am mixing multiple DI methods here without really understanding how do they work?
Update: After more search, I realize that Jersey doesn't use Weld for dependency injection, instead it uses HK2, a different framework that also happens to be a part of GlassFish, when I try to inject AccountService without using #Path it shows the following exception
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=AccountService,parent=ServiceResource,qualifiers={}...
So this updates the questions to the following:
How to make HK2 injections works? // Without using #Path as mentioned in the Java EE Tutorial
If I managed to to do DI with HK2, will it be safe to use DeltaSpike to do DI for the Quartz Job? Is it okay to mix two CDI framewroks together to scan the classes and do the injection?
I put my my source code on pastebin; pom.xml is here and the Java is here
You do not need to set the Path annotation on your AccountService CDI bean. If CDI is enabled on your application (either with empty beans.xml in CDI 1.0 or discovery-mode=all in CDI > 1.0), you can #Inject any CDI bean in your JAX-RS resource.
So you just have to write the following class:
#Path("/")
public class ServiceResource {
#Inject
private AccountService accountService;
#GET
#Path("/account/get")
public Account getAccount(#QueryParam("id") String id) {
return accountService.get(id);
}
}
#javax.inject.Singleton
public class AccountService {
public void Account get(String id){...}
}
The article you linked in your post deals with mixing EJB and CDI annotations. For example you can mix #Stateless and #Path annotations. It's interesting for example because you can :
Benefit of EJB transaction in your Rest resource (even if now you can use #Transactional interceptor binding)
Set a pool of resources
etc.
Note that all of this works without the help of deltaspike dependency.
For your second question, as Quartz manages its own threads, classes are not handled by CDI so you can not inject beans in Quartz classes. The aim of the deltaspike module is to allow injecting CDI beans in Quartz Jobs. Internally, deltaspike controls CDI Contexts.
EDIT
For your last questions:
Your HK2 problem comes pretty sure from a missing dependency (in your application or server). As said in a previous comment, I managed to deploy your App on Glassfish 4 (build 89) with the source files you provided.
Regarding the integration of CDI with Quartz, I think the best is to implement your own JobFactory and instanciate your jobs using BeanManager. Take a look at this link : https://devsoap.com/injecting-cdi-managed-beans-into-quarz-jobs/
First of all injected resources(beans) and Jersey Endpoint class(point of injection) must be CDI-Aware. It must be detecteable by CDI. We can use bean-discovery-mode="all" - then CDI scan ALL classes or
bean-discovery-mode="annotated" and MARK our class with PROPER annotation: from here : Bean defining annotations. I prefer#Dependent or #RequestScoped
Then we must use Jersey Extension
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x-servlet</artifactId>
<version>{version}</version>
<scope>runtime</scope>
</dependency>
`
to connect CDI with HK2 discovery mechanism.
Here is Official oracle Guideline
The default beans.xml discovery-mode (in Java EE 7) is "annotated". Which means only beans that have CDI annotations are recognized and managed by CDI.
Your AccountJob class is not annotated. If you want CDI to be able to inject the service into it then you need to annotate it with some scope annotation, e.g. #ApplicationScoped.
Your other option is to create CDI producer for creating AccountJob beans. See:
http://docs.jboss.org/weld/reference/latest/en-US/html_single/#_producer_methods
I have an application that need to send emails. I might need later to send emails in a second application so I try to do a library to re-use it.
My application is done with Spring-boot.
My library just include Spring-core, Spring-context and Spring-test.
This is my EmailUtils in my library :
#Named
public class EmailUtils {
#Value("${from}")
private String from;
#Value("${to}")
private String to;
...
}
I would like to have a default file application.properties with that in the library :
from=default-from
to=default-to
now I would like if my application spring boot does something like that :
#Service
public void EmailService {
#Inject
private EmailUtils emailUtils;
...
}
I would like if I don't define a new application.properties in my application to get the default value from the library but would be possible to override them by using an application.properties in my Spring-boot app.
Info : My Spring-boot app have ScanComponent package (just to mention it). But my library has nothing. I don't know if I have to use a beans.xml and define a ContextPlaceHolder ...
I am a little bit loss, maybe there is a better way to do it ?
Thank you.
If I am correctly understanding your question - you want to specify a default value for your #Value annotated properties. You can do this simply by simply using the format #Value("${property_key:default value}") so if you wished the default from value to be me#me.com and to to be you#you.com your code would read:
#Named
public class EmailUtils {
#Value("${from:me#me.com}")
private String from;
#Value("${to:you#you.com}")
private String to;
...
}
Hi i have a problem with inject a regular java class (Pojo class) into EJB bean.
#ApplicationScoped
public class DomainRouteFinderService {
#Inject
private Pojo pojo;
private AtomicInteger sequencer;
#PostConstruct
private void init(){
sequencer = new AtomicInteger();
sequencer.lazySet(0);
}
#Produces
#Named("sequencer")
public String getText(){
return "Number: "+ sequencer.getAndIncrement();
}
}
Pojo class:
public class Pojo {
}
In my multiprojects with structure like below:
ROOT - ear
ejb
web
Web module depends on ejb.
In web module is beans.xml with bean-discovery-mode="all"
I resolved my problem by adding another beans.xml to ejb.
I put this file to
main/java/resources/META-INF localization.
Why?
One of the most significant changes in CD 1.1/Java EE 7 is that by
popular request, CDI is now enabled by default. This means that
there's no need to explicitly add a beans.xml to enable DI any more.
However, it is also very important to understand that CDI now also
provides finer grained control over component scanning via the
'bean-discovery-mode' attribute. This attribute has three possible
values:
'annotated' - loosely translated, means that only components with a class-level annotation are processed.
'all' - all components are processed, just like they were in Java EE 6 with the explicit beans.xml.
'none' - CDI is effectively disabled.
By default, if you specify nothing and there is no beans.xml, the bean
discovery mode of 'annotated' and not 'all' is assumed.
But i want to one beans.xml for ejb module and war module.
Is it possible to use some kind of mocking framework with Arquillian, or precisely how to mock injected EJBs? I know that, with using the CDI (Contexts and Dependency Injection), it is possible to inject alternatives in test. But without CDI as injection mechanism, when I'm only using EJB injection, how this is possible?
Recently I have tested my EJBs with service interface mock implementation as following:
// Service inteface
public interface Audit {
void audit(String info);
}
// Mock implementation
#Stateless
public class MockAuditBean implements Audit {
public static String lastInfo = null;
#Override
public void audit(String info) {
this.lastInfo = info;
}
}
// assert in test
assertTrue(MockAuditBean.lastInfo.contains("dummy"));
This approach is possible but requires a lot of custom mock implementations. What is worse, injected instances of mocks are proxies and uses service interface. These can not be cast to mock implementation class to compare results. Only static members and methods of mock implementation can be used.
I have tested also another possibilities to set related EJBs manually. This approach has several draw-backs. It requires that target EJB of test has non-private members or setters for them. When target EJB relies on #PostConstruct lifecycle annotation, you have to call it after your manual "injection" setting.
Advantage of this solution is the ability to use mock frameworks, like mockito or jMock.
Have someone an experience to share, how to test and set-up such integration test, or even use mocking frameworks in it ?
IMO, EJBs where not designed with testing in mind. Your alternative sounds like a good enough compromise and I'd go for it. Using mockito is a major plus and I use it even when working with CDI.
I'd use the "default" member scope and javadoc to other developers access them for testing purposes only.
This article from Oracle shows an approach to "injecting" an EJB for testing using JUnit and Mockito:
http://www.oracle.com/technetwork/articles/java/unittesting-455385.html
Edit:
Basically the inclusion of Mockito allows for mocking objects like EntityManager etc.:
import static org.mockito.Mockito.*;
...
em = mock(EntityManager.class);
They show the approach for EJB as well using mockito. Given an EJB:
#Stateless
public class MyResource {
#Inject
Instance<Consultant> company;
#Inject
Event<Result> eventListener;
The test can "inject" those objects:
public class MyResourceTest {
private MyResource myr;
#Before
public void initializeDependencies(){
this.myr = new MyResource();
this.myr.company = mock(Instance.class);
this.myr.eventListener = mock(Event.class);
}
Note that MyResource and MyResource are in the same class path but different source folders so your tests have access to the protected fields, company and eventListener.
Edit:
Note: you can use FacesMockitoRunner from JBoss (https://community.jboss.org/thread/170800) to get this done for the common JSF components and use annotations for the others (Java EE 6 with CDI enabled as a pre-requisite for this, but does not require JBoss server):
Include jsf, mockito, and jsf-mockito dependencies in maven:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.test-jsf</groupId>
<artifactId>jsf-mockito</artifactId>
<version>1.1.7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
Add the #RunWith annotation to your test:
#RunWith(FacesMockitoRunner.class)
public class MyTest {
Inject common Faces objects using annotations:
#Inject
FacesContext facesContext;
#Inject
ExternalContext ext;
#Inject
HttpServletRequest request;
Mock any other objects using the annotations #org.mockito.Mock (it appears FacesMockitoRunner calls this behind the scenes so it may not be necessary here):
#Mock MyUserService userService;
#Mock MyFacesBroker broker;
#Mock MyUser user;
Init the Injected Mocks using the
#Before public void initMocks() {
// Init the mocks from above
MockitoAnnotations.initMocks(this);
}
Setup your test as usual:
assertSame(FacesContext.getCurrentInstance(), facesContext);
when(ext.getSessionMap()).thenReturn(session);
assertSame(FacesContext.getCurrentInstance().getExternalContext(), ext);
assertSame(FacesContext.getCurrentInstance().getExternalContext().getSessionMap(), ext.getSessionMap());
etc.
You may want to take a look at testfun-JEE which allows you to unit-test (not integration-test) your EJBs outside of a container.
testfun-JEE takes care for injecting EJBs as well as EntityManager and some standard resource directly into your test class - references within these EJBs to other EJBs are resolved automatically.
And the coolest thing is that you can mock any dependency by simple adding a member variable to your test annotated with #Mock - testfun-JEE will inject this mock wherever needed.
See examples in https://github.com/michaelyaakoby/testfun.
BTW, while this framework was published very recently (like today...) it is being widely used for over a year in my company.
Work with a framework, like Mockito.
Unfortunately, Arquillian does not automatically include the necessary dependencies.
You can add them in your #Deployment function:
#Deployment
public static WebArchive deploy()
{
return ShrinkWrap.create(WebArchive.class)
.addAsLibraries( // add maven resolve artifacts to the deployment
DependencyResolvers.use(MavenDependencyResolver.class)
.artifact("org.mockito:mockito-all:1.8.3")
.resolveAs(GenericArchive.class))
);
}
source
Then in your #Test method you could use:
mock(MockedService.class).methodName()
This github showcase shows a way to allow auto discovery, which seems to require some setup:
source
If you really want to interact with mocks in your integration tests (for instance one reason might be that you don't have a full blown implementation yet or you have an facade to external systems which you don't have control over), there is quite an easy way to integrate Mockito with your Arquillian tests, have a look at this example from the showcase. It's actually extension on its own, but not released as one.