I'm using Junit 5, Java bath that run under a webapp EE8 environment.
On the web app, I actually have a resources class that is employed as a producer:
#ApplicationScoped
public class Resources {
#Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
#Produces
#PersistenceContext(unitName = "primary")
private EntityManager entityManager;
}
Now I want to write some SE test, and I need to retrieve an alternative entity manager, something like:
public class MockResources {
#Alternative
#JobScoped
#Produces
public EntityManager getEntityManager() {
return Persistence.createEntityManagerFactory("primary").createEntityManager();
}
}
The issue is that I don't know how to retrieve this alternative entity , as beans.xml want a class (I tried with Hibernate SessionImpl but it doesn't work), neither #Stereotype looks good for my case.
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
<alternatives>
<class>org.hibernate.internal.SessionImpl</class>
</alternatives>
</beans>
Any help ?
You should create an entire #Alternative Resources producer bean, as in
#Alternative
#ApplicationScoped
public class TestResources {
#Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
#Produces
private EntityManager getEntityManager() {
// create your new entitymanager here
return Persistence.createEntityManagerFactory("testunitname").createEntityManager();
}
}
Then define your test alternative class on test beans.xml as described on your question.
Related
My application currently uses a class into which two services get injected with the #Inject annotation.
#Stateless
public class MyClass {
#Inject
private SomeService someService;
#Inject
private OtherService otherService;
}
Both services are pretty similar and both extend an abstract Service class.
Here's what I'm trying to do...
My basic idea is that the MyClass class would look something like this:
#Stateless
public class MyClass {
#Inject
private Service service;
}
Depending on a configuration the application decides to either inject SomeService or OtherService
Example:
if (config.getValue().equals("some_service")) {
return new SomeService();
} else if (config.getValue().equals("other_service")) {
return new OtherService();
}
Does Jave EE provide a solution for this?
To make this work, you'll need to ensure that whatever "makes" SomeService eliminates Service from the list of types it can make, and whatever "makes" OtherService eliminates Service from the list of types it can make.
For example, if SomeService is a simple managed bean, you'll need to add the #Typed(SomeService.class) annotation to it:
#Typed(SomeService.class)
public class SomeService extends Service {
}
If, on the other hand, SomeService is produced by a producer method you'll have to do the same thing analogously:
#Produces
#ApplicationScoped
#Typed(SomeService.class)
private SomeService makeSomeService() {
return fabricateSomeService();
}
The #Typed annotation restricts the set of types to whatever is given, not what is inferred.
If you do this on both "concrete" services, then your getService() producer method as written in your answer above should work.
What do you mean by: "Depending on a configuration..." When do you decide what to use? At compiletime or runtime?
There are severaly ways to get this done:
1. #Alternative and beans.xml
Annotate SomeService and OtherService with #Alternative and activate one of them again in beans.xml with
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>SomeService</class>
</alternatives>
</beans>
2. With qualifier and Producer:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface First {}
And annotate both Beans with:
#First
#Stateless
public SomeService{ ... }
Now you can have a Producer-Class that looks like follows:
#Dependent
public class ServiceProducer {
#Inject
#First
private Service someService;
#Inject
#Second
private Service otherService;
#Produces
#Default
public Service getService() {
switch (someCondition) {
case SOME:
return someService;
case OTHER:
return otherService;
default:
return null;
}
}
}
And finally inject the Service where you want to use it:
#Inject
Service service;
3. Without Producer but with Qualifier-Annotations
You need to Annotate SomeService and OtherService to get this to work.
#Inject
Instance<Service> services;
public void someBussinessMethod(){
Annotation qualifier = someCondition ? new AnnotationLiteral<First>() {} : new AnnotationLiteral<Second>() {};
Service s = services.select(qualifier).get();
}
4. Without Qualifier
This ist in my eyes the ugliest and slowest solution but you can iterrate over the Injectend services and decide by the Class if you want to use it.
#Inject
Instance<Service> services;
public void doSomething() {
Class clazz = someCondition ? SomeService.class : OtherService.class;
Service first = services.stream().filter(s -> s.getClass() == clazz).findFirst().get();
}
A detailed explenation can be found here:
https://docs.jboss.org/cdi/learn/userguide/CDI-user-guide.html#injection
With respect to the comment by #kukeltje I used the #Produces annotation like this:
#ApplicationScoped
public class MyProducer {
#Inject
private SomeService someService;
#Inject
private OtherService otherService;
#Produces
#ApplicationScoped
public Service getService() {
switch (someCondition) {
case SOME:
return someService;
case OTHER:
return otherService;
default:
return null;
}
}
}
Usage:
#Stateless
public class MyClass {
#Inject
private Service service;
}
I'd like for my ResourceConfig to have access to a database for its configuration. I've tried this:
#ApplicationPath("/api")
public class ApplicationConfig extends ResourceConfig {
#PersistenceContext(unitName = "myPU")
private EntityManager em;
#Inject
private MyEjb myEjb;
#PostConstruct
public void init() {
// em and myEjb are both null
...
}
But neither the EntityManager, not the EJB, are injected (both are null)
Is there a special way to do this in JAX-RS?
NOTE: I'm able to inject resources into a Path-annotated class just fine. I'm having trouble doing it in the actual ApplicationPath-annotated class.
I need to do some data migration, which is too complex to do it in a liquibase changeset. We use spring
That's why I wrote a class implementing the liquibase.change.custom.CustomTaskChange class. I then reference it from within a changeset.
All is fine to this point.
My question is:
Is it possible to get access to the other spring beans from within such a class?
When I try to use an autowired bean in this class, it's null, which makes me think that the autowiring is simply not done at this point?
I've also read in some other thread, that the Liquibase bean must be initialized before all other beans, is that correct?
Here is a snippet of the class I wrote:
#Component
public class UpdateJob2 implements CustomTaskChange {
private String param1;
#Autowired
private SomeBean someBean;
#Override
public void execute(Database database) throws CustomChangeException {
try {
List<SomeObject> titleTypes = someBean.getSomeObjects(
param1
);
} catch (Exception e) {
throw new CustomChangeException();
}
...
I get an exception and when debugging I can see that someBean is null.
Here is the config for the SpringLiquibase:
#Configuration
#EnableTransactionManagement(proxyTargetClass = true)
#ComponentScan({
"xxx.xxx.."})
public class DatabaseConfiguration {
#Bean
public SpringLiquibase springLiquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource());
liquibase.setChangeLog("classpath:liquibase-changelog.xml");
return liquibase;
}
...
Some more config:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<includeAll path="dbschema"/>
</databaseChangeLog>
And here the call from the changeset:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="201509281536" author="sr">
<customChange class="xxx.xxx.xxx.UpdateJob2">
<param name="param1" value="2" />
</customChange>
</changeSet>
I'm currently running through this problem as well...After hours of digging, I found 2 solutions, no AOP is needed.
Liquibase version: 4.1.1
Solution A
In the official example of customChange
https://docs.liquibase.com/change-types/community/custom-change.html
In CustomChange.setFileOpener, ResourceAccessor actually is an inner class SpringLiquibase$SpringResourceOpener, and it has a member 'resourceLoader', which is indeed an ApplicationContext. Unfortunately, it's private and no getter is available.
So here comes an ugly solution: USE REFLECTION TO GET IT AND INVOKE getBean
Solution B (More elegant)
Before we get started, let's see some basic facts about Liquibase. The official way of integrating Liquibase with Spring Boot is by using:
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration
This is a conditional inner config bean for creating SpringLiquibase ONLY WHEN SpringLiquibase.class IS MISSING
#Configuration
#ConditionalOnMissingBean(SpringLiquibase.class)
#EnableConfigurationProperties({ DataSourceProperties.class,
LiquibaseProperties.class })
#Import(LiquibaseJpaDependencyConfiguration.class)
public static class LiquibaseConfiguration {...}
So we can create our own SpringLiquibase by adding a liquibase config bean
#Getter
#Configuration
#EnableConfigurationProperties(LiquibaseProperties.class)
public class LiquibaseConfig {
private DataSource dataSource;
private LiquibaseProperties properties;
public LiquibaseConfig(DataSource dataSource, LiquibaseProperties properties) {
this.dataSource = dataSource;
this.properties = properties;
}
#Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new BeanAwareSpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog(this.properties.getChangeLog());
liquibase.setContexts(this.properties.getContexts());
liquibase.setDefaultSchema(this.properties.getDefaultSchema());
liquibase.setDropFirst(this.properties.isDropFirst());
liquibase.setShouldRun(this.properties.isEnabled());
liquibase.setLabels(this.properties.getLabels());
liquibase.setChangeLogParameters(this.properties.getParameters());
liquibase.setRollbackFile(this.properties.getRollbackFile());
return liquibase;
}
}
inside which we new an extended class of SpringLiquibase: BeanAwareSpringLiquibase
public class BeanAwareSpringLiquibase extends SpringLiquibase {
private static ResourceLoader applicationContext;
public BeanAwareSpringLiquibase() {
}
public static final <T> T getBean(Class<T> beanClass) throws Exception {
if (ApplicationContext.class.isInstance(applicationContext)) {
return ((ApplicationContext)applicationContext).getBean(beanClass);
} else {
throw new Exception("Resource loader is not an instance of ApplicationContext");
}
}
public static final <T> T getBean(String beanName) throws Exception {
if (ApplicationContext.class.isInstance(applicationContext)) {
return ((ApplicationContext)applicationContext).getBean(beanName);
} else {
throw new Exception("Resource loader is not an instance of ApplicationContext");
}
}
#Override
public void setResourceLoader(ResourceLoader resourceLoader) {
super.setResourceLoader(resourceLoader);
applicationContext = resourceLoader;
}}
BeanAwareSpringLiquibase has a static reference to ResourceLoader aforementioned. On Spring Bootstartup, 'setResourceLoader' defined by ResourceLoaderAware interface will be invoked automatically before 'afterPropertiesSet' defined by InitializingBean interface, thus the code execution will be like this:
Spring Boot invokes setResourceLoader, injecting resourceLoader(applicationContext) to BeanAwareSpringLiquibase.
Spring Boot invokes afterPropertiesSet, performing Liquibase update including customChange, by now you already have full access to applicationContext
PS:
Remember adding your Liquibase config bean package path to #ComponentScan or it will still use LiquibaseAutoConfiguration instead of our own LiquibaseConfig.
Prepare all beans you need in 'setUp' before 'execute' would be a better convention.
The classes referenced in your changeset.xml are not managed by Spring, so the cool stuff like DI will not work.
What you can do is to inject Spring beans into Non-Spring objects. See this answer: https://stackoverflow.com/a/1377740/4365460
I accomplished this by overriding the Spring Liquibase configuration and setting a static field on the custom task. Setting the fields in the configuration ensures that it is set before the changeset runs.
This is not possible to do with every bean, because some beans (like JPA repositories) are dependent on the liquibase bean. Liquibase runs changelogs when the SpringLiquibase bean is initialized, but the entire Spring context is not completely loaded at that point. If you try to autowire a bean that depends on liquibase, you'll get an exception on startup.
I also think that this technique is safer than exposing the entire application context statically. Only the fields that are needed are passed to the task, and those are not publicly accessible afterward.
/**
Task that has a static member that will be set in the LiquibaseConfiguration class.
*/
public class MyCustomTask implements CustomTaskChange {
private static MyBean myBean;
public static void setMyBean(MyBean myBean) {
MyCustomTask.myBean = myBean;
}
#Override
public void execute(Database database) throws CustomChangeException {
try {
JdbcConnection jdbcConnection = (JdbcConnection) database.getConnection();
// do stuff using myBean
} catch (DatabaseException | SQLException e) {
throw new CustomChangeException(e);
}
}
}
/**
Extend SpringBoot Liquibase Auto-Configuration
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseConfiguration
*/
#Configuration(proxyBeanMethods = false)
#ConditionalOnMissingBean(SpringLiquibase.class)
#EnableConfigurationProperties({DataSourceProperties.class, LiquibaseProperties.class})
public static class MyLiquibaseConfiguration
extends LiquibaseAutoConfiguration.LiquibaseConfiguration {
/**
* Autowire myBean and set it on {#link MyCustomTask}.
*
* #param properties The {#link LiquibaseProperties} to configure Liquibase.
* #param myBean my bean.
*/
public MigrationLiquibaseConfiguration(LiquibaseProperties properties, MyBean myBean) {
super(properties);
MyCustomTask.setMyBean(myBean);
}
}
cdi don't injects entitymanager, always the nullpointer. Following configuration:
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="tutoroo" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/tutoroo</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</properties>
</persistence-unit>
</persistence>
public class ProdutorEntityManager implements Serializable {
private EntityManagerFactory factory = Persistence.createEntityManagerFactory("tutoroo");
//private EntityManager entityManager = factory.createEntityManager();
#Produces
#PersistenceContext
#RequestScoped
public EntityManager criaEntityManager(){
return factory.createEntityManager();
}
public void dispose(#Disposes EntityManager em) {
em.close();
}
}
public class UsuarioDaoImp implements UsuarioDao {
#Inject
private EntityManager manager;
public void salvar(Usuario usuario) {
manager.persist(usuario);
}
}
When I debug the EntityManager UsuarioDaoImp class, this exception occurs: com.sun.jdi.InvocationException occurred invoking method.
I do not know what I'm doing wrong. Can anyone help?
Server is: jboss-as-7.1.1
First off, don't create the persistence units yourself in an app server, but let the server inject it for you.
Here's why, from JavaDocs:
The Persistence class is available in a Java EE container environment as well; however, support for the Java SE bootstrapping APIs is not required in container environments.
Not sure how jbos-as-7 behaves, but it is generally discouraged because of reasons such as loosing JTA support.
For simplicity, I assume you only have one persistence unit in your application. Please ask and I'll edit if you need examples for an application with multiple persistence units.
To simply use the entity manager in any CDI managed bean:
public class CDIBean {
// the container injects it
#PersistenceContext
private EntityManager em;
// just use it
public void someMethod(Entity someEntity) {
this.em.persist(someEntity);
}
}
That's all there is to it.
However, in many examples, a combination of producers / disposers are declared for various reasons. I bet this is where the confusion comes from. Some of the use cases:
To allow you to use #Inject EntityManger em; instead of #PersistenceContext EntityManager em;
// to make it available for injection using #Inject
public class CDIProducer {
// again, the container injects it
#PersistenceContext
private EntityManager em;
// this will have the default dependent scope
#Produces
public EntityManager em() {
return em;
}
public void dispose(#Disposes EntityManager em) {
em.close();
}
}
// to use it
public class CDIBean {
#Inject
private EntityManager em;
// just use it
public void someMethod(Entity someEntity) {
this.em.persist(someEntity);
}
}
or to bind an entity manager to a particular scope.
// to make it available for injection using #Inject, and bind it to the #RequestScope
public class CDIProducer {
// again, the container injects it
#PersistenceContext
private EntityManager em;
// this will be in the request scope
#Produces
#RequestScoped
public EntityManager em() {
return em;
}
public void dispose(#Disposes #RequestScoped EntityManager em) {
em.close();
}
}
// to use it
public class CDIBean {
#Inject
private EntityManager em;
// just use it
public void someMethod(Entity someEntity) {
this.em.persist(someEntity);
}
}
Finally, the method producers above can be converted to field producers. This is equivalent to the last example:
// to make it available for injection using #Inject, and bind it to the #RequestScope
public class CDIProducer {
#PersistenceContext
#Produces
#RequestScoped
private EntityManager em;
public void dispose(#Disposes #RequestScoped EntityManager em) {
em.close();
}
}
I think that #RequestScoped is not allowed as parameter injection.
I'm using decorator pattern in java ee 7 (glassfish 4).
I've this decorator
#Decorator
public class FooIndexer implements FooService {
#Inject
#Delegate
FooService fooService;
private Logger logger = Logger.getLogger(FooIndexer.class.getName());
//#Inject
//Indexer indexer;
#Override
public Foo create(Foo foo, boolean index) {
fooService.create(foo, index);
if (index) {
System.out.println("Im in");
}
return foo;
}
}
And this ejb class
#Stateless(name = "fooService")
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#DeclareRoles({"ADMINISTRATOR", "USER"})
public class FooServiceImpl implements FooService {
#PersistenceContext(unitName = "foo")
private EntityManager em;
#Resource(lookup="java:comp/EJBContext")
private SessionContext ctx;
/** CRUD **/
#RolesAllowed("ADMINISTRATOR")
public Foo create(Foo foo, boolean index) {
Principal cp = ctx.getCallerPrincipal();
System.out.println(cp.getName());
em.persist(foo);
return foo;
}
}
When I use this decorator pattern, EntityManager in EJB is null (without decorator, everything goes fine). I supose is because of decorator use #Inject instead of #EJB annotation (#EJB annotation can't be used in #Decorator), and EntityManager is not being injected.
But, what can I do to get entitymanager will be injected using #decorator?
Thank you
Try adding an empty beans.xml in your META-INF, this will activate CDI bean discovery. I had a similar issue with my project.
See oracle doc here : http://docs.oracle.com/javaee/6/tutorial/doc/gjbnz.html
You must create an empty beans.xml file to indicate to GlassFish Server that your application is a CDI application. This file can have content in some situations, but not in simple applications like this one.
http://docs.oracle.com/javaee/6/tutorial/doc/gjbju.html#gjcvh
Good luck !
Alexander Kirilov