Using Guice 3 with JAX-WS in Java 6 outside web container - java

We have a situation where we use JSR-330 based injections to configure our stand-alone Java 6 applications, which works very well for getting configuration parameters across all the layers.
We have also used JAX-WS web services for quite a while by using first stand-alone Metro distribution with Java 5 inside a web container, but with Java 6 we just use the Endpoint class to get a smaller footprint.
So now I have a situation where I have
A stand-alone Java 6 application - no servlet container (Jetty, Tomcat)
A Guice 3 Injector set up as I like it.
An Endpoint handling my #javax.jws.WebService annotated class which expose my methods as web services.
I would like the web service methods to either have their #Inject fields handled transparently, or to get access to the injector. I can grab it as a static field from the main method, but I'd like a cleaner solution.
Any suggestions?
(I understand from JAX-WS and Guice 3 that the http://jax-ws-commons.java.net/guice/ module does not work with Guice 3, and the workaround suggested is Tomcat specific)
Would JSR-250 #Resource annotations be useful here?

I'm not sure that I've understood every bit of the question. It looks to too easy for +500 bounty. Please post some code if that's not what you're searching for.
Anyway, a simple solution which creates a web service with dependency injection:
final Module module = new HelloModule();
final Injector injector = Guice.createInjector(module);
final HelloService helloService = injector.getInstance(HelloService.class);
Endpoint.publish("http://localhost:8080/helloService", helloService);
Below a more sophisticated solution with classpath scanning (Reflections) based on Marcus Eriksson's code from JAX-WS Guice integration. It publishes all classes which is annotated with #GuiceManaged as a webservice with Endpoint.publish().
private void initGuicedWebservices(final String packageNamePrefix)
throws Exception {
final Reflections reflections = new Reflections(packageNamePrefix);
final Set<Class<?>> guiceManaged =
reflections.getTypesAnnotatedWith(GuiceManaged.class);
for (final Class<?> clazz : guiceManaged) {
doGuice(clazz);
}
}
private void doGuice(final Class<?> clazz) throws Exception {
final GuiceManaged guiceManagedAnnotation =
clazz.getAnnotation(GuiceManaged.class);
final Injector injector = createInjector(guiceManagedAnnotation);
final Object serviceObject = clazz.newInstance();
injector.injectMembers(serviceObject);
final String address = guiceManagedAnnotation.address();
Endpoint.publish(address, serviceObject);
}
private Injector createInjector(final GuiceManaged guiceManagedAnnotation)
throws Exception {
final Class<? extends Module>[] moduleClasses =
guiceManagedAnnotation.module();
final List<Module> moduleInstances = new ArrayList<Module>();
for (final Class<? extends Module> moduleClass : moduleClasses) {
moduleInstances.add(moduleClass.newInstance());
}
return Guice.createInjector(moduleInstances);
}
The GuiceManaged annotation:
#Retention(RUNTIME)
#Target(TYPE)
#Documented
public #interface GuiceManaged {
public Class<? extends Module>[] module();
public String address();
}
And the HelloServiceImpl snippet:
#GuiceManaged(module = HelloModule.class,
address = "http://localhost:8080/helloService")
#WebService
public class HelloServiceImpl implements HelloService {
#Inject // bound in HelloModule
public GreetingsService greetingsService;
#Override
#WebMethod
public String sayHello(final String name) {
return greetingsService.sayHello(name);
}
}

