NullPointerException and #EJB - jboss7.x

I use EJB3+JavaEE6+JBoss. I am absolutely newbie in EJB. I wrote this code:
package server.ejb;
#Remote
public interface HelloUser
{
void sayHello( String name );
}
#Stateless
public class HelloUserBean implements HelloUser
{
#Override public void sayHello( String name )
{
System.out.println( "Hello " + name );
}
}
Having assebled this code with Maven and deployed it on JBoss, I wrote a client:
import server.ejb.HelloUserBean;
import javax.ejb.EJB;
public class Test
{
#EJB
public static HelloUserBean bean;
public static void main( String... args )
{
bean.sayHello( "Alex" );
}
}
After compiling, I've got NullPointerException. It said that bean was null. Using JDNI + PersistentContext I could get a success, but I still can't use DI as well. Please, help me
I reorginized my code! Actually I wrote another server-side project with the same sence and a standalone client-app. Here is the structure of server-side app:
#Remote
public interface EchoRemote{
String getMessage();
}
#Stateless
public class EchoBean implements EchoRemote{
#Override
public String getMessage(){
return "Hello From Stateless Bean";
}
}
public class InvokationClient{
#EJB
private EchoRemote bean;
public String getMessage(){
return bean.getMessage();
}
}
And here is the client-side standalone app:
import com.steeplesoft.client.InvokationClient;
public class Main{
public static void main( String... args ) throws IOException{
InvokationClient client = new InvokationClient();
FileWriter fileWriter = new FileWriter( "D:/invokation_client_test.txt" );
fileWriter.write( client.getMessage() );
fileWriter.close();
}
}
I've got empty file and NullPointerEception in console
I hope you can help me :) It's tremendously important for me!!!

So you start your Test-class standalone in a separate JVM. Where did you configure to which JBoss it should connect? Which component does the dependency injection? Since you don't have a DI container that manages the Test-class and since the connection to JBoss is not configured anywhere, this can't work.
In order to make it work, you can do the following:
1) Write a Servlet, use #EJB in the Servlet and deploy it on JBoss. Put your EJB and the Servlet in the same WAR to make it easy. The Servlet is managed by the container and DI works. As a newbie with EJB I would do this first.
2) Do a JNDI-Lookup and call your EJB from a standalone client as described in https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI
3) Use an Application Client Container (ACC) as described in http://blogs.steeplesoft.com/posts/2011/02/22/java-ees-buried-treasure-the-application-client-container/ Deploy the EAR to jboss and invoke the client locally
$JBOSS_HOME/bin/appclient.sh --host remote://localhost:4447 ./local/path/to/enterpriseapplication-0.1-SNAPSHOT.ear#appclient-0.1-SNAPSHOT.jar
Remark: When I tried the example from blogs.steeplesoft.com, I had problems with the Swing classes, but it did work JBoss EAP 6.2, when I removed the Swing classes.

Related

CDI doesn't work in a simple adapter

