Resteasy and Google Guice: how to use multiple #ApplicationPath and resource with #Injection? - jax-rs

I created a project to test the dependency injection offered by Google Guice in my Jax-rs resources, using Resteasy.
My intentions are:
Use multiple #ApplicationPath for the versions of my API. In each class annotated with #ApplicationPath I load a set of classes for the specific version.
Each resource have a #Inject (from Google Guice) in his constructor to inject some services.
I created two classes annotated with #ApplicationPath: ApplicationV1RS and ApplicationV2RS. In both I added the same resources classes (UserResource and HelloResource), only for my test.
My Module is configured like this:
public class HelloModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(IGreeterService.class).to(GreeterService.class);
binder.bind(IUserService.class).to(UserService.class);
}
}
When I call http://localhost:9095/v1/hello/world or http://localhost:9095/v2/hello/world, I receive the same error:
java.lang.RuntimeException: RESTEASY003190: Could not find constructor
for class: org.jboss.resteasy.examples.guice.hello.HelloResource
Well, as I expected, this not works. The Google Guice is not "smart" to instantiate the resource classes using the construtor for me.
But I can't find a way to work. To be really honest, I'm really confuse about how the Google Guice, Jetty and Resteasy play with each other in this scenario.
If I abandon the idea of use #ApplicationPath, my resources work with Google Guice configuring my HelloModule like this:
public class HelloModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(HelloResource.class);
binder.bind(IGreeterService.class).to(GreeterService.class);
binder.bind(UserResource.class);
binder.bind(IUserService.class).to(UserService.class);
}
}
But in this case, I'm passing the control to register my resources (HelloResource and UserResource) to Guice. It's not flexible for me, I can't setup my multiple #ApplicationPath.
So, what I'm missing or not understanding?
I created a project with the problemetic code. Is very easy to setup and test: https://github.com/dherik/resteasy-guice-hello/tree/so-question/README.md
Thanks!

When you have getClasses method in your Application then it tries to create instance for all the registered resources using the default constructor which is missing in our Resources class. One way is to create a default constructor and Inject the dependencies through setter Injection.
And then instead of overriding getClasses in ApplicationV1RS and ApplicationV2RS you override getSingletons. Since Resources can be Singleton.
Below are the changes that I made to make it work the way you want.
ApplicationV1RS.java
#ApplicationPath("v1")
public class ApplicationV1RS extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV1RS(#Context ServletContext servletContext) {
}
#Override
public Set<Object> getSingletons() {
Injector injector = Guice.createInjector(new HelloModule());
HelloResource helloResource = injector.getInstance(HelloResource.class);
UserResource userResource = injector.getInstance(UserResource.class);
singletons.add(helloResource);
singletons.add(userResource);
return singletons;
}
}
ApplicationV2RS.java
#ApplicationPath("v2")
public class ApplicationV2RS extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV2RS(#Context ServletContext servletContext) {
}
#Override
public Set<Object> getSingletons() {
Injector injector = Guice.createInjector(new HelloModule());
HelloResource helloResource = injector.getInstance(HelloResource.class);
UserResource userResource = injector.getInstance(UserResource.class);
singletons.add(helloResource);
singletons.add(userResource);
return singletons;
}
}
HelloResource.java
#Path("hello")
public class HelloResource {
#Inject
private IGreeterService greeter;
public HelloResource() {
}
#GET
#Path("{name}")
public String hello(#PathParam("name") final String name) {
return greeter.greet(name);
}
}
UserResource.java
#Path("user")
public class UserResource {
#Inject
private IUserService userService;
public UserResource() {
}
#GET
#Path("{name}")
public String hello(#PathParam("name") final String name) {
return userService.getUser(name);
}
}
Add #Singleton to your Service Classes.
Hope it helps.
I have also pushed the code to forked repo. check it out

Related

ejb in session context is allways null