you need to use the AbstractMultiInstanceResolver extension point.
create the annotation GuiceManaged;
#Retention(RUNTIME)
#Target(TYPE)
#Documented
#WebServiceFeatureAnnotation(id=GuiceManagedFeature.ID, bean=GuiceManagedFeature.class)
#InstanceResolverAnnotation(GuiceManagedInstanceResolver.class)
public #interface GuiceManaged {
}
implement the GuiceManagedFeature which is WebServiceFeature :
public class GuiceManagedFeature extends WebServiceFeature {
public static final String ID="FEATURE_GuiceManaged";
#FeatureConstructor
public GuiceManagedFeature()
{
this.enabled=true;
}
public String getID() {
return ID;
}
}
Implement InstanceResolver by Extending AbstractMultiInstanceResolver
public class GuiceManagedInstanceResolver extends AbstractMultiInstanceResolver {
private T instance=null;
public GuiceManagedInstanceResolver(#NotNull Class clazz)
{
super(clazz);
}
public T resolve(#NotNull Packet request) {
if(instance==null)
{
instance=create();
Injector injector= Guice.createInjector(new WebServiceModule());
injector.injectMembers(instance);
}
return instance;
}
}
Now Annotate your Service with #GuiceManaged & use #Inject for method level DI on your business method.

Related

#Inject not working in Singleton but works in API classes

I'm setting up authentication in my Jetty API. And I wanted to use dependency injection to inject a class with database functions into the class that checks the provided token against the database.
I've already used dependency injection in my API classes like this:
#Path("/account")
#Api(value = "/account", description = "Web Service for accounts")
public class AccountService {
#Inject
private IAccountRepo accountRepo;
}
To make this work I created a class which binds the actual class to the interface.
public class RepositoryBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MovieRepo.class).to(IMovieRepo.class);
bind(AccountRepo.class).to(IAccountRepo.class);
}
}
I registered it like this:
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.packages(
MovieService.class.getPackage().getName(),
AccountService.class.getPackage().getName(),
ApiListingResource.class.getPackage().getName()
);
resourceConfig.register(new RepositoryBinder());
resourceConfig.register(new AuthenticationFilter());
resourceConfig.register(ObjectMapperContextResolver.class);
But when I try to use it in my TokenValidator class, the accountRepo is always null.
My TokenValidator looks like this:
#Singleton
public class TokenValidator implements ITokenValidator {
#Inject
private IAccountRepo accountRepo;
private static ITokenValidator instance = null;
private TokenValidator() {
}
public static ITokenValidator getInstance() {
if (instance == null) {
instance = new TokenValidator();
}
return instance;
}
//Some token validation logic here
}
I expected the #Inject to work right away but it doesn't. I've allready tried a bunch of things like registering the TokenValidator the same way the API classes are registered but nothing worked so far.

How to force CDI/Weld to work with the new keyword?

