Access a ResourceContext instance from a static context - java

In Jersey JAX-RS:
Is there a way to access an instance of ResourceContext from a static context? So far I have come-up empty-handed and have tried a number of approaches that fail to do what I expect. Here's an example snippet of what I want to achieve:
import com.sun.jersey.api.core.*;
import javax.annotation.PostConstruct;
import javax.ws.rs.core.Context;
#Singleton
#Provider
public static class MyClass
{
private static MyClass singleton;
#Context
private ResourceContext context;
#PostConstruct
private void constructor ()
{
MyClass.singleton = this;
}
public static <T> T acquireResource(Class<T> clazz)
{
return MyClass.singleton.context.getResource(clazz);
}
}
But unfortunately this doesn't work properly as I suppose providers are lazy loaded. I'm not even sure the "#Singleton" annotation does anything.
I've also tried extending the WebAppResourceConfig which is an instance of Application, but this broke my application and I don't fully understand why.

Related

Is there a proper way to use #PostConstruct in Micronaut?

I'm trying to print a message after the application startup with #PostConstruct, but nothing is printed.
package dev.renansouza.server;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class ServerService {
#PostConstruct
public void print() {
System.out.println("Hello!");
}
}
I have read that #PostConstruct is Lazy. Does this mean that I need to do
something else for this to work?
You can also use #EventListener annotation to acheive what you what, if using #PostConstruct is not that important to you.
For example in your case, you can add following code in any class to listen for application startup event.
#EventListener
void onStartup(ServerStartupEvent event) {
println("Hey, I work from anywhere in project..")
}
Code shared above is in Groovy
Keep in mind, the event listener added in main application class is usually called first from what I have observed.
The problem (aka feature) is, as you already mentioned, the lazy loading.
I see two solutions:
You have to do something to cause that bean to be initialized.
Change the scope of the bean from #Singleton to #Context
Micronaut has a few built-in scopes (see https://docs.micronaut.io/latest/guide/index.html#scopes) and the documentation of #Context states (see https://docs.micronaut.io/latest/api/io/micronaut/context/annotation/Context.html)
Context scope indicates that the classes life cycle is bound to that of the BeanContext and it should be initialized and shutdown during startup and shutdown of the underlying BeanContext.
Micronaut by default treats all Singleton bean definitions as lazy and will only load them on demand. By annotating a bean with #Context you can ensure that the bean is loaded at the same time as the context.
package dev.renansouza.server;
import javax.annotation.PostConstruct;
import io.micronaut.context.annotation.Context;
#Context
public class ServerService {
#PostConstruct
public void print() {
System.out.println("Hello!");
}
}
See the project at https://github.com/jeffbrown/renansouzapostconstruct.
https://github.com/jeffbrown/renansouzapostconstruct/blob/master/src/main/java/renansouzapostconstruct/ServerService.java
package renansouzapostconstruct;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class ServerService {
#PostConstruct
public void print() {
System.out.println("Hello!");
}
}
https://github.com/jeffbrown/renansouzapostconstruct/blob/master/src/main/java/renansouzapostconstruct/DemoController.java
package renansouzapostconstruct;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.HttpStatus;
#Controller("/demo")
public class DemoController {
private ServerService serverService;
public DemoController(ServerService serverService) {
this.serverService = serverService;
}
#Get("/")
public HttpStatus index() {
return HttpStatus.OK;
}
}
When you start the app you won't see the message printed to standard out because the service bean won't have been initialized. Send a request to http://localhost:8080/demo/ and then you will see the message printed to stdout.
I hope that helps.

Mockito with Jersey Test and JAX-RS - UnsatisfiedDependencyException

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.

AbstractContainerRequestValueFactory removed from Jersey 2.26

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

Autowire dependency in builder class with static instantiation method

I'm pondering this builder class that should calculate a hash from the field values. Maybe this in itself is wrong for starters, but at the moment it seems to me that it belongs there because I'm striving to an immutable Article.
I would like to autowire/inject ArticleMD5HashCalculator but when I put #Autowired on the field, IntelliJ complains: field injection is not recommended. Constructor injection is not possible because it's a builder pattern class, which means it has a private constructor without parameters and a static method for instantiation where it would be awkward to pass in hashCalculator.
The builder is injected into a scraper. The scraper will reuse the same builder for many articles. When Spring creates the builder with prototype scope, the builder will carry old values when the next article doesn't overwrite the old values.
New'ing the hashCalculator results is a hard dependency, making it impractical to inject mocks. What is the best way to handle this situation?
Here's the code of how it is now:
import org.observer.media.utils.ArticleMD5HashCalculator;
import org.observer.media.utils.MD5HashCalculator;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ArticleBuilder {
private ArticleMD5HashCalculator hashCalculator;
private String headline;
private String subheading;
private String lead;
// other article fields...
private ArticleBuilder() {
// This seems wrong.
this.hashCalculator = new ArticleMD5HashCalculator(new MD5HashCalculator());
}
public static ArticleBuilder article() {
return new ArticleBuilder();
}
public ArticleBuilder withHeadline(String headline) {
this.headline = headline;
return this;
}
//Other with-methods...
public Article build() {
// calculateHash() is called in the 9th argument.
return new Article(headline, subheading, lead, body, images, quotations, subArticles, url, calculateHash(), author, sources, category, subjects, index, medium, company, datePublished, dateFetched);
}
private String calculateHash() {
return hashCalculator.hash(headline, subheading, lead, body, quotations, datePublished, dateFetched);
}
}
Assumptions:
There is one to one relationship between ArticleBuilder and ArticleMD5HashCalculator. Meaning you don't plan to inject different instances of hashCalculator into ArticleBuilder at different places in the project (essentially having multiple instances of ArticleBuilder)
You can change the ArticleBuilder impl as follows
public class ArticleBuilder {
private ArticleMD5HashCalculator hashCalculator;
public ArticleBuilder(ArticleMD5HashCalculator hashCalculator) {
this.hashCalculator = hashCalculator;
}
}
You can create a spring bean of type ArticleMD5HashCalculator and have this injected into a spring bean of type ArticleBuilder the following way.
#Configuration
public class ArticleConfig {
#Bean
public ArticleMD5HashCalculator articleMD5HashCalculator() {
return new ArticleMD5HashCalculator(new MD5HashCalculator());
}
#Bean
public ArticleBuilder() {
return new ArticleBuilder(articleMD5HashCalculator());
}
}
You can autowire ArticleBuilder elsewhere in your project and use it as a builder.
I am not sure why you made a private constructor and a static method to invoke that. I assume it is because you want a singleton ArticleBuilder. That can be achieved with the above approach. Correct me if I am wrong about this.
Update 1:
Based on the information you provided in the comments, you are injecting ArticleBuilder in a Scraper object and you want to have a way of getting a new instance of ArticleBuilder every time. You can use spring #Lookup annotation for that.
Stub implementation of Scraper class.
public class Scraper {
//assuming this is the method where you want to use ArticleBuilder
public void scrape() {
getArticleBuilder();
}
//You can even pass constructor arguments to this method.
//They will be used to match a constructor on the target bean and that gets invoked
#Lookup
public ArticleBuilder getArticleBuilder() {
//Spring creates a runtime implementation of this method.
return null;
}
}
You can call getArticleBuilder anytime you want a new instance of the bean. If it is declared prototype, you will always get a new instance of the bean.
But the only caveat with this is that Lookup annotation is not going to work with beans created with #Bean annotation. You alternate config may look like this.
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ArticleBuilder {
#Autowired
private ArticleMD5HashCalculator hashCalculator;
public ArticleBuilder(ArticleMD5HashCalculator hashCalculator) {
this.hashCalculator = hashCalculator;
}
}
#Component
public class ArticleMD5HashCalculator {
public ArticleMD5HashCalculator(MD5HashCalculator hashCalculator) {
this.hashCalculator = hashCalculator;
}
}
beans.xml:
<beans>
<bean class="MD5HashCalculator" />
<!-- Fully qualified class name is needed -->
</beans>
Also due to convention used in Spring documentation please use constructor-based injection when possible.
The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null.
Full info (scroll a little): Spring DOCS
I brewed up this alternative approach to pull out the new'ing and to open a window for injecting mocks. The solution implies that the builder has to be instantiated and recreated by a factory.
The factory:
import org.observer.media.hash.ArticleHashCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Component
public class ArticleBuilderFactory {
private ArticleHashCalculator articleHashCalculator;
#Autowired
public ArticleBuilderFactory(ArticleHashCalculator articleHashCalculator) {
this.articleHashCalculator = articleHashCalculator;
}
public ArticleBuilder create() {
return new ArticleBuilder(articleHashCalculator);
}
public class ArticleBuilder {
private ArticleHashCalculator articleHashCalculator;
private String headline;
private String subheading;
//...
private ArticleBuilder(ArticleHashCalculator articleHashCalculator) {
this.articleHashCalculator = articleHashCalculator;
}
public ArticleBuilderFactory.ArticleBuilder withIndex(int index) {
this.index = index;
return this;
}
public ArticleBuilderFactory.ArticleBuilder withHeadline(String headline) {
this.headline = headline;
return this;
}
//...
public Article build() {
return new Article(headline, subheading, lead, body, images, quotations, subArticles, url, calculateHash(), author, sources, category, subjects, index, medium, company, datePublished, dateFetched);
}
private String calculateHash() {
return articleHashCalculator.hash(headline, subheading, lead, body, quotations, datePublished, dateFetched);
}
}
}
Usage of the factory:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.observer.media.hash.ArticleMD5HashCalculator;
import org.observer.media.hash.MD5HashCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Java6Assertions.assertThat;
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
ArticleBuilderFactory.class,
MD5HashCalculator.class,
ArticleMD5HashCalculator.class
})
public class ArticleBuilderFactoryTest {
private static final String HEADLINE = "headline";
private static final String LEAD = "lead";
private static final String BODY = "body";
#Autowired
private ArticleBuilderFactory articleBuilderFactory;
#Autowired
private ArticleMD5HashCalculator hashCalculator;
#Test
public void build() {
ArticleBuilderFactory.ArticleBuilder articleBuilder = articleBuilderFactory.create();
Article article = articleBuilder
.withHeadline(HEADLINE)
.withLead(LEAD)
.withBody(BODY)
.build();
assertThat(article.getHeadline()).isEqualTo(HEADLINE);
assertThat(article.getLead()).isEqualTo(LEAD);
assertThat(article.getBody()).isEqualTo(BODY);
assertThat(article.getHash()).isEqualTo(hashCalculator.hash(HEADLINE, null, LEAD, BODY, null, null, null));
}
}
ArticleMD5HashCalculator has #Component:
#Component
public class ArticleMD5HashCalculator {
}

auto scan for guice

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));
}
}

Categories