Using a custom hk2 InjectionResolver to inject application configuration - java

Kind of a follow up to my previous question. I'm trying to inject application configuration data using JSR-330 standard annotations and the HK2 framework bundled with jersey.
Ideally I'd like to create a custom InjectionResolver for the Named annotation, which will lookup the desired values in a Map or Properties object that I will populate from data read elsewhere. In my first attempt I've created an Application instance like
public class MyApplication extends ResourceConfig {
...
packages(MY_PACKAGES);
property(MY_CONFIG_PROPERTY, someValue);
register(new AbstractBinder() {
#Override
protected void configure() {
bind(ConfigurationInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Named>>(){})
.in(Singleton.class)
}
});
}
and then my InjectionResolver looks like
public class ConfigurationInjectionResolver implements InjectionResolver<Named> {
#Context Application application;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
// lookup data in application.getProperties();
}
}
My problem is that application.getProperties() is empty. Any idea what's wrong? Also, could I bind an instance of my Injector instead of binding the class? That way I could construct the instance passing my Map data as a parameter.

"My problem is that application.getProperties() is empty. Any idea what's wrong?
No. This actually works perfectly fine for me.
public class ConfigurationInjectionResolver implements InjectionResolver<Named> {
#Context
Application application;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> root) {
Named annotation = injectee.getParent().getAnnotation(Named.class);
Map<String, Object> props = application.getProperties();
String name = annotation.value();
System.out.println(props.get(name));
return props.get(name);
}
#Override
public boolean isConstructorParameterIndicator() { return false; }
#Override
public boolean isMethodParameterIndicator() { return false; }
}
#ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("jersey.startup.test");
property("hello.config", "Hello World Property");
register(new AbstractBinder() {
#Override
protected void configure() {
bind(ConfigurationInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Named>>() {
}).in(Singleton.class);
}
});
}
}
Resource
#Path("/config")
public class ConfigResource {
#Named("hello.config")
String hello;
#GET
public Response getHello() {
return Response.ok(hello).build();
}
}
C:\>curl http://localhost:8080/test/rest/config
Hello World Property
Personally though, in this situation, I would create my own annotation, as to not override any existing functionality of the #Named annotation.
Another cool option
HK2 has a configuration extension, where you can load a Properties object from say a .properties file and and have those properties automatically injected with the #Configured annotation. I couldn't find any documentation on this, but there is an example usage of it in the HK2 source code examples.
Here's an example implementation
Required dependencies. Check the Jersey version and see what HK2 version it depends on. In my case Jersey 2.13 uses HK2 2.3.0-b10, so that should be the ${hk2.version}
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-configuration-hub</artifactId>
<version>${hk2.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-configuration-integration</artifactId>
<version>${hk2.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-property-file</artifactId>
<version>${hk2.version}</version>
</dependency>
App config
#ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {
#Inject
public JerseyApplication(ServiceLocator locator) {
packages("jersey.startup.test");
ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);
try {
loadConfigurationProperties(locator);
} catch (IOException ex) {
Logger.getLogger(JerseyApplication.class.getName())
.log(Level.SEVERE, null, ex);
}
}
private void loadConfigurationProperties(ServiceLocator locator)
throws IOException {
ConfigurationUtilities.enableConfigurationSystem(locator);
PropertyFileUtilities.enablePropertyFileService(locator);
PropertyFileService propertyFileService
= locator.getService(PropertyFileService.class);
Properties props = new Properties();
URL url = getClass().getResource("/configuration.properties");
props.load(url.openStream());
PropertyFileHandle propertyFileHandle
= propertyFileService.createPropertyHandleOfAnyType();
propertyFileHandle.readProperties(props);
}
}
configuration.properties
AppConfiguration.App.hello=Hello Squirrel Property!
Resource
#Path("/config")
#ConfiguredBy("AppConfiguration")
public class ConfigResource {
#Configured
String hello;
#GET
public Response getHello() {
return Response.ok(hello).build();
}
}
C:\>curl http://localhost:8080/test/rest/config
Hello Squirrel Property!
Diclaimer: Since this feature isn't well documented, I am not sure if I have a good implementation here. It is just by trial and error. For instance this
ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);
I feel shouldn't be necessary. It seems redundant, as I am already package scanning. So to explicitly add the ConfigResource to the locator context doesn't seem right to me.

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 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.

Accessing a #Singleton from an #Entity without using #Inject/#EJB

