Cant inject Bean class into Restfull WebService (JAX-RS) [duplicate] - java

This question already has answers here:
Inject an EJB into JAX-RS (RESTful service)
(7 answers)
Closed 7 years ago.
I'm trying to save data acquired by Rest web service to database using hibernate/persistence.
In one of my web modules i implemented that service. Database ejb connector is placed in EJB module. They are parts of EAR application.
Every time when i call pb.addDevice() im getting java.lang.NullPointerException when puting proper url with params in browser(worked till i wanted to save it to Database). Can't find what is wrong with it. I'm using jboss 6.1.0 Final.
tried answer of Dependency injection in restful WS
and after following it step by step im alse getting nullpointer also
PS. when i changed from
#EJB
PersistenceBean pb;
to
PersistenceBean pb = new PersistenceBean();
i got null pointer on EntityManager em = emf.createEntityManager();
code:
#Stateless
#Path("/RestService")
public class RestPush {
#EJB
PersistenceBean pb;
#GET
#Path("/RegisterDevice")
public void registerDevice(
#QueryParam("deviceId") String deviceId){
Device d = new Device(true);
d.setId = deviceId;
pb.addDevice(d);
}
}
and EJB class:
#Stateless(mappedName = "PersistenceBean")
public class PersistenceBean {
#PersistenceUnit(unitName = "PersistentUnitName")
EntityManagerFactory emf;
private void persist(Object o, EntityManager entityManager) {
try {
entityManager.persist(o);
} catch (Exception e) {
logger.severe("Error writing to DB: " + e);
logger.severe("" + e.fillInStackTrace());
}
}
public void addDevice(Device d) {
try {
EntityManager em = emf.createEntityManager();
if (persist(device, em)) {
logger.info("Device with id : " + device.getId()
+ " has been added ");
} else {
logger.info("Failed to add device with id: " + device.getId());
} catch (Exception e) {
logger.severe("PersistenceBean: Could not save device.");
e.printStackTrace();
}
}
upadate:
EAR
--EarContent
--META-INF
--application.xml
EJB
--package in ejbModule
--PersistenceBean
--Device
--META-INF
--ejb-jar.xml
--MANIFEST.MF
--persistence.xml
--beans.xml
Web
--package in webModule
--Rest (auto generated class while creating Webservice)
--RestPush
--WebContent
--META-INF
--MANIFEST.MF
--WEB-INF
--web.xml
--beans.xml
stack trace:
`10:23:28,629 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/RestWeb].[Resteasy]] Servlet.service() for servlet Resteasy threw exception: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at
Caused by: java.lang.NullPointerException
at package.RestPush.registerDevice(RestPush.java:68) [:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_27]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [:1.6.0_27]

The #EJB annotation is not supposed to work for all objects.
For this to work you need to use CDI, so substitute the #EJB with #Inject and your bean will be correctly injected.
See also: Inject an EJB into JAX-RS (RESTful service)
EDIT:
Also be sure to add beans.xml to every jar/war archive containing classes you want to inject or be injected. It goes into META-INF for jars and WEB-INF for wars.
Your REST application class packaget.Rest should extend javax.ws.rs.core.Application as in:
#ApplicationPath("/root-path")
public class Rest extends Application
{
}
And according to the documentation here on JBoss 6.1 REST and CDI should work out of the box. If you specify the org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher and the org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap you are probably messing up the RestEasy/CDI classloading.
So your web.xml should look as:
<web-app version="3.0" 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 java.sun.com/xml/ns/javaee/…">
</web-app>
Anyway, I pushed a working example on github

You should add /src/main/resources/META-INF/beans.xml. This will enable injection.

I has similar issue, for me the problem was creating my RESTful bean on my own with constructor, which was dumb while using EJBs and #EJB injection:
PROBLEM:
#ApplicationPath("/")
public class RestApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
public RestApplication() {
singletons.add(new RestService());
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
SOLUTION:
#ApplicationPath("/")
public class RestApplication extends Application {
}
Hope it might save sb's time.

Related

Dispatcher-servlet cannot map to websocket requests

I'm developing a Java webapp with Spring as the main framework (Spring core, Spring mvc, Spring security, Spring data, Spring websocket are notably used).
Declaring a message-broker in a Spring context like this provides a SimpMessagingTemplate bean to the context :
<websocket:message-broker>
<websocket:stomp-endpoint path="/stomp">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic,/queue"/>
</websocket:message-broker>
I have to put this tag in my root context (applicationContext.xml), otherwise services declared in that root context cannot send notifications to users via websocket (because they need the SimpMessagingTemplate).
The thing is, if I put this tag in the root context, clients get a 404 when they subscribe to websocket. And if I put the tag in the dispatcher-servlet, then services in the root context cannot send notifications since they would need the SimpMessagingTemplate (but it is only available in the child dispatcher-servlet context).
Is there a way to "bind" the dispatcher-servlet to the broker ? Declaring the bean twice is not a correct solution.
This issue is the same as Spring : how to expose SimpMessagingTemplate bean to root context ? but looking from another angle (declaring websocket in the root context instead of in the dispatcher-servlet)
I found a dirty solution. I don't like it, but given the lack of answers on SO as well as from current and former colleagues, I had to go forward with the project and implemented a dirty fix.
The dirty fix is to Autowire the SimpMessagingTemplate in Controller and Scheduled classes (all scanned by the dispatcher-servlet, where the websocket tag is declared), and to pass the SimpMessagingTemplate as a parameter to service methods (declared in the root context).
This solution is not transparent (the SimpMessagingTemplate should be autowired directly in services ideally) but it definitely fixes the problem.
I've write a bean to do the injection after the servlet application context inited. It will search through the parent application contexts in order to inject the SimpMessageTemplate
Whatever bean that needs the template:
#Autowired(required=false) //required=false so that it won't throw Exception when startup
private SimpMessagingTemplate messagingTemplate;
PostInjectSimpMessageTemplateBean:
Place this bean in the servlet application context (ie. the same xml file that the websocket located)
(Replace "YOUR.PACKAGE.NAME")
public class PostInjectSimpMessageTemplateBean implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext servletContext = event.getApplicationContext();
ApplicationContext context = servletContext.getParent();
SimpMessagingTemplate template = servletContext.getBean(SimpMessagingTemplate.class);
while(context != null){
for(String beanName : context.getBeanDefinitionNames()){
Object bean = context.getBean(beanName);
Class<?> clazz = bean.getClass();
if(!clazz.getName().startsWith("YOUR.PACKAGE.NAME")) continue;
List<FieldWithAnnotation<Autowired>> fields = ReflectionUtils.findFieldsWithAnnotation(clazz, Autowired.class);
for (FieldWithAnnotation<Autowired> fieldWithAnno : fields) {
Field field = fieldWithAnno.getField();
if(field.getType() == SimpMessagingTemplate.class){
field.setAccessible(true);
try {
field.set(bean, template);
} catch (Exception e) {}
}
}
List<Method> methods = ReflectionUtils.findMethodsWithAnnotation(clazz, Autowired.class);
for (Method method : methods) {
Class<?>[] paramtypes = method.getParameterTypes();
if(paramtypes.length == 1){
if(paramtypes[0] == SimpMessagingTemplate.class){
method.setAccessible(true);
try {
method.invoke(bean, template);
} catch (Exception e) {}
}
}
}
}
context = context.getParent();
}
}
}

JAVA Lookup Failed for bean name in SerialContext

The Scenario goes as follows :
i'm coding a java enterprise application
first i created entity classes from database table "Derby" then i made a helper classes in a java library project then i created a session bean in the enterprise application bean and created a bean facade remote in the java library project
here is the important code part of the session bean :
#Stateless(mappedName = "officefacade")
public class OfficeFacade implements OwnerFacadeRemote {
#PersistenceContext
private EntityManager em;
and then i coded a simple client to test the methods
client code :
public class Client {
private OwnerFacadeRemote request;
public static void main(String[] args) {
// TODO code application logic here
Client x = new Client();
}
public Object getEJBBean(String beanName)
{
try
{
InitialContext ctx = new InitialContext();
return ctx.lookup(beanName);
}
catch(Exception ex)
{
System.err.println("Error : " + ex.getMessage() + "\n\n\n");
}
return null;
}
private void insert()
{
request.createOwner(new OwnerDetails("1","M","444","M","afcdv"));
}
private void display()
{
List<OwnerDetails> xx = request.getAllOwner();
}
public Client()
{
request = (OwnerFacadeRemote) getEJBBean("officefacade");
insert();
display();
}
the problem is every time i run the client i get the error that Lookup failed for 'officefacade'
here is the complete error text
> Error : Lookup failed for 'officefacade' in SerialContext[myEnv{java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFac tory, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl}
how to make sure the mapped name is being available and how to fix it so the it can be found by the lookup even if it means hard coding the mapped name in the serial context "i don't know what this is but it seem as the problem is coming from it"
any help is much appreciated and thanks in advance for your efforts and i'm pretty sure everything is implemented correctly so it's a mapped name related problem
tools of development is netbeans 8.0.2 and glassfish 4.1
Try to replace #Stateless(mappedName = "officefacade") with #Stateless(name = "officefacade"), the lookup method of the InitialContext seems to work with the bean name
See the related JavaDoc section and the related method for more details
UPDATE
Just checked Oracle's documentation on this topic - according to the information available there you might need to actually lookup for "java:module/officefacade" instead of pure "officefacade", depending on the bean context.

Jersey + Spring standalone webservice #Autowire not working

I am running Restful web-service as standalone application using Jersey.
Below are my service classes which serve's the requests.
LoginServiceImpl.java
#Component
public class LoginServiceImpl implements LoginService {
#Value("${login.service.defaultmessage}")
private String defaultMessage;
#Autowired
private EmLoginDAO emLoginDAO;
#Override
public String defaultCall() {
return defaultMessage;
}
#Override
public String updatePassword(List<Login> userList) {
System.out.println(emLoginDAO + "\n" + userList);
emLoginDAO.save(userList);
return "Passwords Updated...";
}
#Override
public List<Login> getPasswords() {
System.out.println("OBJECT: " + emLoginDAO);
List<Login> userList = null;
userList = emLoginDAO.findAll();
return userList;
}
}
LoginService.java
#Component
#Path("/user")
public interface LoginService {
#GET
public String defaultCall();
#POST
#Path(value = "/print")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.TEXT_PLAIN)
public String updatePassword(List<Login> userList);
#GET
#Path(value = "/getpassword")
#Produces(MediaType.APPLICATION_XML)
public List<Login> getPasswords();
}
Below is my spring configuration file.
<context:component-scan base-package="com.em.login" />
<context:annotation-config />
After starting the service when I call the respective method get called.
But my defaultMessage and emLoginDAO objects are null. So it is not referring to the properties and spring configuration files.
So can any one please help me to get this correct. Or to find a way to set the properties and spring configuration file paths to Jersey.
Update
Closeable server = null;
try {
DefaultResourceConfig resourceConfig = new DefaultResourceConfig(
LoginServiceImpl.class);
resourceConfig.getContainerResponseFilters().add(
new GZIPContentEncodingFilter());
server = SimpleServerFactory.create(serviceurl,
resourceConfig);
System.in.read();
} catch (IOException e) {
} finally {
if (server != null) {
try {
server.close();
} catch (IOException ex) {
}
}
}
I think this is the culprit:
DefaultResourceConfig resourceConfig = new DefaultResourceConfig(LoginServiceImpl.class);
You are using Spring's IOC to create the objects and do the autowiring, but you are not getting the instance from the Spring container. You need to get the LoginServiceImpl instance from the Spring container, and not have Jersey create it (Jersey does not know how to autowire your #Autowired properties.
You should use the Spring integration with Jersey, seen here.
Edit to respond to your comment, you posted this code:
LoginServiceImpl loginServiceImpl = (LoginServiceImpl) SpringApplicationContext.getBean("loginServiceImpl");
DefaultResourceConfig resourceConfig = new DefaultResourceConfig( loginServiceImpl.getClass());
You are creating a loginServiceImpl via the spring container, and I'll bet if you check your autowired fields will be there.
However, the second line where you use loginServiceImpl.getClass() this is going to create a new LoginServiceImpl, which is not the same one as the loginServiceImpl you got from the context, so you still are going to have the same problem.
You could take a look at Microserver, that will do all the wiring between Jersey and Spring for you (and setup a Grizzly webserver). From the tags I notice you are using Spring boot, with Microserver: micro-boot module you can do (in a class in package com.em.login):
public static void main(String[] args){
new MicrobootApp(()->"test-app").run();
}
And it should wire up Grizzly, Jersey & Spring with Spring-boot enabled for any backend (non-Jax-rs) dependencies.
Alternatively without Spring Boot (plain old Jersey and Spring)
public static void main(String[] args){
new MicroserverApp(()->"test-app").run();
}
To do it manually, you will need to add the Jersey-Spring integration jar to your classpath and make sure both are configured in a way that interoperates (i.e. I think a registering Spring ContextListener is essential). There is an example app here.
Have you configured those two in your spring configuration files?
I mean have you annotated EmLoginDAO also as stereotype Component?
I got this working.
Referred the this part of the Jersey documentation.
Below is the code I have used to make this working.
ResourceConfig resourceConfig = new ResourceConfig(LoginServiceImpl.class);
resourceConfig.register(org.glassfish.jersey.server.filter.UriConnegFilter.class);
resourceConfig.register(org.glassfish.jersey.server.spring.SpringComponentProvider.class);
resourceConfig.property(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
resourceConfig.property("contextConfigLocation", "classpath:/spring-config.xml");
URI serviceUri = UriBuilder.fromUri(serviceHost).port(servicePort).build();
server = SimpleContainerFactory.create(serviceUri, resourceConfig);
Thank you all for helping.

Jersey Endpoint+OSGi Dependency, Keeping Track

I have a Jersey endpoint which uses a custom OSGi Service ExceptionManager Service.
#Path("service")
public class ServiceFacade {
private volatile ExceptionManager exceptionManager;
public ServiceFacade() {
BundleContext bC = FrameworkUtil.getBundle(ServiceFacade.class).getBundleContext();
ServiceReference<ExceptionManager> sR = bC.getServiceReference(ExceptionManager.class);
if (sR != null)
this.exceptionManager = bC.getService(sR);
}
#GET
#Consumes({MediaType.APPLICATION_JSON})
#Produces(MediaType.APPLICATION_JSON)
public Response sayHello() {
try {
if (exceptionManager == null)
return Response.status(Status.SERVICE_UNAVAILABLE).build();
// Do some work...
} catch (Exception e) {
exceptionManager.handle(e);
}
}
}
This Jersey class is added to the Jersey Application as a simple class, that means that every time a user hits this endpoint, a new instance of this class is created to handle the request. As you can see, the class contains a constructor which initializes the ExceptionManager Service. My question is, isn't there a simplified way of retrieving the service without going to BundleContext?
I have seen DependencyManager, but this bundle seems to only add the dependencies to the class (ServiceFacade in this case) during the Activation process, but that dependency resolution is too early this has to be done during run-time, every time an instance is created. Bellow is an approximation with DependencyManager but is not a solution for this:
public class Activator extends DependencyActivatorBase {
#Override
public void init(BundleContext bundleContext, DependencyManager dependencyManager) throws Exception {
dependencyManager.add(createComponent()
.setImplementation(ServiceFacade.class)
.add(createServiceDependency()
.setService(ExceptionManager.class)
.setRequired(true));
}
}
Thanks.-
You can obtain the reference to an OSGi service without accessing to BundleContext by using Declarative Services. A tutorial can be found here.
You can make the endpoint a singleton resource. This way you can let the dependency manager create a single instance and inject services and then add that instance to the Jersey application.
There are a few limitations, like Jersey's field or constructor injection does not work. You also have to be careful about concurrency when using fields of the resource.

How to look up an object of a class

There is an application ABC which dependency is on an ejb module 'XYZ' but both are deployed & running on different server machine.
ABC deployed on JBoss AS & IP address is 192.108.1.1
XYZ deployed on JBOss As & IP address is 192.108.1.2
in XYZ ejb module, there is a xyzService class which access db and populates the data into a bean class, please see below
#Stateless(mappedName = "ejb/xyzService")
#TransactionManagement(TransactionManagementType.BEAN)
public class XyzService extends XyzPersistenceService implements xyzRemote, xyzLocal {
public List<xyzBean> fetchDataFromDB (List<String> idList) throws Exception
{
List<xyzBean> detailList = null;
try {
// gets data from DB and populate into a bean class i.e. xyzBean
} catch (Exception e) {
new myExceptionClass("error", e);
}
return detailList;
}
}
//Bean class
public class xyzBean{
String Id;
String name;
// getter-setter here
}
Now i want,
1. lookup the object of service class of XYZ module
2. invoke the method
3. gets the list of bean class
Could you please guide me how to do that, while i am bit confused how to start doing this from my ABC application ?
This example is geared towards connecting to the XYZ bean, but you could easily use it with a little adjustment for the ABC bean. Anyway, here is how you can lookup your xyzService.
Explicitly
By #EJB annotation
By ejb-ref
Explicitly
// Lookup the EJB from JNDI
InitialContext ctx = new InitialContext();
xyzRemote remoteobj = (xyzRemote)ctx.lookup("ejb/xyzService");
By annotation
#EJB (mappedName="ejb/xyzService")
private xyzRemote remoteobj;
With annotation the container injects an instance of the remote EJB bean through DI.
By ejb-ref
In your client class, add the below code. This is only a
InitialContext ctx = new InitialContext();
xyzRemote remoteobj = (xyzRemote) ctx.lookup("java:comp/env/ejb/xyzService");
As for configuring your client's InitialContext, you'll need a jndi.properties file
### JBossNS properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://192.108.1.2:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

Categories