i have created sigleton session bean which keeps one connection to my mongo database. It works well in jax-rs class when using #EJB annotation - after controller is contructed and bean is injected it calls init method anotated with #PostConstruct.
Then i created similar class, which is implementing SecurityContext. I used same pattern as in controller, but it is not working properly. init() method is never called and EJB instance is always null.
So is there a way to inject EJB to my SecurityContext implemetation ? it works well unless i try to inject and use MongoConnection
my singleton session bean I use to connect mongo database:
#Singleton
#Startup
public class MongoConnection {
#PostConstruct
public void init() {
// initialize properties
}
I use it in JAX-RS controller. it works here, also in classes inherited from EntityController.
Produces(MediaType.APPLICATION_JSON)
public class EntityController extends Application {
#Context
private UriInfo context;
**#EJB
protected MongoConnection connection;**
public EntityController() {
#PostConstruct
void init() {
...
connection.getMongo();
connection.getDatabaseName();
...
}
}
I implemented my own security context, which is looking for loged user roles in mongo database.
public class MongoSecurityContext implements SecurityContext {
**#EJB
private MongoConnection connection;**
public MongoSecurityContext() {
}
#PostConstruct
void init() {
...
connection.getMongo();
connection.getDatabaseName();
...
}
public MongoSecurityContext(ContainerRequestContext requestContext) {
token = requestContext.getHeaderString("token");
}
#Override
public boolean isUserInRole(String roleName) {
//**connection is allways null**, so it returns false;
if (connection == null)
return false;
}
}
EDIT:
I forget, i also have this warning in glassfish 4 console:
A provider extremeteacher.mongo.connection.MongoConnectionEjb registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider extremeteacher.mongo.connection.MongoConnectionEjb will be ignored
EDIT2:
#Provider
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) {
requestContext.setSecurityContext(new MongoSecurityContext(requestContext)) ;
}
}
Injection does not work for objects created with new because the container is never given control to perform the injection. I recommend moving the #EJB to the filter and passing it to the MongoSecurityContext constructor.

Google guice inject a instance created by Spring and method intercept

I use Gucie 3.0 to intercept any methods that have my defined annotation #LogRequired. However for my application, some beans are initialized by Spring with injected fields values. After calling giuce injector.injectMembers(this), the beans gets proxied by guice but all original fields values are gone. Looks like Guice re-constucts the beans and throw away all old values. Is this expected behavior or how can I solve this issue?
Create a class extends AbstractModule
public class InterceptorModule extends AbstractModule{ public void configure()
{ LogInterceptor tracing = new LogInterceptor(); requestInjection(tracing); bindInterceptor(Matchers.any(), Matchers.annotatedWith(LogRequired.class), tracing); }
}
Define the interceptor business logic
public class LogInterceptor implements MethodInterceptor { //business logic here }
Create LogService class
Public class LogService { Injector injector = Guice.createInjector(new InterceptorModule()); }
I have one of the bean example below with the getName method wants to be intercepted:
public class UserImplTwo implements IUser {
private String name;
#LogRequired
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
which is initialized by Spring context:
Finally I have a consumer to consume the bean:
public class Consumer
{
#Inject
private UserImplTwo instance;
public void setInstance(UserImplTwo instance)
{
this.instance = instance;
}
public void init()
{
// the value of name is printed out as 'hello world'
System.out.println( this.instance.getName());
LogService.injector.injectMembers(this);
// the value of name is printed out as null, should be 'hello world'
System.out.println( this.instance.getName());
}
}
Then use Spring to initialized the bean:
<bean id="consumer" class="com.demo.Consumer" init-method="init">
<property name="instance" ref="userTwo"></property>
</bean>
Please let me know if this the the right approach or if I did something wrong, because I have to use Spring to initialize some beans.
A "right approach" is probably to keep things simple and use Spring's DI if you use Spring Framework, and not try to mix and match with Guice :-)
Having said that there seems no technical reason why they can't be mixed and matched together to some degree.
I think you will have more success with another approach. One that I have used before is to make use of Spring MVC Java-based configuration. Here is the basic approach.
Create a class that extends WebMvcConfigurationSupport:
#Configuration
#Import(BeansConfig.class)
public class Config extends WebMvcConfigurationSupport {
}
Separate out your beans config (probably it can be merged with the above but I guess it's quite dull code and you normally don't want want to see it). And use it to create your beans with your Guice injector before providing them to Spring.
#Configuration
public class BeansConfig {
#Bean
public Consumer getConsumer() {
return SomeGuiceInjectorFactory.newInstance(Consumer.class);
}
}
Include this in your spring.xml (or bootstrap other ways if your servlet container is newer than mine was)
<context:annotation-config/>
<bean id="extendedWebMvcConfig" class="Config"/>
Constructor injection and most/all? other Guice goodness should work also with such scenario.
Also you won't need to configure your beans in xml.

NinjectModule and IProvider not resolving types

Here is the set up that is not working
Using Ninject V3.0
public class LoggerModule : NinjectModule{
public override void Load()
{
Bind<ILogger>.ToProvider(MyLoggerProvider);
}
}
public class MyLoggerProvider: IProvider<ILogger>
{
public object Create(IContext context){
return new OneOfMyLoggers();
}
}
In my application wherever I inject instance of ILogger (using constructor or property injection, just does matter) I never get instance of ILogger resolved.
But If do not use module and/or povider, and bind when kernel is created, everything works like a charm. The following works
public class MyDiResolver()
{
public MyDiResolver()
{
MyKernel = new StandardKernel();
MyKernel.Bind<ILogger>().To<OneOfMyLoggers>();
}
}
The same arrangement of modules and providers works fine in Ninject2.x version. Is there something different about Ninject V3.0 that I am missing?
Thanks
Try passing the module into the StandardKernel so it knows to use it:
using (IKernel kernel = new StandardKernel(new LoggerModule()))
{
ILogger logger = kernel.Get<OneOfMyLoggers>();
}

bind to property always return null

I am trying to bind a repository to property using Ninject but always get null reference of binding object. I will explain the problem using code below.
public interface IServiceRepository
{
User GetUser(string email);
IQueryable<Statistic> GetStatisticForCurrentMonth(string ip);
void InsertStatistic(ConversionModel conversionModel);
class ServiceRepository : IServiceRepository
{
//Implementation of the Interface
}
I am would like to bind the repository above to class below while the class is created. Unfortunately Repository object is always null. Maybe I have misunderstood how Ninject is working? How to solve the problem?
public class Converter
{
[Inject]
public static IServiceRepository Repository { get; set; }
private static Converter _converter;
public static Converter Instance
{
get { return _Converter ?? (_Converter = new Converter ());
}
}
Ninject activator code
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IServiceRepository>().ToMethod(context => Converter.Repository);
}
Update
I have tried to rewrite code like this
public class Converter
{
private readonly IServiceRepository _repository;
public Converter(IServiceRepository repository)
{
_repository = repository;
}
//skip code
}
The test...
[TestMethod]
public void ConverterInstanceCreated()
{
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<IServiceRepository>().To<ServiceRepository>();
Assert.IsNotNull(kernel.Get<Converter>());
}
}
gives exception
Test method PC.Tests.NinjectTest.ConverterInstanceCreated threw exception:
Ninject.ActivationException: Error activating IServiceRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IServiceRepository into parameter repository of constructor of type Converter
1) Request for Converter
I just lost, I am trying to understand how Ninject is working for about week without any success. In my case why this exception is thrown?
Also please someone post working example with one repository injection to singleton class.
Ninject does not inject statics. Change the coynverter to a non-static class and configure it as Singleton in ninject. Also use constructor injection and make the repo a private field.
Now you can inject the converter to the constructors where you need it.
Even though you are using Property injection and not Constructor injection I think it would still be
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IServiceRepository>().To<ServiceRepository>();
}
As ninject still just needs to know what concrete type to map to the Interface
I haven't tested this so apologies if it's wrong.