I'm using Domain-Driven Design (I think!) and I have a requirement to access some global properties. I have my #Singleton thus:
#Singleton
public class MyProperties {
private Properties props;
#PostConstruct
private void initialize()
{
try {
props.load(new FileInputStream("my.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public String getProperty(String propertyName)
{
return props.getProperty(propertyName);
}
}
I would like to do this:
#Entity(name="MYENTITY")
public class MyEntity {
#Inject private MyProperties props;
void doSomething()
{
String myProp = props.getProperty("my-prop");
// ...etc...
}
}
However, this doesn't work - props is null, and anyway sites tell me not to do that, and I should use a Service Locator instead, but that all smells of using JNDI lookup which EJB 3.x kills off.
My plan might be to try this sort of thing:
#WebListener
public class MyServletContextListener implements ServletContextListener{
#Inject private MyProperties props;
private MyServletContextListener theInstance;
#Override
public void contextInitialized(ServletContextEvent sce) {
theInstance = this;
}
static public MyServletContextListener theInstance() { return theInstance; }
public MyProperties getProperties() { return props; }
}
Does this make sense, or am I barking up the wrong tree, or do I just have some silly bug in my code?
EDIT: Note that I am using vanilla Java EE with CDI, JPA, etc, no Spring.
EDIT2: I see that CDI Best Practises say one should add the #Vetoed annotation to all persistent entities. Currently my application flow control is from a #MessageBean through a series of #Entitys - is this a design smell?
First, any your entities are NOT in spring application context, so, any beans of spring can not inject into your entities!
Second, If you really want to do this, please add:
<context:spring-configured />
into your spring configuration, then add #Configurable at the MyEntity class!
Well, I cracked out my venerable Gang of Four book and realised that I have a Visitor pattern here, which is particularly useful as my #Entitys form a hierarchy. So, I will add code like this:
public class DoSomethingVisitor extends EntityVisitor {
#Inject private MyProperties props;
#Override
void visit(MyEntity entity)
{
String myProp = props.getProperty("my-prop");
if(entity.getValue().equals(myProp))
//...or whatever...
}
}
And:
#Entity(name="MYENTITY")
public class MyEntity {
void Accept(EntityVisitor visitor)
{
visitor.visit(this);
}
}
This solution also allows me to get rid of a logger parameter that I was passing around the doSomething() calls, and my business logic is now out of the #Entitys and into a place where I can do injections.
If you chosen a javaee way that I suppose that using of #EntityListener annotation above entity would be preferred in this case. How it works. Define a listener class with some methods annotated with for example #PostConstruct or #PrePersist :
public class DoSomethingVisitor {
#PrePersist
void visit(MyEntity entity)
{
String myProp = props.getProperty("my-prop");
if(entity.getValue().equals(myProp))
//...or whatever...
}
}
And define this class in annotation of the entity:
#Entity(name="MYENTITY")
#EntityListeners(value = {DoSomethingVisitor.class})
public class MyEntity {
void Accept(EntityVisitor visitor)
{
visitor.visit(this);
}
}
All the best patterns already included in javaee box!

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.

How to write tag in my spring project?

I want to write my tag (extends TagSupport) in my spring framework. In my tag class, will use some service which should auto inject by spring. But I always get null, seems spring can't inject service instance in my tag class.
The code is like the following:
public class FetchTagNameTag extends TagSupport {
#Autowired
private TaskService taskService;
...
taskService is always null.
How can I resolve this?
Thanks.
Have a try by utilizing RequestContextAwareTag. It will offer you methods to obtain RequestContext and then WebApplicaitonContext. Have a look at here.
JSP tag objects are not managed by Spring, they are managed by the servlet container. As a result, you cannot autowire stuff into your tags.
If you need to get hold of beans from the spring appcontext, then your Spring MVC controller needs to set the bean as a request attribute (using request.setAttribute()), so that the tag object can get hold of it.
Annotate your Tag-Implementation with #Configurable and add <context:component-scan base-package="your.webapp"> to your Spring-Configuration.
Check out these spring packages in the spring reference docs and in the spring source:
org.springframework.web.servlet.tags
org.springframework.web.servlet.tags.form
If nothing else, those will show you how the spring developers wrote the spring tags.
What you could do is create a static method like this:
public static void autowireAllFor(Object target) {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(...yourBeanFactory...);
bpp.processInjection(target);
}
and then for your tag you could do
public class YourTag extends TagSupport {
#Autowired
private SomeBean someBean;
public YourTag() {
YourHelperClass.autowireAllFor(this);
}
}
The obvious disadvantage of this approach is that you have to do this for every constructor, but as TagSupport only has one, it should not be a problem. You can go even one step further and create a helper superclass which always guarantees autowiring:
public class SpringTagSupport extends TagSupport {
public SpringTagSupport() {
super();
YourHelperClass.autowireAllFor(this);
}
}
The rest is as easy as extending your classes from SpringTagSupport.
First I write this:
public abstract class SpringSuportedTag extends SimpleTagSupport{
protected WebApplicationContext _applicationContext;
protected WebApplicationContext getSpringContext(){
PageContext pageContext = (PageContext) getJspContext();
if(_applicationContext==null){
_applicationContext = RequestContextUtils.getWebApplicationContext(
pageContext.getRequest(),
pageContext.getServletContext()
);
initCustomBeans();
}
return _applicationContext;
}
protected abstract void initCustomBeans();
/**
* Deprecated for inserting extra logic. Use {#link #doTagWithSpring()} instead.
*/
#Override
#Deprecated
public void doTag() throws JspException, IOException {
getSpringContext();
doTagWithSpring();
}
abstract void doTagWithSpring() throws JspException, IOException;
}
And usage:
public class SlotTag extends SpringSuportedTag {
// #Resource(name="userDetailHolder")
// not work here
UserDetailHolder userDetail;
private String slotname;
public String getSlotname() {
return slotname;
}
public void setSlotname(String slotname) {
this.slotname = slotname;
}
#Override
void doTagWithSpring() throws JspException, IOException {
PageContext pageContext = (PageContext) getJspContext();
String userDetailCode = pageContext.getAttribute(InitWidgetUserTag.KAY_USERDETAIL, PageContext.PAGE_SCOPE).toString();
userDetail.init(userDetailCode);
String pageID = pageContext.getAttribute(InitWidgetUserTag.KAY_PAGEID, PageContext.PAGE_SCOPE).toString();
getJspContext().getOut().println("<b>slot for user:"+userDetail.getUserId()+"</b>");
}
#Override
protected void initCustomBeans() {
userDetail = (UserDetailHolder) getSpringContext().getBean("userDetailHolder");
}
}
It's work.
But than i found this:
Spring supported Tag Libraries. Truth in my progect I still use own solution.
Use :-
import org.springframework.web.servlet.tags.RequestContextAwareTag;
public class FetchTagNameTag extends RequestContextAwareTag {
// #Autowired
// private TaskService taskService;
#Override
protected int doStartTagInternal() throws Exception {
TaskService taskService= getRequestContext().getWebApplicationContext().getBean(TaskService.class);
return 0;
}

Categories