This question had been asked a few times before, however the answers doesn't seem to work and/or Jersey has moved on with more changes.
I'm exposing some REST APIs using JAX-RS and Jersey (version 2.24). And I wish to annotate the interface with JAX-RS and a concrete implementation (without any annotations). However, since this patch Jersey stopped supporting this possibility. As far as I understand the spec, it doesn't strictly prohibit doing that.
If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored.
implying that it is totally okay to do that. In many cases it is good to use an interface, and have a server and client each have their respective implementations.
There are plenty of solutions out there,
Use a ResourceConfig and do a registerClasses(MyImplementation.class) . However, this doesn't work.
Disable the package scanning configuration in web.xml, create a custom javax.ws.rs.Application and do a register of your implementation from there. Doesn't work.
use a ResourceConfig and define a custom AbstractBinder and do a bind so that Jersey's dependency injection can find the concrete implementations. Doesn't work.
Use RESTEasy. RESTEasy doesn't seem to impose the interface restrictions as in Jersey. Never tried it myself.
I would appreciate if someone can share their experience with this. Any help on how to get Jersey working would be great too. As for the option (4) is it really necessary to switch ? A sample code below.
MyResource
package com.foo;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public interface MyResource {
#GET
public String sayHello();
}
MyResourceImpl
package com.bar;
public class MyResourceImpl implements MyResource {
#Override
public String sayHello() {
return "Hello Jersey";
}
}
Also have a web.xml that has the package scanning enabled to scan com.foo
If you want to separate Resource interface from implementation (allowing you to use the interface with some REST client like resteasy client) you can use #RequestScoped on the implementation. Thus, this bean could use injected resources like EJB, EntityManager, ...
Using your sample :
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public interface MyResource {
#GET
public String sayHello();
}
MyResourceImpl
package com.bar;
#RequestScoped
public class MyResourceImpl implements MyResource {
#Override
public String sayHello() {
return "Hello Jersey";
}
}
Nevertheless, you have to take into consideration that as soon as you use specific JAX-RS classes in your implementation code (like UriInfo, Response object, ...) you will create a coupling between your implementation and the JAX-RS API.
In Jersey,We should Put the class level #Path on the implementation instead of the interface.
package com.foo;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public interface MyResource {
#GET
public String sayHello();
}
MyResourceImpl
package com.bar;
#Path("/hello")
public class MyResourceImpl implements MyResource {
#Override
public String sayHello() {
return "Hello Jersey";
}
}
Related
I've created a jaxrs resource like this:
#Path(ReferenceEndpoint.PATH)
public interface ReferenceResource {
#GET
public Response download(
#PathParam(ReferenceEndpoint.Download.Parameters.ID)
String id
);
}
I'm struggling with #Stateless and RequestScoped annotations.
javax.ejb.Stateless;
javax.enterprise.context.RequestScoped;
I figure out what are they stand for, but I don't quite figure out why I see them in some code over there.
I mean, I've took a look over there, and sometimes I see #Stateless, but other times, #RequestScoped, and sometimes netiher of them.
Any lights?
I have something like this
#ApplicationPath("/")
public class MyJaxRSApplication extends ResourceConfig {
public MyJaxRSApplication() {
String[] packages = {"com.xxx.xyz.rules.rest"};
packages(packages);
}
}
I do have a security service to intercept request
package com.xxx.xyz.rules.restfilter;
#Priority(20)
#Provider
public class UrlBasedAuthorizationFilter implements ContainerRequestFilter {
}
Above code snippet is working, but I can't get my hear-around understanding how jersey scanning works. Does it takes as "com.xxx.xyz.rules.rest*".
I haven't tested it, but if what you are showing works, then it looks like a bug (rather than a feature) to me. How it's documented to work is to scan the exact package specified, and all its subpackages, recursively
com.xxx.xyz.rules.rest
com.xxx.xyz.rules.rest.sub1
com.xxx.xyz.rules.rest.sub1.sub2
com.xxx.xyz.rules.rest.sub1.sub2.tillstackoverflow
im little confused. What is the exact difference between javax.inject.Singleton and javax.ejb.Singleton?
I found a plausible explanation here:
By default, javax.ejb.Singleton session beans are transactional (section 13.3.7 of the EJB 3.1 specification) and require acquisition of an exclusive lock for every business method invocation (sections 4.8.5.4 and 4.8.5.5).
In contrast, a javax.inject.Singleton is not transactional and does not support container-managed concurrency (the major consequence being that no locking scheme is implemented by the container). [...]
If you don't need EJB features, stick with #ApplicationScoped (javax.inject.Singleton is not defined by CDI, and its semantics are therefore not governed by that specification).
To reduce future confusion, I use this small unit test (first level package name needs to be replaced):
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.junit.Test;
public class SingletonTest {
/** requires com.tngtech.archunit:archunit-junit:0.4.0 */
#Test
public void detectWrongSingletonAnnotation() {
final ClassFileImporter importer = new ClassFileImporter();
final JavaClasses classes = importer.importPackages("first_level_package");
noClasses().should().beAnnotatedWith("javax.inject.Singleton")
.as("Please use javax.ejb.Singleton instead of javax.inject.Singleton.")
.check(classes);
}
}
Since accepted answer didn't solve my problem I post my own answer. It won't be as good as article by Adam Bien but definitely will be more practical:
Consider following code:
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
#Singleton
public class DatabaseConnection {
#PostConstruct
public void init() {
System.out.println("init");
}
public ChampionComp getFirstRecord() {
return new ChampionComp("Ashe", "Teemo", "Warwick",
"Blitzcrank", "Syndra", "Anivia", "Brand", "Rammus", "Xin Zhao", "Irelia");
}
}
And this REST service:
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
#Path("/champions")
public class ChampionsAPI {
#Inject
private DatabaseConnection db;
#GET
#Produces("text/plain")
public String getClichedMessage() {
ChampionComp comp = db.getFirstRecord();
return comp.toString();
}
}
Using javax.ejb.Singleton this code works just fine. The DatabaseConnection instance is created once and injected to REST service.
However when replacing ejb in import with inject you would receive NPE in ChampionsAPI class while accessing db field - that's because your Singleton was not created (for some reason, maybe because one need to make use of interfaces while using javax.inject.Singleton ? ).
In simple clarity:
javax.ejb.Singleton is an annotation used to create an #Singleton EJB (as opposed to #Sateless EJB or #Stateful EJB)
On the other hand, javax.inject.Singleton is an annotation used to create a CDI with singleton scope
So basically, one creates a singleton EJB while the other creates a CDI with singleton scope
JBOSS 7.x has the possibility to activate schema validation on the server side by means of using an #SchemaValidation annotation on the SEI.
However I would like to customize my errors as well. Moreover I would like to change the exception into a report (result).
I've found the following question / answer on Stack Overflow. Which explains how to setup a customized ValidationEventHanlder with CXF. However, JBOSS uses it own way deployment descriptors overriding the CXF ones. It is possible to achieve the same result as with the #Schemavalidation by means of the JBOSS web service deployment descriptor. However, I was not able yet to activate my own event handler.
I'm thinking about not throwing an exception, but storing the validation result in a HTTP header or in a ThreadLocal, in order to create my own result.
Questions:
1) Is it possible to setup a ValidationEventHander in JBOSS 7.x.x (or in JBOSS 6.x.x EAP)?
2) Is it possible to override the default exception (not throwing an exception on non-fatal errors, like ranges, formats etc?) and returning a result?
Thanks!
JBOSS 7.x uses a concept called 'interceptors'. By defining an interceptor one can access the message context. There are 2 flavours of messsage contexts:
The WebService Context that is available via the #Resource annotation in the Servlet or EJB
The CXF WebService Context that is avialable to 'later interceptors' in the chain.
The latter one is available by menas of the setContextualProperty.
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.ValidationEvent;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class ValidatingInterceptor extends AbstractPhaseInterceptor<Message> {
public static String CTX_KEY_VALIDATOR_EVENTS = "event_key";
public ValidatingInterceptor() {
super(Phase.READ);
}
#Override
public void handleMessage(Message message) throws Fault {
List<ValidationEvent> validationRes = new ArrayList<ValidationEvent>();
message.put(CTX_KEY_VALIDATOR_EVENTS, validationRes);
message.setContextualProperty("jaxb-validation-event-handler", new XmlValidationHandler(validationRes));
}
}
Here is the validator that is inserted:
import java.util.List;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
public class XmlValidationHandler implements ValidationEventHandler {
private final List<ValidationEvent> results;
public XmlValidationHandler(List<ValidationEvent> results) {
this.results = results;
}
#Override
public boolean handleEvent(ValidationEvent event) {
results.add(event);
return true;
}
}
The validator adds a List to the context described in 1. and is now available for further processing in the EJB or Servlet. The SEI then looks like this:
#SchemaValidation
#InInterceptors(classes = {ValidatingInterceptor.class})
#Stateless
public class LogicBean implements SEI
Note: the #SchemaValidation is still required as annotation, since that triggers the annotation in the first place.
I'm trying to inject a Stateless EJB into my JAX-RS webservice via annotations. Unfortunately the EJB is just null and I get a NullPointerException when I try to use it.
#Path("book")
public class BookResource {
#EJB
private BookEJB bookEJB;
public BookResource() {
}
#GET
#Produces("application/xml")
#Path("/{bookId}")
public Book getBookById(#PathParam("bookId") Integer id)
{
return bookEJB.findById(id);
}
}
What am I doing wrong?
Here is some information about my machine:
Glassfish 3.1
Netbeans 6.9 RC 2
Java EE 6
Can you guys show some working example?
I am not sure this is supposed to work. So either:
Option 1: Use the injection provider SPI
Implement a provider that will do the lookup and inject the EJB. See:
#EJB injection.
Example for com.sun.jersey:jersey-server:1.17 :
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;
/**
* JAX-RS EJB Injection provider.
*/
#Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) return null;
try {
Class c = (Class)t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue() {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Option 2: Make the BookResource an EJB
#Stateless
#Path("book")
public class BookResource {
#EJB
private BookEJB bookEJB;
//...
}
See:
How to Combine REST Services with EJB 3.1
EJB 3.1 And REST - The Lightweight Hybrid
Option 3: Use CDI
#Path("book")
#RequestScoped
public class BookResource {
#Inject
private BookEJB bookEJB;
//...
}
See:
Injecting an EJB from a jar into a jax-rs class in a war
This thread is rather old, nevertheless i fought the same problem just yesterday. Here is my solution:
Just make the BookResource a managed bean through #javax.annotation.ManagedBean at class level.
For this to work you need to enable CDI with a beans.xml:
<?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>
This file needs to be in WEB-INF if the BookResource is part of a war file. If the BookResource is packaged with the ejbs put it into META-INF.
If you want to use #EJB you're done. If you want to inject the EJB through #Inject than a beans.xml must be put into the ejbs jar file into META-INF as well.
What you're doing: You're just telling the container that the resource should be container managed. Therefor it supports injection as well as lifecycle events. So you have your business facade without promoting it to an EJB.
You don't need to extend javax.ws.rs.core.Application for this to work. BookResource is as a root resource automatically request scoped.
Tested with Glassfish 3.1.2 and a maven project.
Happy coding.
You shall be able to do injection in JAX-RS resource without making it EJB or CDI component. But you have to remember that your JAX-RS resource must not be singleton.
So, you setup your application with this code. This makes BookResource class per-request JAX-RS resource.
#javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public InjectionApplication() {
// no instance is created, just class is listed
classes.add(BookResource.class);
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
With this setup, you are letting JAX-RS to instantiate BookResource for you on per-request basis and also inject all the required dependencies. If you make BookResource class singleton JAX-RS resource, this is, you put in getSingletons
public Set<Object> getSingletons() {
singletons.add(new BookResource());
return singletons;
}
then, you created instance which is not managed by JAX-RS runtime and nobody in container cares to inject anything.
Unfortunately, my answer is too long for a comment, so here goes. :)
Zeck, I hope that you are aware of what exactly you are doing by promoting your bean to an EJB, as suggested by Pascal. Unfortunately, as easy as it is nowadays with Java EE to 'make a class an EJB', you should be aware of the implications of doing so. Each EJB creates overhead along with the additional functionality it provides: they are transaction aware, have their own contexts, they take part in the full EJB life cycle, etc.
What I think you should be doing for a clean and reusable approach is this: extract the access to your servers services (which hopefully are accessed through a SessionFacade :) into a BusinessDelegate. This delegate should be using some kind of JNDI lookup (probably a ServiceLocator - yes, they are still valid in Java EE!) to access your backend.
Okay, off the record: if you really, really, really need the injection because you do not want to write JNDI access manually, you could still make your delegate an EJB, although it ... well, it just feels wrong. :)
That way at least it will be easy to replace it later with something else if you do decide to switch to a JNDI lookup approach...
I was trying to do the exact same thing. I'm using EJB 3.1 and have a deployed my app as an EAR with separate EJB project. As Jav_Rock pointed out, I use context lookup.
#Path("book")
public class BookResource {
#EJB
BookEJB bookEJB;
public BookResource() {
try {
String lookupName = "java:global/my_app/my_ejb_module/BookEJB";
bookEJB = (BookEJB) InitialContext.doLookup(lookupName);
} catch (NamingException e) {
e.printStackTrace();
}
}
#GET
#Produces("application/xml")
#Path("/{bookId}")
public Book getBookById(#PathParam("bookId") Integer id) {
return bookEJB.findById(id);
}
}
See the link below for very useful JNDI look up tips
JNDI look up tips
Arjan is right. I created another class to initialize the EJB instead of creating a bean for RS
#Singleton
#LocalBean
public class Mediator {
#EJB
DatabaseInterface databaseFacade;
to avoid null pointer with:
#Path("stock")
public class StockResource {
#EJB
DatabaseInterface databaseFacade;
...
it actually works on GF
I have the same problem, and I solved it calling te EJB by a context lookup (the injection was impossible, I had the same error NullPointerException).