I'm trying to inject a bean located in a different jar file then the bean i'm trying to inject it into. Both beans are just basic #Stateless beans with local and remote interfaces.
If i use the normal injection
#EJB
IBean injectedBean;
or
#EJB
IBeanLocal injectedBean;
i get a NullPointerException when deploying the application.
If i use:
#EJB(mappedName="Bean")
IBean injectedBean;
or
#EJB(mappedName="Bean")
IBeanLocal injectedBean;
everything works and JBoss throws no deployment errors.
I might mention i use JBoss 5.
The bean class i'm injecting is declared as:
#Remote
public interface IBean
#Local
public interface IBeanLocal extends IBean
#Stateless(name = "Bean")
public class Bean implements IBean, IBeanLocal
My problem is that as specified in the documentation the mappedName property is vendor-specific. Is there any other way i could get this to work?
SOLVED:
I managed to solve the problem.
The problem was that i tried to deploy both jars individually which meant that each would get it's own ClassLoader in JBoss so that they couldn't find each other and would return a NullPointerException when trying to inject the bean.
The sollution was to add the jars to an ear and add an META-INF containing an application.xml looking like this:
<application xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"
version="1.4">
<display-name>Simple example of application</display-name>
<module>
<ejb>ejb1.jar</ejb>
</module>
<module>
<ejb>ejb2.jar</ejb>
</module>
</application>
I also had to change some JNDI lookups i made to match the new structure by adding the ear name before the classes: "ear-name/bean"
After this i just added the jars to the ear and everything deployed nicely.
You need to declare the local interface in order to have JBoss find the bean based on the interface only (assuming you're using EJB 3.0):
#Stateless(name = "Bean")
#Local ( IBeanLocal.class )
#Remote ( IBean.class )
public class Bean implements IBean, IBeanLocal { ... }
Edit: IBean is a remote interface (see comment).
Try injecting your bean with #EJB(beanName = "Bean")
Not sure if it'll work, but we had a similar issue and it was caused by the lack of the beanName attribute.
Related
I have an EJB deployed in an EAR:
#Stateless
#Remote(ActorProvider.class)
public class ActorServiceClient implements Serializable, ActorProvider { ... }
Here is the remote interface:
#Remote
public interface ActorProvider { ... }
Now, I have a separate WAR being deployed with the following class:
#Singleton
#Startup
public class ShiroStartup implements IShiroStartup {
#EJB
ActorProvider actorProvider;
...
}
The idea being that I deploy my actor service in an EAR, and I separately deploy a client project that gets the ActorProvider which Shiro uses for authorization (this is ancillary, but what I'm using it for).
I get an error starting the ShiroStartup (after I have deployed the EAR with the provider in it):
No EJB found with interface of type 'consumers.ActorProvider' for binding realm.ShiroStartup/actorProvider
Why can't I do this? If I put the Provider in the war with the ShiroStartup it works fine, but it will not inject across deployments. Why is that? This is Wildfly 9 using JavaEE 7.
1., The EJB and WAR modules should take place in the same EAR
or
2., Include the EJB jar into the classpath of the WAR
or :)
3., with portable JNDI names (for remote interfaces):
https://docs.oracle.com/cd/E19798-01/821-1841/girgn/index.html
In particular: java:app[/module name]/enterprise bean name[/interface name]
I have a very simple Spring JPA Repository which is packed into a JAR and stored in the local maven repository.
I can use the JPA Repository in my Unit-Tests and in a little Main-Test-Routine. It gets #Autowired without any problem.
Here is the definition of my JPA-Repository:
public interface TestRepo extends CrudRepository<Seminar , Integer > {
List<Seminar> findAll();
}
And in the applicationContext.xml of the JAR:
<jpa:repositories base-package="de.dmsb.my.core"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager">
</jpa:repositories>
There a also some other Services defined in this JAR too which can be used in the JAR and in the WAR, which includes the JAR as a dependency with maven.
But as soon as a try to #Autowire the the JPA-Repository:
#Autowired
TestRepo testRepo;
I get an runtime error that there is no suitable bean defined. Other beans work - but as soon as it comes to JPA-Repositories it doesn't work.
I mean of course you cannot #Autowire a interface - and in the WAR there is not JPA-Repository bean in the ApplicationContext when I debug it - all the other beans from the JAR are there.
Any idea what the problem might be?
I have a module/jar that I've created and am using as a util library. I created a service in there like so:
#Service
public class PermissionsService { ... }
... where this resides in a package here: com.inin.architect.permissions and in my main application, I'm referencing/loading this jar (i.e. set as a dependency in the maven POM.xml file for the app) like so:
<dependency>
<groupId>com.inin.architect</groupId>
<artifactId>permissions</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
and within the application I want to use that service like:
#Autowired
PermissionsService permissions
In the application's spring setup, I've got this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.inin.generator", "com.inin.architect.permissions" })
public class WebConfig extends WebMvcConfigurerAdapter implements ServletContextAware { }
However when I run my application under tomcat, it complains that there isn't a bean for the PermissionsService: "org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ..."
So, how can I bring over the bean from the lib into my application? Surely there's a way. Do you have to set the library up as a full blown spring MVC application so that this can work? i.e. do you have to have #Configuration and #ComponentScan setup in the lib as well?
You have to scan at least the package containing the class you want to inject. For example, with Spring 4 annotation:
#Configuration
#ComponentScan("com.package.where.my.class.is")
class Config {
...
}
It is the same principle for XML configuration.
Just a note on this, but you could decouple your dependency from spring. In your #Configuration class create
#Bean public PermissionsService permissionsService(){
return new PermissionsService()
}
This will also allow it to be injected. Not that you have to remove your spring annotation, just an option making it potentially usable outside of spring.
Ok - i had exactly the same problem - i wanted to autowire a mongo db repository interface from an external jar.
I could autowire every bean from that jar with using
#SpringBootApplication(scanBasePackages = {"com.myrootpackage"})
However - autowiring the interface always failed with "Could not find blablabla..."
But the interface was in the same package as the beans i could import.
It turned out that searching for the mongo db interfaces is NOT taking the scanBasePackages from the #SpringBootApplication into consideration!
It has to be explicitly configured via
#EnableMongoRepositories(basePackages = {"com.myrootpackage"})
Or you could move the main class "up" so the default searching works also for the mongo interfaces. So i understood the problem and found a solution. But i am still a bit unhappy because i need to configure the same lookup path twice. I find it stupid honestly.
I faced the same issue while scanning other classes from other project dependencies, The scanning solution depends on the type of classes you need to scan as follows:
if they are normal #Component, #Service annotations use
#ComponentScan({"com.mypackge1","com.mypackage2"})
If the type of classes are domain objects based on entities use
#EntityScan("com.mypackge1.domain")
If JPA repository classes
#EnableJpaRepositories(basePackages = {"com.mypackage.repository"})
If Redis repository classes use
#EnableRedisRepositories(basePackages = {"com.mypackage.repository"})
Same for Mongo, etc.
You can import application-context.xml for com.inin.architect.permissions in the following manner inside your main application.
<import resource="classpath:/permissionApplicationContext.xml" />
This will enable you to autowire beans from com.inin.architect.permissions that you have defined.
I'm having trouble injecting dao bean declared on a lib jar.
So I have a jar (mine) with a persistence context, entities and daos. Here is a dao example :
#Stateless
public class SomeDao {
#PersistenceContext
private EntityManager em;
...
}
Now I want to use this dao on my main application.
A jax-rs use case :
#Path("rs")
public class WebService{
#Inject
private SomeDao dao;
#POST
public Response doPost(){
//dao is injected but nullpointer thrown on EntityManager
dao.doSomething();
}
...
}
There is a beans.xml in both project (under META-INF/ for lib, WEB-INF/ for the web application). like this one :
<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>
------------- Edit ------------
I've just found out if I remove the #Stateless annotation and the producer it works. So the problem is in fact : how to inject with CDI an EJB declared on an lib jar.
Firstly, if this a jar you create and not a third party just, simply add a beans.xml in the correct location for the jar and you'll have those objects available for injection. That's the easiest way.
If it is a third part jar, your next best idea is to create a portable extension and listen to the BeforeBeanDiscovery in CDI 1.0 or AfterTypeDiscovery in CDI 1.1 and call the addAnnotatedType method to add in those classes you need from the jar. You'd create this extension in your war / ear classpath.
The issue I am currently experiencing is that my entityManager fails to be injected during the execution of a web application deployed within an ear.
The ear is setup as follows:
/META-INF -application.xml (EJBJar +
WAR)
-MANIFEST.MF
-weblogic-application.xml (currently just the default one that eclipse
generates)
/APP-INF
-lib
-EJBClientJar (interfaces + pojos)
-other jars
-classes
EJBJar
/META-INF
-persistence.xml
/src
-Annotated classes
WAR
-Service classes
Classes are as follows:
DAO inside EJBJar
#Stateless(mappedName="AwesomeBean")
public class Awesome implements AwesomeRemote //AwesomeRemote in EJBClientJar
{
#PersistenceContext
EntityManager em;
}
public class AwesomeService //Inside WAR
{
AwesomeRemote = context.lookup (Awesome.path.to.AwesomeRemote) //Is found
}
The call stack is like this:
War -> EJBClientJar -> EJBJar
On the EJB jar the entity manager is null. Question being how do I ensure that the PersistenceContext gets injected? The JNDI lookup succeeds on the AwesomeRemote Interface. The Interface has no annotations on it.
It's probably due to the fact that you try to inject on POJO class, not on managed component. Could you try to mark it as #Stateless and public and check whether it works?
For simple testing you can also add #WebService annotation and invoke your bean with SoapUI for example.
You should read about "packaging" part of ejb specifications.
This structure should be sufficient and work:
/
/lib
EJBClientJar (interfaces + pojos)
/META-INF
persistence.xml
application.xml
EJBJar.jar
WAR.war
As some formatting was lost, I'm not sure about what wasn't right in yours.
If this still doesn't work, try removing the only tricky part from above: put all classes from EJBClientJar in root. You the just have the most simple EAR packaging possible, it just will work.
Also, if you don't use your session bean outside a web application, you could use #Local instead of #Remote .