I need to create objects with user defined data at runtime.TO do that i have used
google guice assisted inject.But when i run my test it throws null pointer exception.Please let me know where i made the mistake.
IArtifacts Interface
public interface IArtifacts {
MavenMetaDataXMLDTO getArtifactsVersions();
}
ArtifactsService.java
public class ArtifactsService implements IArtifacts {
private ProductProfile productProfile;
#Inject
public ArtifactsService(#Assisted ProductProfile productProfile){
System.out.println(productProfile.getArtifactManagementURL());
this.productProfile=productProfile;
}
#Override
public MavenMetaDataXMLDTO getArtifactsVersions() {
System.out.println(productProfile.getArtifactManagementURL());
return null;
}
}
ArtifactsFactory Interface
public interface ArtifactsFactory {
IArtifacts create(ProductProfile productProfile);
}
Module Class
#Override
protected void configure() {
install(new FactoryModuleBuilder().implement(IArtifacts.class,ArtifactsService.class).build(ArtifactsFactory.class));
}
TestArtifacts.java
public class TestArtifacts {
#Inject // this obj is null
private ArtifactsFactory artifactsFactory;
private IArtifacts s;
public TestArtifacts(){
}
public void getdata(){
//Pass custom data to factory
this.s=artifactsFactory.create(Products.QA.get());
System.out.println(s.getArtifactsVersions());
}
}
REST ENDPOINT
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String getartifacts(){
new TestArtifacts().getdata();
}
you created an Instance of the class TestArtifacts on your own in your Rest Endpoint class but all of your classes need to be created by the Guice Framework and not by you.
So how should the Guice Framework inject something into your class when you create them with new? You also need to inject the class TestArtifacts into your Rest Endpoint and your Rest Endpoint has to be created by Guice too.
Update:
Maybe this link will help you
https://sites.google.com/a/athaydes.com/renato-athaydes/posts/jersey_guice_rest_api
I was able to fix it adding following code snippet to below TestArtifacts.java class
TestArtifacts.java
private Injector injector=Guice.createInjector(new MYModule());//where implemented configuration
#Inject
private ArtifactsFactory artifactsFactory=injector.getInstance(ArtifactsFactory.class);
Related
For simplifying our web services I'd like to introduce a custom MyObj class using the Jersey framework in version 2.34 and want to inject the created instances via the #Context annotation.
I have two questions:
Assuming a web service method #GET test(#Context MyObj obj), how can I control when instances of MyObj are created in respect to the execution of existing servlet request filters?
To create instances of MyObj, I already have a working example based on HK2's Factory's (see below). Since I observed that my factory class gets instantiated twice, and Jersey 2.26+ recomments to use the newer approach based on Supplier's, I tried to convert my example. Unfortunately, configure() won't be called in the provided Binder implements Supplier class, and thus, no objects get created. How can I get this working? (Btw., In both cases, Binder and BinderHK are registered via jersey.config.server.provider.classnames in my web.xml.)
Thank you for any help.
Working HK2 Factory example:
public class MyObjHK {}
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
public class BinderHK
extends AbstractBinder {
#Override protected void configure() {
bindFactory(MyObjFactoryHK.class).to(MyObjHK.class).in(RequestScoped.class);
}
}
import org.glassfish.hk2.api.Factory;
public class MyObjFactoryHK
implements Factory<MyObjHK> {
#Override public MyObjHK provide() {return new MyObjHK();} // ok
#Override public void dispose(MyObjHK instance) {};
}
public class API_HK2 {
#GET
public static Response myobjhk(#Context MyObjHK obj) {
System.out.println("called hk, obj="+obj); // ok
return Response.ok().build();
}
}
Not working Supplier example:
public class MyObj {}
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
public class Binder
extends AbstractBinder {
#Override protected void configure() { // not called ???
bindFactory(MyObjFactory.class).to(MyObj.class).in(RequestScoped.class);
}
}
import java.util.function.Supplier;
public class MyObjFactory
implements Supplier<MyObj> {
#Override public MyObj get() {return new MyObj();}
}
public class API {
#GET
public static Response myobj(#Context MyObj obj) {
System.out.println("called, obj="+obj); // null ???
return Response.ok().build();
}
}
The binder isn't something that can be registered with the jersey.config..classnames init-param. You need to either register it with a ResourceConfig or with Feature (and register the Feature with the init-param)
#Provider
public class MyFeature implements Feature {
#Override
pubic boolean configure(FeatureContext ctx) {
ctx.register(new MyBinder());
return true;
}
}
I have a certain type of class that can provide data and a registry where the different data providers are registered. I am looking for an elegant way to implement this in spring boot.
My current implementation looks like this (code is shortened for brevity):
public interface DataProvider{
Data getSomeData();
}
public class Registry{
public register(DataProvider provider){
//add to internal list
};
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
public class Provider1 implements DataProvider { ... }
public class Provider2 implements DataProvider { ... }
Now for the wiring part, and this is the part I want to change to something more elegant:
#Configuration
public class MyAppConfiguration{
#Bean
public Registry providerRegistry(){
Registry reg = new Registry();
reg.register(new Provider1());
reg.register(new Provider2());
return reg;
}
}
Then I can inject the registry into other classes that need to operate on the services.
I know that DI is for providing different implementation for a single type but one at a time. So DI most probably is not the right tool, my question is more about spring if there's a good way I don't know to achieve this.
As example Annotate them with a Qualifier and then resolve all Beans with that qualifier in the registry.
The way I would not want to take is using a custom Annotation and then resolving all the classes via reflection, instantiate them and put them in the registry. But at the moment it's the only way I can see so I don't have to modify the config and handwire the services.
If you want all of them to be autowired, you can just autowire a list of your interface implementations.
#Bean
public class Provider1 implements DataProvider { ... }
#Bean
public class Provider2 implements DataProvider { ... }
#Bean
public class Registry{
#Autowired
private List<DataProvider> providers;
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
In case you want to keep using a configuration class you could do something like:
#Bean
public class Provider1 implements DataProvider { ... }
#Bean
public class Provider2 implements DataProvider { ... }
public class Registry{
private List<DataProvider> providers;
public Registry(final List<DataProvider> providers) {
this.providers = providers;
}
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
#Configuration
public class MyAppConfiguration{
#Bean
#Autowired
public Registry providerRegistry(final List<DataProvider> providers){
return new Registry(providers);
}
}
Is there any way to inject dependencies into manually created objects?
public class MyCommand {
#Inject Repository repository;
}
public Repository {
#Inject EntityManager em;
}
MyCommand command = new MyCommand();
Repository is properly registered the jersey ResourceConfig and can be injected in objects that are created through the CDI container for example a resource class.
But since I create the Command myself the #Inject annotation gets ignored.
Is there a way to get a registered class beside #Inject and #Context?
Something like Application.get(Repository.class)
public class MyCommand {
Repository repository;
public MyCommand() {
repository = Application.get(Repository.class);
}
}
----- EDIT -----
Thanks to your help and some rethinking I found a solution for my problem.
The first thing is that it's possible to inject the ServiceLocator without any preperation into you objects.
The second thing is that I moved from normal commands with a execute method to a a command bus system.
The reason for that is I have no controle over the creation of commands so there clean way to get dependencies injected.
The new approach looks like this:
class CommandBus {
private final ServiceLocator serviceLocator;
#Inject
public CommandBus(ServiceLocator serviceLocator) {
this.serviceLocator = serviceLocator;
}
public void dispatch(Command command) {
Class handlerClass = findHandlerClassForCommand(command);
CommandHandler handler = (CommandHandler) serviceLocator.getService(handlerClass);
handler.handle(command);
}
}
interface CommandHandler {
void handle(Command command);
}
interface Command {
}
class ConcreteCommand implements Command {
// I'm just a dto with getters and setters
}
class ConcreteHandler implements CommandHandler {
private final SomeDependency dependency;
#Inject
public ConcreteHandler(SomeDependency dependency) {
this.dependency = dependency;
}
#Override
public void handle(ConcreteCommand command) {
// do some things
}
}
And in my resources I have something like this:
#Path("/some-resource")
class Resource {
#Context
private CommandBus bus;
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void runCommand(ConcreteCommand command) {
bus.dispatch(command);
}
}
As pointed out by jwells - HK2 is an injection framework :)
I spent some time looking into it - I have to say, I find it much more complicated than say guice or spring. Maybe this is due to the fact that I use Dropwizard and it makes it not as easy to access the Service locators.
However, here is how you can do that.
First, you will have to get a reference to your ServiceLocator. It must be the same ServiceLocator that jersey is using as well. You can access it for example like:
How to get HK2 ServiceLocator in Jersey 2.12?
In my example code I will use an event listener, which is due to my Dropwizard Setup.
You now have 2 choices: Register your command with your Service Locator and have the injection framework handle creation, or pass the ServiceLocator to your command in order to use it.
I wrote up a quick example using Dropwizard and jersey:
public class ViewApplication extends io.dropwizard.Application<Configuration> {
#Override
public void run(Configuration configuration, Environment environment) throws Exception {
environment.jersey().register(new ApplicationEventListener() {
#Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) {
ServiceLocator serviceLocator = ((ServletContainer) environment.getJerseyServletContainer())
.getApplicationHandler().getServiceLocator();
ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
#Override
protected void configure() {
bind(new Repository("test")).to(Repository.class);
bind(MyCommandInjected.class).to(MyCommandInjected.class);
}
});
MyCommandInjected service = serviceLocator.getService(MyCommandInjected.class);
MyCommandManual tmp = new MyCommandManual(serviceLocator);
}
}
#Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
});
}
#Override
public void initialize(Bootstrap<Configuration> bootstrap) {
super.initialize(bootstrap);
}
public static void main(String[] args) throws Exception {
new ViewApplication().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test.yaml");
}
#Path("test")
#Produces(MediaType.APPLICATION_JSON)
public static class HelloResource {
#GET
#Path("asd")
public String test(String x) {
return "Hello";
}
}
public static class Repository {
#Inject
public Repository(String something) {
}
}
public static class MyCommandInjected {
#Inject
public MyCommandInjected(final Repository repo) {
System.out.println("Repo injected " + repo);
}
}
public static class MyCommandManual {
public MyCommandManual(final ServiceLocator sl) {
Repository service = sl.getService(Repository.class);
System.out.println("Repo found: " + service);
}
}
}
In the Run method, i get access to my ServiceLocator. I bind my classes in there (so there is an example of how to do that). You can alternatively also register Binders with jersey directly - they will use the correct ServiceLocator.
The 2 classes MyCommandInjected and MyCommandManual are examples of how you can create this command.
The relevant line for you is probably:
Repository service = sl.getService(Repository.class);
This asks the service locator for a new instance of the Repository.
Now, this is just a quick example. I am much more fond of the guice bridge than using HK2 directly :) I find it much easier to use and much clearer. Using the guice-jersey-bridge you can do everything through guice and it will automatically do the right thing.
Hope that brings some inside,
Artur
You can use the inject method of ServiceLocator in order to inject already created objects. ServiceLocator is the basic registry of HK2 and should be available in your resource.
I have a interface here
interface Idemo{
public int getDemo(int i);
}
And it's one implementation
class DemoImpl implements Idemo{
#Override
public int getDemo(int i){
return i+10;
}
}
And there is a class which has a dependency on Idemo
class Sample{
#Inject
Idemo demo;
public int getSample(int i){
return demo.getDemo(i);
}
}
Now say I want to test Sample class
public class SampleTest extends JerseyTest {
#Inject
Sample s;
#Override
protected Application configure() {
AbstractBinder binder = new AbstractBinder() {
#Override
protected void configure() {
bind(Demo.class).to(Idemo.class);
bind(Sample.class).to(Sample.class); //**doesn't work**
}
};
ResourceConfig config = new ResourceConfig(Sample.class);
config.register(binder);
return config;
}
#Test
public void test_getSample() {
assertEquals(15, s.getSample(5)); //null pointer exception
}
}
Here the Sample instance is not getting created and s remains null.I suppose this is because by the time the execution reaches line where binding is specified this test class has already been created.But I am not sure.With Spring Autowired instead of jersey CDI the same works
Had Sample been a resource/controller class the test framework would create an instance of it with no need to inject it but is it possible to test any other non-web class using Jersey DI ?
The reason it works with Spring is that the test class is managed by the Spring container by using #RunWith(SpringJUnit4ClassRunner.class). The runner will inject all managed objects into the test object. JerseyTest is not managed this way.
If you want, you can create your own runner, but you need to understand a bit how HK2 (Jersey's DI framework) works. Take a look at the documentation. Everything revolves around the ServiceLocator. In a standalone, you might see something like this to bootstrap the DI container
ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
ServiceLocator locator = factory.create(null);
ServiceLocatorUtilities.bind(locator, new MyBinder());
Then to get the service, do
Service service = locator.getService(Service.class);
In the case of the test class, we don't need to gain any access to the service object, we can simply inject the test object, using the ServiceLocator:
locator.inject(test);
Above, test is the test class instance that gets passed to us in our custom runner. Here is the example implementation of a custom runner
import java.lang.annotation.*;
import org.glassfish.hk2.api.*;
import org.glassfish.hk2.utilities.*;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.*;
public class Hk2ClassRunner extends BlockJUnit4ClassRunner {
private final ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
private Class<? extends Binder>[] binderClasses;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public static #interface Binders {
public Class<? extends Binder>[] value();
}
public Hk2ClassRunner(Class<?> cls) throws InitializationError {
super(cls);
Binders bindersAnno = cls.getClass().getAnnotation(Binders.class);
if (bindersAnno == null) {
binderClasses = new Class[0];
}
}
#Override
public Statement methodInvoker(FrameworkMethod method, final Object test) {
final Statement statement = super.methodInvoker(method, test);
return new Statement() {
#Override
public void evaluate() throws Throwable {
ServiceLocator locator = factory.create(null);
for (Class<? extends Binder> c : binderClasses) {
try {
ServiceLocatorUtilities.bind(locator, c.newInstance());
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
locator.inject(test);
statement.evaluate();
locator.shutdown();
}
};
}
}
In the runner, the methodInvoker is called for every test method, so we are creating a fresh new set of objects for each test method called.
Here is a complete test case
#Binders({ServiceBinder.class})
#RunWith(Hk2ClassRunner.class)
public class InjectTest {
public static class Service {
#Inject
private Demo demo;
public void doSomething() {
System.out.println("Inside Service.doSomething()");
demo.doSomething();
}
}
public static class Demo {
public void doSomething() {
System.out.println("Inside Demo.doSomething()");
}
}
public static class ServiceBinder extends AbstractBinder {
#Override
protected void configure() {
bind(Demo.class).to(Demo.class);
bind(Service.class).to(Service.class);
}
}
#Inject
private Service service;
#Test
public void testInjections() {
Assert.assertNotNull(service);
service.doSomething();
}
}
I was facing the same situation but in the context of running some integrations test that needs to have some of the singletons that my application have already defined.
The trick that I found is the following. You just need to create a normal test class or a standalone that use the DropwizardAppRule
In my case, I use JUnit as I was writing some integration test.
public class MyIntegrationTest{
//CONFIG_PATH is just a string that reference to your yaml.file
#ClassRule
public static final DropwizardAppRule<XXXConfiguration> APP_RULE =
new DropwizardAppRule<>(XXXApplication.class, CONFIG_PATH);
}
The #ClassRule will start your application like is said here . That
means you will have access to everything and every object your application needs to start. In my case, I need to get access to a singleton for my service I do that using the #Inject annotation and the #Named
public class MyIntegrationTest {
#ClassRule
public static final DropwizardAppRule<XXXConfiguration> APP_RULE =
new DropwizardAppRule<>(XXXAplication.class, CONFIG_PATH);
#Inject
#Named("myService")
private ServiceImpl myService;
}
Running this will set to null the service as #Inject is not working because we don't have at this point anything that put the beans into the references. There is where this method comes handy.
#Before
public void setup() {
ServiceLocator serviceLocator =((ServletContainer)APP_RULE.getEnvironment().getJerseyServletContainer()).getApplicationHandler().getServiceLocator();
//This line will take the beans from the locator and inject them in their
//reference, so each #Inject reference will be populated.
serviceLocator.inject(this);
}
That will avoid creating other binders and configurations outside of the existing on your application.
Reference to the ServiceLocator that DropwizardAppRule creates can be found here
I'm using the HK2 container in my Jersey application . I need to use my custom factory method to get the injected instance from the HK2 container.
For example ,
// Here I declare the IOC binding.
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(Logger.class).to(ILogger.class).in(Singleton.class);;
bind(MySqlRepository.class).to(IRepository.class).in(Singleton.class);
}
}
public class MyApplication extends ResourceConfig {
public static ApplicationBinder binder ;
public MyApplication () {
binder = new ApplicationBinder();
register(binder);
packages(true, "com.myapplication.server");
}
}
Here is my code :
public class BusinessLogic
{
//#Inject
//ILogger logger ;
//Instead
ILogger logger = DependencyResolver .resolve(ILogger.class) // resolve will get ILogger from HK2 container
}
The reason I need to do this way is for sometimes , I allocate classes manually which has dependencies , so in this way each use of #Inject return null.
For example, if I use new BusinessLogic() , then the logger with #Inject is null. I have to bind businesslogic also and use IOC in order to get the ILogge.
I need something like this:
public class DependencyResolver {
public static <T> T resolve(Class<T> beanClass){
return instance;
}
}
I need to use the DependencyResolver in order to get the instances I registered in MyApplication.
Any suggestions.
Thanks in advance...
I'm not 100% sure what exactly you want to do, but ...
I think you misunderstood AbstractBinder.bind(...) or bindings itself. Also, afaig you can't inject something into an instance which is not kinda managed component (like your BusinessLogic).
See jersey.java.net - ioc for examples regarding your BusinessLogic. You may have a look at ComponentProvider and/or InjectableProvider
For your ILogger I would suggest to create and bind a Factory like this:
public class LoggerFactory implements Factory<ILogger> {
// inject stuff here if you need (just an useless example)
#Inject
public LoggerFactory(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
#Override
public ILogger provide() {
// here you resolve you ilogger
return MyLocator.resolve(ILogger.class);
}
#Override
public void dispose(ILogger instance) {
// ignore
}
}
Bind Factory
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(LoggerFactory.class).to(ILogger.class).in(PerLookup.class /* or other scopeAnnotation if needed */);
// what's you Logger.class ?
// bind(Logger.class).to(ILogger.class).in(Singleton.class);
// bind(MySqlRepository.class).to(IRepository.class).in(Singleton.class);
}
}
Hope this was helpful somehow. Maybe someone is willing to write something about Providers for your case.