I have a command line Java SE application that I would like to modernize a bit. I want to use interceptors and dependency injection among other CDI features. However the application was not designed with CDI or dependency injection in mind, it extensively uses the new keyword and constructor parameters instead of delegating object creation to the DI container. CDI/Weld does not inject dependencies or run interceptors on objects created with new, and it can not handle constructor parameters at all. A simplified example:
class Main {
#Inject
private SomeModule someModule;
public static void main (String[] args) {
SeContainer container = ... set up CDI container ...
Main main = container.select(Main.class).get();
main.main(args);
}
#TraceLog
public Main () {
...
}
#TraceLog
public main (String[] args) {
Encryptor = new Encryptor(args[1], args[2], args[3]);
encryptor.run();
}
}
class Encryptor {
#Inject
private SomeModule someModule;
private String inputFile;
private String outputFile;
private String key;
#TraceLog
public Encryptor (String inputFile, String outputFile, String key) {
...
}
#TraceLog
public run () {
...
}
}
Main is instantiated by the CDI container, someModule is injected, and #TraceLog interceptor is called for both constructor and method. However Encryptor is created explicitly with the new keyword, someModule is not injected, and #TraceLog is not called.
CDI supports programmatic creation of beans, but only for classes with a parameterless non-private constructor. Examples:
CDI.current().select(DefinitelyNotEncryptor.class).get();
#Inject
private Instance<DefinitelyNotEncryptor> instance;
instance.select(DefinitelyNotEncryptor.class).get();
Spring supports injection into objects created with the new keyword, with the use of AspectJ. No idea about support for interceptors on constructors and methods though.
#Configurable(preConstruction = true)
#Component
class Encryptor {
#Autowired
private SomeModule someModule;
private String inputFile;
private String outputFile;
private String key;
#TraceLog
public Encryptor (String inputFile, String outputFile, String key) {
...
}
#TraceLog
public run () {
...
}
}
Is there any similar solution to CDI/Weld? Or should I resort to using Spring? Does it support constructor and method interceptors?
Let's start with few remarks...
and it can not handle constructor parameters at all
Wrong. It's called constructor injection.The only limitation being that all parameters have to be resolvable CDI beans.
#Inject
public Foo(Bar bar) { // -> CDI will attempt to inject Bar
// constructor logic
}
CDI/Weld does not inject dependencies or run interceptors on objects created with new
Yes, not by default. But it is achievable via BeanManager.createInjectionTarget(...).inject(...)
Not a go-to way to convert an existing application though!
NOTE: the above code will only enable injection. Not interception. For that would perhaps need to use InterceptionFactory.
You shouldn't need either for your problem though.
CDI supports programmatic creation of beans...
What you described with your code (Instance<T>) is not creation but rather a dynamic/programmatic lookup. It adheres to the same resolution rules as #Inject only allowing you to make it dynamic and not set in stone.
If you speak of creation, you may mean producer methods?
Now, to your problem...
If I get it correctly, the only problem is that the constructor of Encryptor has parameters. Well, then you need to make sure those parameters can be injected in some way. Since they are all three of type String, you will need to either wrap them in some bean or use qualifiers so that typesafe resolution does not blow up with ambiguous resolution when you have multiple beans of type String.
Here is how the constructor would look like with qualifier-based solution. #Output, #Input and #Key are all qualifiers:
#Inject
public Encryptor (#Input String inputFile, #Output String outputFile, #Key String key){...}
Here is an example of one of these qualifiers:
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface Key {}
And finally, you need to produce those String beans, that you can do with producer methods, mentioned above. Here is one (exception the logic to grab that value as I cannot know how you do that):
#Produces
#Key
public String produceKeyString() {
// CDI will invoke this method in order to create bean of type String with qual. #Key
String key = new String("safeKey") // replace with your logic to get the value
return key;
}
If you want CDI Injection, you must avoid using the new operator.
This this how I would have find a solution to your design problem
#ApplicationScoped
class Main
{
#Inject
private SomeModule someModule;
#Inject
private Encryptor encryptor;
public static void main (String[] args)
{
SeContainer container = ... set up CDI container ...
Main main = container.select(Main.class).get();
main.run(args);
}
#TraceLog
public Main ()
{
...
}
#TraceLog
public void run(String[] args)
{
encryptor.init(args[0], args[1], args[2]).run();
}
}
#Dependent
class Encryptor
{
#Inject
private SomeModule someModule;
private String inputFile;
private String outputFile;
private String key;
#TraceLog
public Encryptor init(String inputFile, String outputFile, String key)
{
this.inputFile = inputFile;
this.outputFile = outputFile;
this.key = key;
return this;
}
protected void run()
{
// do the real job of the encryptor here
}
}
The main things about this code are :
using scope annotations ApplicationScoped and Dependent
providing init() method on your Encryptor class which will take runtime arguments
returning the instance of Encryptor at the end of init() to be able to call the run() method which is protected to avoid direct call (It could be also private, I think) without calling init() first
It should work with this design.

How to make Jersey work with Dagger dependency injection?

Jersey normally uses HK2 dependency injection, but I would like to use Jersey with Dagger 2. Both Dagger and HK2 implement JSR 330, which I have taken as evidence that this should be possible without too much effort. I found ways to make Jersey work with CDI (e.g. Weld), Spring DI and Guice, but I can't find anything on Dagger.
To provide some context: I'm running a Grizzly–Jersey server in an SE environment, not in an EE container. My Maven project has com.google.dagger:dagger and org.glassfish.jersey.containers:jersey-container-grizzly2-http as dependencies, but not org.glassfish.jersey.inject:jersey-hk2, since I want to replace HK2 with Dagger.
The resource classes look like this:
#Path("/example")
public final class ExampleResource {
private final Dependency dependency;
#Inject
public ExampleResource(final Dependency dependency) {
this.dependency = Objects.requireNonNull(dependency);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Example getExample() {
return this.dependency.giveExample();
}
}
And the Dagger component could e.g. be defined as follows:
#Component
public interface Application {
public ExampleResource exampleEndpoint();
public XyzResource xyzEndpoint();
// etc.
}
So that the main method would look similar to:
public final class Main {
public static void main(final String[] args) {
final Application application = DaggerApplication.create();
final URI baseUri = UriBuilder.fromUri("http://0.0.0.0/").port(80).build();
final ResourceConfig resourceConfig = new ResourceConfig();
// how to initialize `resourceConfig` using `application`?
final HttpServer httpServer = GrizzlyHttpServerFactory
.createHttpServer(baseUri, resourceConfig, false);
try {
httpServer.start();
} catch (final IOException ex) {
...
}
}
}
Running the application immediately results in an exception: IllegalStateException: InjectionManagerFactory not found. It seems that a Dagger implementation of this factory is needed.
My question is: how to integrate Dagger with Jersey?
You shouldn't think of it as "how to integrate dagger with jersey". Figure out how to setup jersey, then once you have that figured out, then you can worry about using dagger.
Here's (very roughly) how I would do it.
Create your own implementation of the ResourceConfig class.
#ApplicationPath("/service")
public class MyResourceConfig extends ResourceConfig {
#Inject
public MyResourceConfig(
#Nonnull final ExampleResource exampleResource) {
this.register(exampleResource);
}
}
Then create a module that sets up everything you need to create an HttpServer
#Module
public class MyServiceModule {
#Provides
#Singleton
#Named("applicationPort")
public Integer applicationPort() {
return 80;
}
#Provides
#Singleton
#Named("applicationBaseUri")
public URI baseUri(
#Named("applicationPort") #Nonnull final Integer applicationPort) {
return UriBuilder.fromUri("http://0.0.0.0/").port(applicationPort).build();
};
#Provides
#Singleton
public HttpServer httpServer(
#Named("applicationBaseUri") #Nonnull final URI applicationBaseUri,
#Nonnull final MyResourceConfig myResourceConfig) {
return GrizzlyHttpServerFactory
.createHttpServer(applicationBaseUri, myResourceConfig, false);
}
}
Then create your component that exposes the HttpServer. I typically like to make components that expose as little as possible. In this case, all you need to expose is the HttpServer.
#Singleton
#Component(modules = { MyServiceModule.class })
protected interface ServiceComponent {
HttpServer httpServer();
#Component.Builder
interface Builder {
// Bind any parameters here...
ServiceComponent build();
}
}
Then just go ahead and build your component, and start your HttpServer
public static void main(String[] args) {
final ServiceComponent component = DaggerServiceComponent.builder().build()
try {
component.httpServer().start();
} catch (Exception ex) {
// handle exception...
}
}
One more thing to note. I personally do not ever use the #Named("") annotation. I prefer to use a Qualifier. So you create a Qualifier annotation with a unique value. Then you can inject things like
#Provides
#Singleton
#MyUniqueQualifier
public String myUniqueQualifierProviderValue() {
return "something";
}
Then when injecting it
#Inject
public SomeClass(#MyUniqueQualifier #Nonnull final String myUniqueQualifiedValue)
If you use the #Named annotation you don't get compile time checks for conflicts or missing values. You would find out at run time that a value was not injected or then name conflicts with something else. It gets messy quick.
You need to implement an InjectionManagerFactory that will return an InjectionManager delegating to Dagger and have it registered as a service by putting an entry in META-INF/services, similar to the hk2 one here:
https://github.com/jersey/jersey/blob/master/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
but referencing your own implementation.

Tomcat8 WebSockets (JSR-356) with Guice 3.0

I am trying to #Inject a Guice service into a #ServerEndpoint. I am using Tomcat 8.0.15 as the JSR-356 implementation. However, the dependency injection isn't working. Is there any additional configuration that needs to be done in order to enable Guice injection? Note that I am using all standard javax annotations only.
I figured this out. The Websocket endpoint needs to have a custom configurator, which creates and returns instances using the Guice injector instance.
Example:
Custom Guice servlet context listener:
public class CustomServletContextListener extends GuiceServletContextListener {
public static Injector injector;
#Override
protected Injector getInjector() {
injector = Guice.createInjector(...);
return injector;
}
}
Websockets custom configurator:
public class CustomConfigurator extends Configurator {
#Override
public <T> T getEndpointInstance(Class<T> clazz)
throws InstantiationException {
return CustomServletContextListener.injector.getInstance(clazz);
}
}
And then in the Websocket endpoint:
#ServerEndpoint(value = "/ws/sample_endpoint", configurator = CustomConfigurator.class)
public class SampleEndpoint {
private final SomeService service;
#Inject
public SampleEndpoint(SomeService service) {
this.service = service;
}
...
}
Building upon Aritra's own answer:
To be honest, I don't know for sure if this works with Guice 3.0, but it does work for 4.0, which is the current stable release.
I think a somewhat cleaner approach is to change your CustomConfigurator into something like this:
public class CustomConfigurator extends Configurator {
#Inject
private static Injector injector;
public <T> T getEndpointInstance(Class<T> endpointClass) {
return injector.getInstance(endpointClass);
}
}
And then from your extended ServletModule class' configureServlets method, call requestStaticInjection(CustomConfigurator.class)
That way you won't expose the injector to everyone. I don't know about you, but it gives me a nice and fuzzy feeling inside to know that no one will be able to mess with my injector :-).

Jersey 2.*. How to replace InjectableProvider and AbstractHttpContextInjectable of Jersey 1.*

I would like to create a class whose objects can be injected using the #Context annotation (or better yet a custom annotation for cases where I need to pass an argument to the annotation) into resource methods. In Jersey 1.* I would have used InjectableProvider (in my case together with AbstractHttpContextInjectable). What I'm trying to achieve is something like #Auth [1] from dropwizard (which uses Jersey 1.7).
The injection capabilities of Jersey were replaced by HK2 as far as I know and I could not find any example of what I'm describing.
Edit: See this question for further problems I have encountered while trying to follow Michal's guide.
You need to implement InjectionResolver<T> interface from HK2. Take a look at existing implementations that are present in Jersey workspace:
ContextInjectionResolver handling #Context
ParamInjectionResolver handling #PathParam, #QueryParam, ... (via it's subclasses)
AutowiredInjectResolver handling #Autowired
Once you have this, you need to extend AbstractBinder from HK2 and bind your InjectionResolver via it's #configure() method:
public class MyResolverBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<MyAnnotation>>() {})
.in(Singleton.class);
}
}
... and register an instance of this binder in your application class (or via feature):
Feature:
public class MyFeature implements Feature {
#Override
public boolean configure(final FeatureContext context) {
context.register(new MyResolverBinder());
return true;
}
}
register MyFeature into Application:
public class JaxRsApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final HashSet<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyFeature.class);
// Register other providers or resources.
return classes;
}
}
register MyResolverBinder or Feature in the ResourceConfig
new ResourceConfig()
// Register either MyFeature
.register(MyFeature.class)
// or MyResolverBinder
.register(new MyResolverBinder())
// Register other providers or resources
.packages("my.package");
Providing an implementation of InjectionResolver only helps with injection, not when resolving values for the parameters of a resource method.
At least with Jersey 2.11, you need to define a ValueFactoryProvider annotated with #Provider.
#Provider
public class MyValueFactoryProvider implements ValueFactoryProvider {
#Inject
private MyFactory factory;
#Override
public Factory<?> getValueFactory(Parameter parameter) {
if (parameter.getAnnotation(MyAnnotationParam.class) != null) {
return factory;
}
return null;
}
#Override
public PriorityType getPriority() {
return Priority.NORMAL;
}
}
If you also want to get the value injected in, e.g., members and constructor parameters, then InjectionResolver works well.

Categories