How does Spring inject values into variable annotated by #HeaderParam? - java

I am trying to dive deep into the mechanics of the Spring Framework. The following piece of code achieves inserting "token" parameter from HTTP request into the token variable:
#POST
#Path("/")
Response saveOne(#HeaderParam("token") String token, UserDTO uDTO) {
}
How can I achieve the same?
And what tools do I need? Is it done using AOP? Say, I would like to come up with a custom annotation #MyAnnotation and any parameter or field marked by it would be customized by some logic. Example:
public class MyClass {
...
#MyAnnotation
private String myVar1;
public void myMethod(#MyAnnotation myParam1) {
...
}
...
}
When I create instance of MyClass or when I autowire it in my Spring application I would like to have a piece code that triggers right before I use the myVar1 variable and/or when I call the myMethod(param1). I want to set the annotated variable to whatever value I want. How can I do this?
What makes me wonder is how Spring does do it in case of the #HeaderParam? I basically need the same functionality.

Related

Better practice with Spring MVC: Service with non-fixed dependency

I have a requirement of compatibility with a new architecture based in Spring 3.2. The requirement is: a http request will come to a controller with an attribute that defines which kind of object is required. For example ...mycontroller/load?objType='obj1'.
My controller will have this structure:
#Controller
public class myController{
private ObjectService objectService;
#Autowired
public setObjectService(ObjectService objectService){
this.objectService = objectService;
}
}
So after that, I need to check this attribute to decide which service will I use. For example, this case is Obj1Service (method: "load"). All this services are extended from ObjectService, so: It is a good idea to swap objectService dependency to Obj1Service / Obj2Service in each incoming call? For example:
if(objType.equals("obj1")) this.setObjectService(context.getBean("obj1Service"..))
if(objType.equals("obj2")) this.setObjectService(context.getBean("obj2Service"..))
I know that is not a great design, but we need to integrate this new modules with other system that produces this kind of http requests.
It is necessary the inheritance because we have very similar behavior in many service's code, but with modifications in internal methods, so part of the behavior will be placed in ObjectService (it is not abstract) and other portion of the code will be placed in it children. Is there another way, more appropriate, to do this? Or you consider that is an acceptable solution?
Thanks!
You can use a map for all of your services, and get the appropriate service inside each controller method.
Let's say you have two services:
#Service("obj1")
public class ObjectServiceImpl1 implements ObjectService {
...
}
#Service("obj2")
public class ObjectServiceImpl2 implements ObjectService {
...
}
In your controller:
private Map<String, ObjectService> objectServices;
#Autowired
public setObjectServices(Map<String, ObjectService> objectServices){
this.objectServices= objectServices;
}
Spring will inject the map with all the ObjectService beans mapped by their names.
In load?objType=obj1 handler, you would have something like:
objectServices.get("obj1").doSomething(); // will use ObjectServiceImpl1
The same with load?objType=obj2 handler:
objectServices.get("obj2").doSomething(); // will use ObjectServiceImpl2
And so on.

HK2 and Impls with constructor arguments

