I upgrade Jersey in my project to 2.26 version.
My code is:
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
public class ClassA extends AbstractContainerRequestValueFactory<ClassB> {
#Override
public ClassB provide() {
.....
}
}
AbstractContainerRequestValueFactory class was removed, and I didn't found how to fix this.
From https://github.com/jersey/jersey/commit/1f4614787c4cfddb5d9177c6c2a663b96ab673cc#diff-bcd9d3f0cfac8ea5e8e9a6b00119237b
commit we can see we should use below code instead.
private static final class BeanParamValueProvider implements Function<ContainerRequest, Object> {
Alternatively, we can use custom HK2 bindings, that are configured as part of Jersey application. Add jersey-hk2 dependency dependency in the classpath org.glassfish.jersey.inject:jersey-hk2
Define the Factory class to generate the instance based on the resource scopes
import org.glassfish.hk2.api.Factory;
import javax.ws.rs.ext.Provider;
#Provider
public class ClassA implements Factory<ClassB> {
#Override
public ClassB provide() {
// construct ClassB instance based on your requirement
//here I am simply returning the object
return new ClassB();
}
#Override
public void dispose(ClassB instance) {/**Noop**/}
}
Registering the custom factory class
For instance, I have to inject ClassB instance for every request then I can register the above factory with the scope of RequestScoped, in such case, for every request ClassA#provide will be called to create the value of ClassB instance that can be retrieved as #Context ClassB classB
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ext.Provider;
#Provider
class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(ClassA.class)
.to(ClassB.class)
.in(RequestScoped.class);
}
});
}
}
The following scopes are currently supported by Jersey
Related
I have a class that uses a custom json serializer via #JsonAdapter annotation:
import com.google.gson.annotations.JsonAdapter;
#JsonAdapter(IFooAdapter.class)
public interface IFoo {
//...
}
The IFooAdapter class has a dependency on IMyFactory that should be injected.
Injection is configured via Guice.CreateInjector() and bind(IMyFactory.class).to(MyFactoryImpl.class);.
But how can I get guice to inject this into my IFooAdapter class (shown below), which is only used in the #JsonAdapter annotation (shown above)?
import com.google.gson.JsonElement;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.inject.Inject;
public class IFooAdapter implements TypeAdapter<IFoo> {
#Inject IMyFactory myFactory; // <-- THIS INJECTION DOES NOT WORK
#Override public IFoo read(JsonReader in) {
return myFactory.create(/*...*/);
}
#Override public void write(JsonWriter out, IFoo value) {
//...
}
}
After injection via guice.InjectMembers(myMainClass), when I try to parse json via GsonBuilder().create().fromJson(), and debug IFooAdapter.read(), myFactory is Null.
(Which is really not that surprising, after all the IFooAdapter is not a member of myMainClass)
But how do I inject this properly?
You could try registering InstanceCreator for your adapter via something like
gsonBuilder.registerTypeAdapter(IFooAdapter.class, type -> injector.getInstance(type))
You would need to create Gson instance in a place, where you have access to injector (I would do it as #Provides method providing Gson instance with Injector parameter, then inject Gson wherever needed).
I'm testing a Micronaut class that has a bean injected into it. In my test I provide a #MockBean class to override it. However, it seems Micronaut still injects the real dependency.
#MicronautTest
public class ClassUnderTestTest {
#Inject ClassUnderTest classUnderTest;
#Test
public void test() {
}
#MockBean
Dependency dependency() {
return mock(Dependency.class);
}
}
I uploaded a minimum repro to Github: https://github.com/crummy/micronaut-test-dependencies . The real dependency throws an exception, and the test does too. I would not have expected this to happen because of my #MockBean.
If I change the annotation to be #MockBean(Dependency.class) then I get this error: Message: No bean of type [di.failure.example.Dependency] exists. This seems even more confusing to me - now it doesn't resolve my real or my mock dependency?
Injecting mock bean with #MockBean annotation works if your dependency in ClassUnderTest is represented by interface. Let's say Dependency is a simple interface like:
package di.failure.example;
public interface Dependency {
void run();
}
Your application may provide an implementation for this interface called DependencyImpl:
package di.failure.example;
import javax.inject.Singleton;
#Singleton
public class DependencyImpl implements Dependency {
#Override
public void run() {
throw new RuntimeException("I don't want this to load!");
}
}
Now, for test purpose you can define a mock that replaces DependencyImpl:
package di.failure.example;
import io.micronaut.test.annotation.MicronautTest;
import io.micronaut.test.annotation.MockBean;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.mockito.Mockito.mock;
#MicronautTest
public class ClassUnderTestTest {
#Inject
ClassUnderTest classUnderTest;
#Test
public void test() {
classUnderTest.run();
}
#MockBean(DependencyImpl.class)
public Dependency dependency() {
return mock(Dependency.class);
}
}
This test executes and the mock returned by dependency() method is used in place of DependencyImpl.
Using #Replaces annotation
As Sergio mentioned in the comments section you can replace class based bean dependency using #Replaces annotation. Consider following example:
package di.failure.example;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import javax.inject.Singleton;
#MicronautTest
public class ClassUnderTestTest {
#Inject
ClassUnderTest classUnderTest;
#Test
public void test() {
classUnderTest.run();
}
#Replaces(Dependency.class)
#Singleton
public static class MockDependency extends Dependency {
public MockDependency() {
System.out.println("MockDependency.<init>");
}
#Override
void run() {
System.out.println("Does not throw any exception...");
}
}
}
In this example we have defined a class MockDependency and we instruct Micronaut's DI mechanism to replace Dependency bean with MockDependency. However, there is one important thing we need to remember about - because our MockDependency extends Dependency class, parent construct gets invoked. The example you have shown in the question won't work in this case, because Dependency.<init> throws RuntimeException and the test fails. In this modified example I have used class like this one:
package di.failure.example;
import javax.inject.Singleton;
#Singleton
public class Dependency {
public Dependency() {
System.out.println("Dependency.<init>");
}
void run() {
throw new RuntimeException("I don't want this to load!");
}
}
When I run the test it passes and I see following console output:
Dependency.<init>
MockDependency.<init>
Does not throw any exception...
The main difference comparing to #MockBean is that in case of #Replaces you are using a concrete class object. As a workaround (if we really need a Mockito mock object) is to create a mock internally and delegate calls to this object, something like this:
#Replaces(Dependency.class)
#Singleton
public class MockDependency extends Dependency {
private final Dependency delegate;
public MockDependency() {
this.delegate = mock(Dependency.class);
}
#Override
void run() {
delegate.run();
}
}
I had the case - controller MyController with service MyService.
#MockBean(MyServiceImpl.class) did't mock injected service.
when(myService.doSomething()).thenReturn... immediately called real method.
I fixed mocking issue with giving MyService-bean a name and passing this name to #MockBean(name = )
controller:
#Controller
public class MyController {
private MyService myService;
...
}
factory:
#Factory
public class MyFactory {
#Named("myService") // Named just because #MockBean didn't work without it
#Context
public MyService myService() {
return new MyServiceImpl();
}
}
test:
#MicronautTest
class MyControllerTest {
#Inject
MyService myService;
#Inject
#Client("/")
#HttpClient client;
#MockBean(named = "myService")
MyService mockMyService() {
return mock(MyService.class);
}
#Test
void test() {
when(myService.doSomething()).thenReturn(genDto());
...
}
}
Details:
micronaut-test-junit5 3.1.1
junit-jupiter-api 5.6.2
I'm trying to implement the simplest possible Java program where a #Singleton object is injected via #Inject. However, after #Inject, the object is always null.
I realized that I need to use Guice to bind a certain behavior. I'm doing so through MyGuiceModule, which extends AbstractModule. However MyGuiceModule never got called so I had to add this line:
Injector injector = Guice.createInjector(new MyGuiceModule());
But it does not work. Here are my files:
LonelyObject
import javax.inject.Inject;
import javax.inject.Singleton;
#Singleton
public class LonelyObject {
public LonelyObject() {
System.out.println("LonelyObject Constructor");
}
public void alive() {
System.out.println("I AM ALIVE");
}
}
TheTest
public class TheTest {
// inject LonelyObject here
#Inject
LonelyObject L;
public TheTest() {
}
// use LonelyObject
public void doit() {
L.alive();
}
}
MyGuiceModule
import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
import javax.inject.Inject;
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
System.out.println("MyGuiceModule extends AbstractModule");
// make sure LonelyObject is always instantiated as a singleton
bind(LonelyObject.class).asEagerSingleton();
}
}
main function
public static void main(String[] args) {
System.out.println("main");
// this is only here so MyGuiceModule gets called, otherwise
// it will be ignored. this seems to be the only way I can see
// to configure Guice. note that the returned Injector is not used.
Injector injector = Guice.createInjector(new MyGuiceModule());
TheTest t = new TheTest();
// crashes here with Exception in thread "main" java.lang.NullPointerException
t.doit();
}
You're bypassing Guice entirely.
Actually, the culprit is this line:
TheTest t = new TheTest();
You shouldn't create your instance yourself. Instead, ask Guice to create it for you:
TheTest t = injector.getInstance(TheTest.class);
An alternative would be to request Guice to inject the fields directly in your instance for you (but this recommended only when integrating legacy libraries):
TheTest t = new TheTest();
injector.injectMembers(t);
Trying to test a fairly simple JAX-RS endpoint
#ApplicationScoped
#Path("mypath")
public class MyRestService {
#Inject
private Logger logger;
#Inject
private EjbService ejbService;
#GET
public String myMethod() {
logger.info("...");
return ejbService.myMethod();
}
}
with Mockito and Jersey Test
#RunWith(MockitoJUnitRunner.class)
public class MyRestServiceTest extends JerseyTest {
#Mock
private EjbService ejbService;
#Mock
private Logger logger;
#InjectMocks
private MyRestService myRestService;
...
#Override
protected Application configure() {
MockitoAnnotations.initMocks(this);
return new ResourceConfig().register(myRestService);
}
}
The Grizzly container is returning a org.glassfish.hk2.api.UnsatisfiedDependencyException for Logger and EjbService even thought the dependencies are injected correctly by Mockito.
Seems Grizzly is trying, correctly, to ovverride the Mockito mocks.
If I register an AbstractBinder in the configure method, everything works fine.
.register(new AbstractBinder() {
#Override
protected void configure() {
bind(ejbService).to(EjbService.class);
bind(logger).to(Logger.class);
}
});
But I don't feel it's the best way to accomplish injection. Mockito style is better imho.
What do I need to do to solve this issue?
I was able to create the following base class in order to achieve integration between JerseyTest and Mockito such as the OP aimed for:
package org.itest;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.JerseyTestNg;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.util.ReflectionUtils;
import javax.ws.rs.core.Application;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* #author Nom1fan
*/
public abstract class JerseyTestBase extends JerseyTestNg.ContainerPerClassTest {
#Override
protected Application configure() {
MockitoAnnotations.openMocks(this);
ResourceConfig application = new ResourceConfig();
Object resourceUnderTest = getResourceUnderTest();
application.register(resourceUnderTest);
Map<String, Object> properties = Maps.newHashMap();
properties.put(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
properties.put("contextConfigLocation", "classpath:applicationContext.xml");
// Retrieve the fields annotated on subclass as #Mock via reflection and keep each instance
// and its type on an entry in the map, later used to bind to Jersey infra.
HashMap<Object, Class<?>> mocksToBindMap = Maps.newHashMap();
List<Field> fieldsWithMockAnnotation = FieldUtils.getFieldsListWithAnnotation(getClass(), Mock.class);
for (Field declaredField : fieldsWithMockAnnotation) {
declaredField.setAccessible(true);
Object fieldObj = ReflectionUtils.getField(declaredField, this);
mocksToBindMap.put(fieldObj, declaredField.getType());
}
application.setProperties(properties);
application.register(new AbstractBinder() {
#Override
protected void configure() {
for (Map.Entry<Object, Class<?>> mockToBind : mocksToBindMap.entrySet()) {
bind(mockToBind.getKey()).to(mockToBind.getValue());
}
}
});
return application;
}
protected abstract Object getResourceUnderTest();
}
The hook getResourceUnderTest must be implemented by the extending test class, providing the instance of the resource it wishes to test.
Test class example:
import org.itest.JerseyTestBase;
import org.mockito.InjectMocks;
import org.mockito.Mock;
public class MyJerseyTest extends JerseyTestBase {
#Mock
private MockA mockA;
#Mock
private MockB mockB;
#InjectMocks
private MyResource myResource;
#Override
protected Object getResourceUnderTest() {
return myResource;
}
#Test
public void myTest() {
when(mockA.foo()).thenReturn("Don't you dare go hollow");
when(mockB.bar()).thenReturn("Praise the Sun \\[T]/");
// Test stuff
target("url...").request()...
}
}
MyResource class looks something like this:
#Path("url...")
#Controller
public class MyResource {
private final MockA mockA;
private final MockB mockB;
#Autowired // Mocks should get injected here
public MyResource(MockA mockA, MockB mockB) {
this.mockA = mockA;
this.mockB = mockB;
}
#GET
public Response someAPI() {
mockA.foo();
mockB.bar();
}
}
NOTE: I used Spring's and Apache's reflection utils to make things easier but it's not mandatory. Simple reflection code which can be written by hand.
The MockitoJUnitRunner is for unit tests and JerseyTest is for integration tests.
When using Mockito, your tests will call directly the declared myRestService and Mockito dependency injection will take place.
When using JerseyTest, a new web container is created and your tests talk to MyRestService via an HTTP call. Inside this container, the real dependency injection is happening, the classes are not even seeing you declared mocks.
You can use JerseyTest and Mockito together, exactly as you did. It just requires some extra configurations (as you already found) and the #RunWith annotation is not necessary.
I have never used guice before, and I wanted to try it out on an example project with jersey based JAX-RS API backed by a service-bean. I followed this guide: http://randomizedsort.blogspot.de/2011/05/using-guice-ified-jersey-in-embedded.html and was able to bring it to work. My setup is very simple, a JAX-RS resource is invoked via Guice and has a field that is annotated #Inject and injected by Guice:
#Path("configuration")
#Produces(MediaType.APPLICATION_JSON)
#Singleton
public class ConfigurationResource {
#Inject
private ConfigurationService configurationService;
So far so good, everything works like it should, besides following: I am using GuiceServletContextListener for setting things up and have to name each component explicitly:
#WebListener
public class GuiceInitializer extends GuiceServletContextListener{
#Override
protected Injector getInjector() {
return Guice.createInjector(new JerseyServletModule() {
#Override
protected void configureServlets() {
//resources
bind(ConfigurationResource.class);
//services
bind(ConfigurationService.class).to(ConfigurationServiceImpl.class);
// Route all requests through GuiceContainer
serve("/management/*").with(GuiceContainer.class);
}
});
}
}
I find it pretty inconvenient to explicitly name all dependencies. I have worked with standalone jersey before and it's perfectly capable of auto-scanning for resources in defined packages. Also Spring and CDI are capable of mapping implementation to interfaces without need to explicitly name them.
Now the question part:
is there any autoscan extension/setting for guice? I found some on the internet, but it's hard to tell which of them are still useable and uptodate.
is there any other possibility to make configuration of implementations and resources more convenient?
thanks in advance.
Leon
I do not think Guice has built in support for someting like the component-scan of Spring framework. However, it is not difficult to simulate this feature in Guice.
You simply need to write a helper module like the following
import com.google.inject.AbstractModule;
import org.reflections.Reflections;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* To use this helper module, call install(new ComponentScanModule("com.foo", Named.class); in the configure method of
* another module class.
*/
public final class ComponentScanModule extends AbstractModule {
private final String packageName;
private final Set<Class<? extends Annotation>> bindingAnnotations;
#SafeVarargs
public ComponentScanModule(String packageName, final Class<? extends Annotation>... bindingAnnotations) {
this.packageName = packageName;
this.bindingAnnotations = new HashSet<>(Arrays.asList(bindingAnnotations));
}
#Override
public void configure() {
Reflections packageReflections = new Reflections(packageName);
bindingAnnotations.stream()
.map(packageReflections::getTypesAnnotatedWith)
.flatMap(Set::stream)
.forEach(this::bind);
}
}
To component scan a package like com.foo and sub packages for classes carrying #Singleton, use it in this way:
public class AppModule extends AbstractModule {
public void configure() {
install(new ComponentScanModule("com.foo", Singleton.class));
}
}