EJB 3.1 : Singleton bean not getting injected inside another stateless bean though both beans are getting registered

Here is my bean that is trying to inject a singleton bean InformationService :
#Path("/information/{name}")
#Stateless (name="InformationResource")
public class InformationResource {
#EJB
private InformationService appService;
#GET
#Produces(MediaType.APPLICATION_XML)
public Information getInfo(#PathParam("name") String name){
return appService.getMap().get(name);
}
#PUT
#POST
#Consumes(MediaType.APPLICATION_XML)
public Information putInfo(#PathParam("name") String name, Information info){
return appService.getMap().put(name,info);
}
#DELETE
public void deleteInfo(#PathParam("name") String name){
appService.getMap().remove(name);
}
}
This is the InformationService class
#Singleton
public class InformationService {
private Map<String,Information> map;
#PostConstruct
public void init(){
map = new HashMap<String,Information>();
map.put("daud", new Information("B.Tech","Lucknow"));
map.put("anuragh", new Information("M.Sc","Delhi"));
}
public Map<String,Information> getMap(){
return map;
}
}
Its part of a very simple JAX-RS implementation and I am deploying as war in JBoss 6.1 Final. The problem is that InformationService throwing a NullPointerException when I make the proper get request. If I initialize appService explicitly, everything works fine. Why is #EJB annotation not working ?
Are you using Jersey as REST implementation? If so, EJB injection is not supported out of the box.
This link provides more information on this and also a solution.
Check that your #Singleton is javax.ejb.Singleton.
Any other exceptions before NPE ?