I'm using HK2 as part of a Jersey RESTful API. I'm working in an multitenant system, and in most of my API calls, the tenant is a path parameter. I also have several DAOs, which currently accept the tenantId in their constructor, such as:
public final class WidgetMapper {
public WidgetMapper(final int tenantId) { .. }
..
}
I'd like to use HK2 to provide my DAOs to the other layers of my application. What's the right way to do this?
Change the DAOs to use a setter rather than a constructor argument. Only .. ick. The tenantId is part of the required state of the DAO.
Add a layer of abstraction. Create <interface>MapperFactory and MapperFactoryImpl, which has a no-arg constructor and a bunch of getters, such as getWidgetMapper and getGizmoMapper. Only .. this seems cumbersome. I'd rather not have to maintain these extra classes.
Is there some magic way for HK2 to inject that int value into the WidgetMapper constructor at runtime? Then I could inject the tenantId into the mapper, and the mapper into my other classes.
?? Other HK2 magic?
You need to extract the tenant ID from the path parameter in the request, so as long as it's OK to instantiate your DAOs for each request, you can implement a Factory.
public WidgetMapperFactory implements Factory<WidgetMapper> {
private final ContainerRequestContext containerRequestContext;
#Inject
public WidgetMapperFactory(ContainerRequestContext containerRequestContext) {
this.containerRequestContext = containerRequestContext;
}
public WidgetMapper provide() {
UriInfo uriInfo = containerRequestContext.getUriInfo();
List<String> matchedUris = uriInfo.getMatchedURIs();
int tenantId = 1; // Actually work it out from the matched URIs
return new WidgetMapper(tenantId);
}
public void dispose() {
// Do any clean up you need
}
}
Then bind the factory:
public MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(WidgetMapperFactory.class).to(WidgetMapper.class).in(RequestScoped.class);
}
});
}
}
You can then inject WidgetMapper in a Resource class, and the WidgetMapper doesn't have any knowledge it's being used in a web service.
Change the DAOs to use a setter rather than a constructor argument.
Only .. ick. The tenantId is part of the required state of the DAO.
If your DAOs are singletons I don't see how this would work (or at least how it could be done cleanly).
What's the right way to do this?
IMO, I think the best approach is to have 1) singleton DAOs 2) some type of proxy that got injected into the DAOs when they were instantiated by HK2 and then provided the correct tenant id for the current thread.
I can think of two ways to do this:
Option 1:
I haven't tried it, but I think you could probably inject UriInfo into your DAOs, either through the constructor, a private field, or setter. You could extract the tenant id for the current request from the UriInfo instance.
If I were you, I'd create an abstract class for my DAOs that got a UriInfo injected into a private field. I'd then provide a protected method to return the current tenant id from uriInfo.getPathParameters
public abstract class AbstractDao {
// jersey/hk2 provides a proxy that references the current thread-bound request
#Context
private UriInfo info;
protected int getTenantId()
{
// always returns the tenant id for the current request. TODO: add
// logic to handle calls that don't have a tenant id.
return Integer.valueOf(info.getPathParameters.getFirst("tenantId");
}
}
Option 2:
?? Other HK2 magic?
You could write a custom injection resolver.
One more idea...
Option 3:
This one doesn't directly answer your question since it doesn't use HK2 to inject the tenant ID into the DAOs but I think it's worth mentioning.
You could implement your own ContainerRequestFilter that obtained the tenant id and provided it to other components in your app.
By default, Jersey will invoke the filter after it resolves the resource method but before the method is actually invoked. You can obtain a UriInfo from the ContainerRequestContext, get the tenant id path param, then stuff that param into your own thread local variable. You could then reference the thread local within your DAO. Again, I recommend adding a protected method in a base DAO class to encapsulate this logic.
in most of my API calls, the tenant is a path parameter
Optionally, you can use NameBinding to control the behavior described above.
If you wanted to, you could implement option 3 using a regular ServletFilter instead.
Note:
After I wrote this answer, I realized that I assumed you were comfortable extending ResourceConfig, that you knew how to obtain an instance of ServiceLocator, and that you were comfortable with adding your own bindings. If you're not, let me know and I'll edit my answer to provide more details.

Instantiating bean using factory pattern in Spring MVC 3

I got Object coming in a REST web service controller's web method which is locally initialized.
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
System.out.println(reqObj.getcode());
return new ModelAndView("responsedetails", "object", reqObj);
}
This RequestObj object holds the key code to instantiate dependency using factory.
Different codes classes have been defined which implement BaseCode Interface.
How can I use factory method to instantiate particular code class based on code value coming in as BaseCode type in my service bean?
Any idea? Thanks in advance.
What I usually do in such cases is:
inject the factory into the controller using Spring's bean
create a method getBaseCode(String code) in the factory (please note: String here stands for code type, so use the actual code type if not String
make getBaseCode returning the BaseCode interface while constructing the real implementation
supposing you have an execute method in BaseCode, use the getBaseCode method into the controller to get the real collaborator and then call the execute method to perform the actual action
Ignoring the first point (which I think you can easily looking at any Spring tutorial) the factory will be something like
public class BaseCodeFactory {
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return new ThisBaseCodeImpl();
else //and so on
}
}
while computeDetails becomes similar to:
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
//...
factory.getBaseCode(reqObj.getcode()).execute();
//...
}
As a side note, I will not go for names like the one I choose here, I suggest you to look for something more significative in your domain (BaseCode has no meaning for example), take this snippets just as a directive.
Base on OP comment. If you have ThisBaseCodeImpl which makes use of other Spring bean you can
annotate it with #Configurable so, when you use new ThisBaseCodeImpl(/*args if you like*/) its bean are instantiated by Spring. I don't personally like this solution since, in my opinion, it pollutes the code with hidden Spring's bean. On the other hand is quite flexible, since it allows you to manage both runtime constructor arguments and Spring beans
add ThisBaseCodeImpl to the Spring context and change the factory, so that a collaborator for ThisBaseCodeImpl is injected into it.
1st point example:
#Configurable
public class ThisBaseCodeImpl {
#Resource
private Bean bean;
}
2nd point example:
public class BaseCodeFactory {
#Resource
ThisBaseCodeImpl thisBaseCodeImpl;
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return thisBaseCodeImpl;
else //and so on
}
}
I'm not sure if I understood your problem well, but in general spring dependencies have nothing to do here. Just write custom Factory class and return BaseCode implemetation depending on the reqObj.getcode().
I did it this way -
Make your factory as ServletContextAware in a way to get the currentContext. And define getInstance method as
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
ctx.getBean(classNameToBeInstantiated);
Define your bean's inheritance in spring context so that Spring injects its dependencies.

Writing interceptors for parameter annotations using Guice