I've added the CDI feature to the server.xml file<feature>cdi-1.2</feature>.
My maven module contains the beans.xml inside the <module_name>/src/main/resources/META-INF folder.
This is the beans.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<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"
version="1.1" bean-discovery-mode="all">
</beans>
But when I use the #Inject annotation it doesn't work, my bean is always null.
Code:
package ch.webapp.presentation;
...
#Path("/test/")
public class MyController {
#Inject
private MyService myService;
#GET
#Path("/foo/{count}")
#OAuthSecurity(scope = "login")
#Produces("application/json")
public Response news(#PathParam("count") int count) {
return Response
.ok(myService.getBar(count))
.build();
}
}
EDIT:
That's my bean
package ch.webapp.service;
...
#RequestScoped
public class MyService {
public String getBar(int count) {
return "foo";
}
}
I initialize jax-rs by extended the MFPJAXRSApplication class
package ch.webapp;
...
public class AccountApplication extends MFPJAXRSApplication {
#Override
protected void init() throws Exception {
}
#Override
protected void destroy() throws Exception {
}
#Override
protected String getPackageToScan() {
return getClass().getPackage().getName();
}
}
Environment details:
Launching mfp (WebSphere Application Server 8.5.5.8/wlp-1.0.11.cl50820151201-1942) on Java HotSpot(TM) 64-Bit Server VM, version 1.8.0_172-b11 (en_CH)
Console Product version: 8.0.0.00-20180717-175523
What's wrong?
First it seems that websphere jax-rs implementation does not integrate jax-rs resources automatically unless you annotate them appropriately.
Put the jax-rs in a CDI managed context by annotating it appropriately
#Path("/test/")
#javax.enterprise.context.RequestScoped
public class MyController {
#Inject
private MyService myService;
#GET
#Path("/foo/{count}")
#OAuthSecurity(scope = "login")
#Produces("application/json")
public Response news(#PathParam("count") int count) {
return Response
.ok(myService.getBar(count))
.build();
}
}
Also be sure that the annotation used for your service is
#javax.enterprise.context.RequestScoped
Based on the inputs provided by you please go through the below checklist.
Your services and controllers are in the same module and its packaging type is war, So you must place your beans.xml in this path src/main/resources/WEB-INF/beans.xml. (If this is Java EE 7 application then beans.xml is optional.
In your AccountApplication class try hardcoding the package name to ch.webapp.presentation
#Override
protected String getPackageToScan() {
return "ch.webapp.presentation";
}
This is just to check Behaviour of MFPJAXRSApplication.getPackageToScan() method whether it is scanning the specified package only or its child packages too.
Except these, everything seems fine to me. If this still doesn't work add complete application startup logs so that community can find the root cause of it.
This is classical mistake. CDI works for managed beans (for instance EJB's and servlets). If you want to enable it on your JAXRS bean, you have to make it "managed", that is annotate MyController as (for instance) javax.annotation.ManagedBean or as a javax.ejb.Stateless.
Also beware that in case of webapp (.war), the beans.xml file has to be located in the WEB-INF folder !

How to inject EJB from different EAR in same glassfish

I have been trying to implement this design for couple of days ago and had no success. (before continuing I tell that I have read this article "How can I inject an EJB from an other application on the same GlassFish Server?" and other than glassfish-ejb-jar.xml I tried everything in it )
I have 2 ear application. test.ear is my main app which I want to test it, but I don't want to add any remote interfaces in this project, so I created another .ear(automation.ear) which contains remote interfaces and inject EJBs from test.ear . so my standalone application calls automation app and can not access test application directly.
each application contains these modules: entities, ejb , ear (for example automation application contains :automation-entities, automation-ejb, automation-ear)
here is my journey :
(I deployed test.ear before all these attempts)
-first try: I added test.ejb with ejb type as a maven dependency to automation-ejb pom.xml and injected EJB of test.ear in one of the beans of automation project and gave it a mappedName; it worked however I realized that it is a false positive and it actually doesn't go to the implementation of test.ear. it uses the copy it has (because of dependency)
- second try: I added a plugin in pom.xml of test.ear to create ejb-client for me (which only contains the interfaces and not the implementation) and added this .jar to automation pom.xml as a dependency, then injected the ejb gave it mappedName and try to deply ; well it complained about not finding the class!--> can't deploy
- third try: I added a copy of the interface I wanted to use(from test.ear) in automation.ear and removed the dependencies in pom.xml of automation. injected EJB and gave it the mappedName; tried to deploy and no luck ! still can't find the class--> can't deploy
Here are my classes:
test.ear application
package com.ericsson.test.service;
import javax.ejb.Local;
#Local
public interface TestService1 {
public String TestMethod1();
}
//////////////////////////////////////////////////////
package com.ericsson.test.service;
import javax.ejb.Local;
import javax.ejb.Stateless;
#Local(TestService1.class)
#Stateless(name = "TestService1")
public class TestServiceBean1 implements TestService1{
#Override
public String TestMethod1() {
return "Test Method1";
}
}
automation.ear application
#Remote
public interface RemoteInterfaceTest{
public void doSomething();
}
////////////////////////////////////////////////////////////////////////
package com.ericsson.test.service;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.naming.InitialContext;
#Singleton
#Startup
public class RemoteInterfaceTestBean implements RemoteInterfaceTest {
#EJB(mappedName = "Test-Server-Local/test-ejb-0.0.1-SNAPSHOT/TestService1/local")
private TestService1 testService1EJB;
#PostConstruct
public void doSomething() {
try {
InitialContext ic = new InitialContext();
TestService1 service1 = (TestService1) ic
.lookup("java:global/Test-Server-Local/test-ejb-0.0.1-SNAPSHOT/TestService1");
System.out.println(service1.TestMethod1());
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("OOOOOOPPPPPPSSSSSSSSS ! First try");
}
try {
testService1EJB.TestMethod1();
} catch (Exception e) {
System.out.println("OOOOOOPPPPPPSSSSSSSSS ! Second try");
}
}
}
and this is the exception I get:
SEVERE: Exception while deploying the app [automation-csdp-remote] : Cannot resolve reference Local ejb-ref name=com.ericsson.test.service.RemoteInterfaceTestBean/testService1EJB,Local 3.x interface =com.ericsson.test.service.TestService1,ejb-link=null,lookup=,mappedName=Test-Server-Local/test-ejb-0.0.1-SNAPSHOT/TestService1/local,jndi-name=,refType=Session
I have tried played with it like 1000 times, I checked the glass fish and the class is there, why it can not find it ? any idea would be greatly appreciated.
I am using EJB 3.x , glassfish 3.1.2 , maven 3.0.5, eclipse kepler

Inject EJB into JAX-RS 2.0 subresource when subresource is got via ResourceContext

I am using Jersey 2.8 with Glassfish 4.0.
I have a resource locator class which looks like below
#Path("/")
#ManagedBean
public class MyServiceLocator {
#Context
ResourceContext rc;//javax.ws.rs.container.ResourceContext
#EJB
private MyEJBHome myEJB;
#Inject//javax.inject.Inject
MySubService mss;
#Path("/mysubservice")
public MySubService getMySubService() {
return rc.getResource(MySubService.class);
//also tried return rc.initResource(new MySubService());
}
}
and a sub resource class which is
#ManagedBean
public class MySubService {
#EJB
public MyEJBHome myEJB;
#Context
HttpHeaders heads;
/*#Inject
private myEJBHome myEJB2;*/
#Path("/mypath")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Object doSomething(#Context SecurityContext securityContext) {...}
}
beans.xml file is put to META-INF and WEB-INF.
In MyServiceLocator class private MyEJBHome myEJB is injected successfully. And MySubService mss object is injected successfully and with EJB injected into it.
The problem is that when MySubService is got via ResourceContext the EJB is not injected into it.
Previously i used Glassfish 3 and Jersey 1.17 with proprietary ResourceContext and absolutely the same code worked ok.
I googled a lot and read a lot of similar (but a bit different) questions and as i understood non JAX-RS stuff (EJB in my case) can't be injected when sub resource is got via ResorceContext. Is it true? If yes how can i work it around?
The one possible solution is to inject sub resource objects to the resource locator class but there are too many of them and it seems to be very ugly.
EDIT Injection with #Inject works if to create a binder, bind ejb class to ejb interface and register that binder. But i don't want to describe binding for hundreds of my ejbs. Also as i understand it is specific binding fir HK2 system and i don't want to be linked to it.
Different actions with setting #Named annotations and trying to inject via CDI didn't help. It seems that when getting sub-resource via ResourceContext Jersey uses only HK2 and that's why CDI can't do it's work. Is that correct?
The only appropriate solution i found was to create my own annotation and inject provider.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface EJBInject {
String beanName();
}
#Provider
public class EjbInjectProvider implements InjectionResolver<EJBInject> {
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
try {
String beanName = injectee.getParent().getAnnotation(EJBInject.class).beanName();
return new InitialContext().lookup("java:global/MyApp/" + beanName);
} catch (Exception e) {
return null;
}
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
Then ejb can be injected using that annotation like
#EJBInject(beanName="MyBean")
MyBeanEJBHome myBean;
In such case any standard EJB injections which MyBeanEJBHome might need work correctly, too.

EJB Injection failure on deploy

I've got a problem exxh EJB's.
First of all, my setup: I am using GlassFish & JEE6. I have got a REST-Service packaged as a WAR and a bean packaged as an EJB-Jar. They are not inside an EAR.
The EJB should be used from the REST-WAR via #EJB, but when I try to deploy the WAR, GlassFish shows this error:
Error occurred during deployment:
Exception while deploying the app [exx-upload-1.0] : Cannot resolve reference Local ejb-ref name=com.ex.exx.model.FileUpload/ocr,Local 3.x interface =com.ex.exx.api.IOCRService,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session. Please see server.log for more details.
(The EJB was deployed before without any erros).
I have no clue why. Here is the EJB Code:
Interface:
#Local
public interface IOCRService {
public String performOCRonImage(BufferedImage input);
}
and Implementation:
#Stateless
#LocalBean
public class OCRScanner implements IOCRService {
private Logger logger = Logger.getLogger(this.getClass().getName());
private final static String NOT_RECOGNIZED = "Can not regocnize text";
/**
* Default constructor.
*/
public OCRScanner() {
logger.log(Level.INFO, "### OCR SCANNER BUILD" + this);
}
public String performOCRonImage(BufferedImage input) {
logger.log(Level.INFO, "### OCR SCANNER CALLED" + this);
}
...
And here is the important part in the WAR:
public class FileUpload {
private final File PROPERTIES_FILE = new File(
"fileUploadProperties.properties");
private final String PARAMETER_NAME = "file";
private final Logger logger = Logger.getLogger(this.getClass().getName());
#EJB
private IOCRService ocr;
public Response uploadFile(...) {
// do some stuff
logger.log(Level.INFO, "### EJB" + ocr.toString())
}
Anny suggestions? I can not find my failure here.
Solved this, by replaceing #Local with #Remote.
This works, however, I am not satisfied as I do not understand why.
Basically, given the specs (eg. explained in the tutorial), an application can only access other application's EJB, if they are decorated with #Remote.
Thus, you have 3 options:
decorate your EJB with #Remote (what you have done),
package both together inside an ear (as they would reside in the
same application then). But if you intent to deploy them in seperate
applications or even seperate servers, use 1.)
use CDI with #Inject, but this will still only discover the EJB if
either in the same application, or decorated as #Remote if not.
HTH,
Alex
You should not use #EJB if the target is not an EJB. I guess this is your case because you are trying to inject into a class in your WAR.
Instead use:
#Inject
private IOCRService ocr;
Basically, #Inject is better in most cases, because:
it is more typesafe,
it supports #Alternatives
it is aware of the scope of the injected object.
Another solution it's to add #Stateless(name=""), this worked form

Dozer DozerBeanMapper Instantiation Startup EJB App Server Glassfish

Dozer's documentation states that you should only have one instance of DozerBeanMapper running in the app on the server. For initial development I ignored this, now I want to update the app to do this.
How can I instantiate the DozerBeanMapper class when the application starts on glassfish, and how would I access its "map" method in another class once the application has started or been newly deployed?
This is for EJBs so I can't use any servlet to do this.
OK, so I've finally had time to refactor this code. With the pointer from #Mikko Maunu, I am editing my question to provide the code that I have working for me for anyone who might find it useful in the future.
package com.xyz.utilities.singleton;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import org.dozer.DozerBeanMapper;
#Startup
#Singleton
public class DozerInstantiator {
private DozerBeanMapper mapper = null;
#PostConstruct
void init() {
mapper = new DozerBeanMapper();
}
public DozerBeanMapper getMapper() {
return mapper;
}
}
And here is a straight forward usecase:
Inject an EJB member variable to your client class:
#EJB
DozerInstantiator di;
Within a method somewhere in the client class you can invoke the dozer mapper like so:
Credentials credentials = di.getMapper().map(credentialsDTO, Credentials.class);
// or
Credentials credentials = new Credentials();
di.getMapper().map(credentialsDTO, credentials);
If this is wrong or off base, someone please leave a comment. Until then, this seems to work so I'll use this solution I've developed with Mikko's input.
If you are using GlassFish 3.x, then you can use EJB 3.1 Singleton Session Bean:
#Startup //initialization in application startup
#Singleton //only one instance
public class DozerInitializer {
private String status;
#PostConstruct //executed once and only once when sole instance is created
void init {
//do steps needed to instantiate DozerBeanMapper
//here
}
}