Main References for My Question:
Writing Method Interceptors for Google Guice: http://code.google.com/p/google-guice/wiki/AOP
The JavaDoc for the MethodInterceptor interface: http://aopalliance.sourceforge.net/doc/org/aopalliance/intercept/MethodInterceptor.html
General references about Java annotations: http://docs.oracle.com/javase/tutorial/java/javaOO/annotations.html and http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html
Now My Question:
I am writing a Java application that heavily relies on Google Guice for creating objects and handling dependency injection. I am trying to use interceptors to run pre-processing code before certain annotated methods are executed. So far, I have successfully been able to execute interceptors (using the MethodInterceptor interface) on methods that have been annotated, using Guice's instructions. However, I want to now write interceptors that will execure on Parameter Annotations.
Here is an example scenario. First, I create my own annotation. For example::
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface MyParameterAnnotation {
}
Next, I write my own interceptor for this annotation:
public class MyParameterAnnotationInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Do some stuff
return invocation.proceed();
}
}
Here's an example of how I intend on using #MyParameterAnnotation:
public class ExampleObject {
public String foo(#MyParameterAnnotation String param) {
...
}
}
Finally, I need to create a Guice Injector and use it to create an instalce of ExampleObject, or else I cannot use a method interceptor in this project. I configure the Injector so that the MyParameterAnnotationInterceptor is bound to #MyParameterAnnotation, like so:
final MethodInterceptor interceptor = new MyParameterAnnotationInterceptor();
requestStaticInjection(MyParameterAnnotationInterceptor.class);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyParameterAnnotation.class), interceptor);
When I follow the above steps and execute a call to ExampleObject.foo(), unfortunately the interceptor is not executed despite the parameter being marked by #MyParameterAnnotation. Note that these similar steps will work if the annotation was placed at the method level instead.
This leads me to come up with two possible conclusions: either Guice cannot support binding an interceptor to a parameter annotation, or I am doing something completely incorrect (perhaps I should use another AOP Alliance interface for the interceptor, like FieldInterceptor, but I highly doubt it because the JavaDoc for Guice's AbstractModule suggests that the bindInterceptor() method can only use a MethodInterceptor parameter).
Nonetheless, all help us much appreciated :)
The matcher is for method annotations not method parameter annotations.
There is no matcher provided by Guice for method parameter annotations--you either have to write one yourself or use some other scheme. Note that this is a bit of an odd use case--Generally you can get away with
public class ExampleObject {
#MyAnnotation
public String foo(String param) {
...
}
}
You have the right Guice interceptor config for the above example.

Intercepting Specific Annotations with Spring AOP

I'm looking to see whether or not the following is even possible, as all preliminary searches haven't turned back anything to indicate either way.
I'd like to use Hibernate's Validator annotations to validate bean methods, and I would like to use some AOP framework (Spring, AOP Alliance, AspectJ, etc.) to intercept methods annotated with a subset of the Hibernate Validator annotations (#NotNull, #NotEmpty, #Email, etc.); I then want AOP advice to run when they are encountered.
Is this possible to do? If so, I am having a tough time visualizing how the code would work. Using Spring AOP's MethodInterceptor interface as an example:
First, the bean using Hibernate Validator:
public class SomeBean
{
private String data;
// Hibernate Validator annotation specifying that "data" cannot be an empty
// string.
#NotEmpty
public String getData() { ... } // etc.
}
Then, some code using that bean:
public void someMethod()
{
SomeBean oBean = new SomeBean();
// Validation should fail because we specified that "data" cannot be empty.
oBean.setData("");
}
Next, the AOP advice to be ran when Hibernate Validator-annotated methods are encountered.
public class ValidationInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation invocation)
{
// Here's where we would use Hibernate's validator classes.
// My code example here is wrong, but it gets the point across.
Class targetClass = invocation.getClass(); // Should give me SomeBean.class
ClassValidator<targetClass> oValidator= new ClassValidator<targetClass>();
// Here I need to get a reference to the instance of the offending
// SomeBean object whose data has been set to empty...not sure how!
SomeBean oOffendingBean = getTheBadBeanSomehow();
InvalidValue[] badVals = oValidator.getInvalidValues(oOffendingBean);
}
}
So, not only am I choking on what the Spring AOP (pointcut definitions, etc.) configuration would look like to intercept the Hibernate Validator annotations I want, and not only do I not fully grasp how to implement the actual advice (e.g. how to instantiate the offending SomeBean from inside the advice as I mention above in the comments), but I'm not even sure if this solution is possible, Spring or otherwise.
Thanks in advance for some gentle "nudges" in the right direction!
You might be interested in the method validation feature introduced with Hibernate Validator 4.2 which provides support for validating method parameters and return values.
You then might use Seam Validation which integrates this functionality with CDI. If you want to use method validation together with Spring you could have a look this project on GitHub which shows how to integrate the method validation functionality with Spring AOP (disclaimer: I'm the author of this project as well as of Seam Validation).
To make your example working you would have to annote the parameter of the setter method with #NotEmpty like this:
public class SomeBean {
private String data;
#NotEmpty
public String getData() { return data; }
public void setData(#NotEmpty String data) { this.data = data; }
}

Categories

Resources