I have an interface, for example
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
public #interface AutoLogged {
boolean query() default false;
}
How can I get query parameter in interceptor implementation?
#Provider
#AutoLogged
public class AutoLoggedInterceptor implements WriterInterceptor {
#Context
private ResourceInfo resourceInfo;
#Override
public void aroundWriteTo(final WriterInterceptorContext context)
throws IOException, WebApplicationException {
try {
final String methodName = this.resourceInfo.getResourceMethod().getName();
BasicAutoLoggedProducer.makeCall(methodName);
} catch (final Exception e) {
e.printStackTrace(System.err);
} finally {
context.proceed();
}
}
}
I can not find it in context.getPropertyNames. I see annotation AutoLogged with getAnnotations method. How to retrieve parameter query from interface?
You can simply do
AutoLogged annotation = resourceInfo.getResourceMethod().getAnnotation(AutoLogged.class);
if (annotation != null) {
boolean query = annotation.query();
}
"and want to set parameter query"
Not exactly sure what you mean hear, but if you mean you want to set the value at runtime, I'm not really sure the purpose and not really sure how to do it. Hopefully you men "get" instead of "set" :-)
Related
I'm building a package that is trying to intercept a function's return value based on a flag. My design involves some AOP. The idea is that a class FirstIntercept intercepts a call firstCall and stores parameters in a Parameters object. Then later, a second class SecondIntercept intercepts another call secondCall and does some logic based on what is populated in Parameters:
// pseudoish code
public class FirstIntercept {
private Parameters param;
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// logic handling payload returned from firstCall()
// logic provides a Boolean flag
this.param = new Parameters(flag);
}
}
public class Parameters {
#Getter
private Boolean flag;
public Parameters(Boolean flag) {
this.flag = flag;
}
}
public class SecondIntercept {
private static Parameters params;
#Around("execution(* ...secondCall(..))")
public void handleSecondCallIntercept(ProceedingJoinPoint joinPoint) {
// want to do logic here based on what params contains
}
}
What I want to achieve is that the Parameters object is loaded once and for all when FirstIntercept.loadParam is invoked through AOP. I'm not too sure how I can go about with this persistence. I looked online and Google guice seems to be promising. I believe a first step would to use dependency injection on the Parameters, but I'm really not sure. Can someone help point me in the right direction?
edit:
So I tried this setup:
public class FirstIntercept implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("invoked!");
return invocation.proceed();
}
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// do stuff
}
public String firstCall() {
return "hello";
}
}
public class InterceptionModule extends AbstractModule {
protected void configure() {
FirstIntercept first = new FirstIntercept();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class), first);
}
}
public class FirstIterceptTest {
#Test
public void dummy() {
Injector injector = Guice.createInjector(new InterceptionModule());
FirstIntercept intercept = injector.getInstance(FirstIntercept.class);
intercept.firstCall();
}
}
When I do .firstCall(), I can see the #AfterReturning running but the invoke is not being called.
If you expand upon the documentation for AOP https://github.com/google/guice/wiki/AOP you should get something close to:
public class FirstInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
// your logic based on result to set parameters.setFlag()
return result;
}
}
Then the second:
public class SecondInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
boolean flag = parameters.getFlag();
// your logic here
return invocation.proceed(); // maybe maybe not?
}
}
Your parameters is the key, you'll need to ensure it's thread safe, which is another topic. But to inject these you need:
public class InterceptionModule extends AbstractModule {
protected void configure() {
// Ensure there is only ever one Parameter injected
bind(Parameter.class).in(Scopes.SINGLETON);
// Now inject and bind the first interceptor
FirstInterceptor firstInterceptor = new FirstInterceptor();
requestInjection(firstInterceptor );
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
firstInterceptor);
// Now inject and bind the second interceptor
SecondInterceptor SecondInterceptor = new SecondInterceptor ();
requestInjection(firstInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
SecondInterceptor);
}
}
Edit
Look at what you're doing.
You're telling Guice to wrap a method with #AfterReturn with the FirstInterceptor
Then you're calling interceptor.firstCall()
First call does not have #AfterReturn annotation, so why would it be matched against that configuration?
I'm guessing if you called:
intercept.loadParam();
you would see the invoke method. Also, this is great for a test, but in real life you want to have a Service level class have the #AfterReturn which is then Injected into another Api/Job/Etc that will call LoadParam.
edit
Oh no. Take a look at this line
bindInterceptor(Matchers.any(), // a class with this matcher
Matchers.annotatedWith(AfterReturning.class), // a method with this
firstInterceptor);
This means that the injector only fires on the loadParams. You need to annotate the method of the class youw ish to cause the interception with #AfterReturning. And you want the loadParams to be the invoke method.
If an exception should be ignored inside a method call, one would write eg the following:
public void addEntryIfPresent(String key, Dto dto) {
try {
Map<String, Object> row = database.queryForMap(key);
dto.entry.put(row);
} catch (EmptyResultDataAccessException e) {}
}
I'm trying to write eg a custom spring annotation that has the same effect, but could just be applied to the method header. That could look similar to the following:
#IgnoreException(EmptyResultDataAccessException.class) //this annotation does not exist
public void addEntryIfPresent(String key, Dto dto) {
Map<String, Object> row = database.queryForMap(key);
dto.entry.put(row);
}
How could such an annotation be created?
Here is a way of doing it with AspectJ.
First of all, define a method level annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface IgnoreRuntimeException{
}
Then, define an around aspect for the annotation.
#Component
#Aspect
public class ExceptionHandlingAdvice {
#Around("#annotation(com.yourpackage.IgnoreRuntimeException) && execution(* *(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
Object returnObject = null;
// do something before the invocation
try {
// invoke method
returnObject = joinPoint.proceed();
// do something with the returned object
return returnObject;
} catch (Exception e) {
// do something with the exception
}
}
}
You can then apply the annotation on top of your methods to ignore exceptions.
#IgnoreRuntimeException
public void addEntryIfPresent(String key, Dto dto) {
// ...
}
You can also check the parameters of the annotation using the api of ProceedingJoinPoint to ignore only the exceptions that you'd like to ignore.
I have annotation:
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
public #interface Loggable { }
and aspect:
#Aspect
public class AspectLogger {
#Around("#annotation(aspects.Loggable)")
public void aroundLogging(ProceedingJoinPoint joinPoint) {
System.out.println("aroundLogging()");
throw new AuthentificationFailException();
}
}
Also I have interface and class:
public interface IAuthInteractor {
public User authorization(String login, String password);
}
public class AuthInteractor implements IAuthInteractor {
private EntityDAO<User> userDAO;
private ITokenGenerator tokenGenerator;
public AuthInteractor(EntityDAO<User> userDAO,
ITokenGenerator tokenGenerator) {
this.userDAO = userDAO;
this.tokenGenerator = tokenGenerator;
}
#Loggable
public User authorization1(String login, String password) {
return null;
}
#Loggable
public User authorization(String login, String password) {
return null;
}
}
For first method (authorization1) annotation doesn't work. For method authorization (that was described in interafce) annotation works.
Why does it work this way? and how to work without interface?
First of all, the aspect's advice has a void return type, i.e. it will never kick in for methods returning other types such as User in your example. The aspect should not even compile. It does not for me in any case. The AspectJ compiler says:
applying to join point that doesn't return void: method-execution(de.scrum_master.app.User de.scrum_master.app.AuthInteractor.authorization(java.lang.String, java.lang.String))
So, assuming you change your advice to
#Around("#annotation(aspects.Loggable)")
public Object aroundLogging(ProceedingJoinPoint joinPoint) {
System.out.println("aroundLogging()");
throw new AuthentificationFailException();
}
it will compile and also kick in. I tested it locally.
Now let me just quickly change the advice to actually proceed to the original method instead of always throwing an exception so we can test a bit more without catching exceptions all the time. I also want to print the actual joinpoint signature, so we can see what is going on:
#Around("#annotation(aspects.Loggable)")
public Object aroundLogging(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
//throw new AuthentificationFailException();
return joinPoint.proceed();
}
If then you add this main method to your interface implementation class:
public static void main(String[] args) {
System.out.println("Interface object");
IAuthInteractor iAuthInteractor = new AuthInteractor(null, null);
iAuthInteractor.authorization("user", "pw");
System.out.println("\nImplementation object");
AuthInteractor authInteractor = new AuthInteractor(null, null);
authInteractor.authorization("user", "pw");
authInteractor.authorization1("user", "pw");
}
The console log should print something like this, assuming you use AspectJ and not just "AOP lite" via Spring AOP which does not support call() joinpoints:
Interface object
execution(User de.scrum_master.app.AuthInteractor.authorization(String, String))
Implementation object
call(User de.scrum_master.app.AuthInteractor.authorization(String, String))
execution(User de.scrum_master.app.AuthInteractor.authorization(String, String))
call(User de.scrum_master.app.AuthInteractor.authorization1(String, String))
execution(User de.scrum_master.app.AuthInteractor.authorization1(String, String))
As you can see, executions are always caught, but calls are not for interface type instances because the interface method is not annotated, only the implementation.
BTW, method annotations are not inherited anyway, so your #Inherited meta annotation for an annotation type with #Target({ElementType.METHOD}) is kinda useless.
I use #ControllerAdvice to handle all my app exceptions :
#ControllerAdvice
public class ExceptionHandlingController {
#ExceptionHandler({UnauthorizedException.class})
public String unauthorizedException() {
.........
}
#ExceptionHandler({UnauthorizedAjaxException.class})
#ResponseBody
public void unauthorizedAjaxException() {
.........
}
#ExceptionHandler({Exception.class})
public String globalException(){
.........
}
}
And somewhere in my code i do throw new UnauthorizedException();
#Around("#annotation(Authenticated)")
public Object profilingAuthentication(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
if( request.getSession().getAttribute("idContact") == null ) {
if( "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) )
throw new UnauthorizedAjaxException();
throw new UnauthorizedException();
}
return pjp.proceed();
}
But sadly Spring MVC appears to be acting random by using the most generic case (Exception) rather than more specific ones (UnauthorizedException for example). And sometimes he choose the correct one !
How the order works works ? and is there any way to specify the order ?
UnauthorizedException is a custom exception
public class UnauthorizedException extends Exception {
public UnauthorizedException(){
super();
}
public UnauthorizedException(String message){
super(message);
}
}
UPDATE
i found out that the order it's not rondom actually the methods who throw UnauthorizedException works normally but the others not !
#Authenticated
#RequestMapping(value="/favoris")
public String favoris(ModelMap model, HttpServletRequest request)
throws UnauthorizedException {
....
}
#Authenticated
#RequestMapping(value="/follow")
public String follow(ModelMap model, HttpServletRequest request) {
.....
}
So i have to add throws UnauthorizedException manually or there is some other solution ?
we are using exception handler in following way and never order get mixed and it work as expected.
So it could be possible if you will use it as following example then it will solve your problems
**********handler class******************
#ControllerAdvice
public class GlobalExceptionHandler {
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public boolean handle1(Exception exc) {
System.out.println("#####Global Exception###" + exc);
exc.printStackTrace(System.out);
return true;
}
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = CustomException.class)
public boolean handle2(CustomException exc) {
System.out.println("###custom exception######" + exc);
exc.printStackTrace(System.out);
return true;
}
}
***************Controller class************
#RestController("test")
#RequestMapping("/test1")
public class TestController {
#RequestMapping("/t1")
public boolean test() {
if (true) {
throw new CustomException();
}
return true;
}
}
In above example exception habdler is handle2 because 1st of all it will search for matching exception if not found then go for parrent handler
If we throw new NullPointerException() then it will search for matching handler but not found in this case then go for parrent that is handle1
for more you can refer here
I hope it will help you. Thanks
Use an annotation #Order or implement an interface Ordered for #ControllerAdvice.
See implementations of:
ExceptionHandlerMethodResolver class
ExceptionHandlerExceptionResolver class (method initExceptionHandlerAdviceCache)
AnnotationAwareOrderComparator class
There is no order/priority as long as you have a single controlleradvice class in your project. But if you have multiple controlleradvice classes, you can set the Order. But here, in your case, the order is not applicable as the two exceptions are handled differently (i.e., UnauthorizedException and Exception).
The good thing is, Spring will automatically find the respective custom Exception class (if any,
otherwise generic Exception) and invoke the corresponding method.
Please refer for more information on Spring Controller Advice and Exception handling:
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
I am trying to create a custom http param binding for my restful service. Please see the example below.
#POST
#Path("/user/{userId}/orders")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(#PathParam("userId") String someString, #UserAuthHeaderParam String authString){
}
You can see that there is a UserAuthHeaderParam annotation in the function signature. What I want to do is have a custom http param binding other than the standard javax.ws.rs.*Param .
I have try to implement org.glassfish.hk2.api.InjectionResolver which basically extract the value from http header:
public class ProtoInjectionResolver implements InjectionResolver<UserAuthHeaderParam>{
...
#Override
public Object resolve(Injectee injectee, ServiceHandle< ? > root)
{
return "Hello World";
}
...
}
When I call the restful service, the server get below exceptions. It indicates that the framework fails to resolve the param in the function signature:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=MyResource,qualifiers={}),position=0,optional=false,self=false,unqualified=null,2136594195),
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of rs.server.MyResource errors were found
Please help. Any advise is appreciated. I do make a lot of search on google but fails to make it work. Jersey 2.*. How to replace InjectableProvider and AbstractHttpContextInjectable of Jersey 1.* might be the similar question.
-- UPDATES:
I use AbstractBinder to bind my resolver to UserAuthHeaderParam:
public class MyApplication extends ResourceConfig
{
public MyApplication()
{
register(new AbstractBinder()
{
#Override
protected void configure()
{
// bindFactory(UrlStringFactory.class).to(String.class);
bind(UrlStringInjectResolver.class).to(new TypeLiteral<InjectionResolver<UrlInject>>()
{
}).in(Singleton.class);
}
});
packages("rs");
}
}
Thank you!
If all you want is to pass value directly from the header to the method you don't need to create custom annotations. Let's say you have a header Authorization, then you can easily access it by declaring your method like this:
#GET
public String authFromHeader(#HeaderParam("Authorization") String authorization) {
return "Header Value: " + authorization + "\n";
}
You can test it by calling curl, e.g.
$ curl --header "Authorization: 1234" http://localhost:8080/rest/resource
Header Value: 1234
Given that the answer to your question, how to create custom binding is as follows.
First you have to declare your annotation like this:
#java.lang.annotation.Target(PARAMETER)
#java.lang.annotation.Retention(RUNTIME)
#java.lang.annotation.Documented
public #interface UserAuthHeaderParam {
}
Having your annotation declared you have to define how it will be resolved. Declare the Value Factory Provider (this is where you'll have access to the header parameters - see my comment):
#Singleton
public class UserAuthHeaderParamValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
protected UserAuthHeaderParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(Parameter parameter) {
Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(String.class))) {
return null;
}
return new AbstractHttpContextValueFactory<String>() {
#Override
protected String get(HttpContext httpContext) {
// you can get the header value here
return "testString";
}
};
}
}
Now declare an injection resolver
public class UserAuthHeaderParamResolver extends ParamInjectionResolver<UserAuthHeaderParam> {
public UserAuthHeaderParamResolver() {
super(UserAuthHeaderParamValueFactoryProvider.class);
}
}
and a Binder for your configuration
public class HeaderParamResolverBinder extends AbstractBinder {
#Override
protected void configure() {
bind(UserAuthHeaderParamValueFactoryProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
bind(UserAuthHeaderParamResolver.class)
.to(new TypeLiteral<InjectionResolver<UserAuthHeaderParam>>() {})
.in(Singleton.class);
}
}
now the last thing, in your ResourceConfig add register(new HeaderParamResolverBinder()), like this
#ApplicationPath("rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new HeaderParamResolverBinder());
packages("your.packages");
}
}
Given that, you should be now able to use the value as you wanted:
#GET
public String getResult(#UserAuthHeaderParam String param) {
return "RESULT: " + param;
}
I hope this helps.
I don't know how to resolve your exception. However, may I propose you a different way to do the same thing. I hope it helps.
I've faced exactly the same problem: I need extra parameters in the http header (btw, also related to authentication). Besides, I need to send them in every call, since I want to do a "typical" rest implementation, without maintaining a session.
I'm using Jersey 2.7 - but I'd say it should work in 2.0. I've followed their documentation
https://jersey.java.net/documentation/2.0/filters-and-interceptors.html
It's quite clear there, but anyway I copy-paste my implementation below.
It works fine. True there are some other ways to secure a rest service, for example this is a good one:
http://www.objecthunter.net/tinybo/blog/articles/89
But they depend on the application server implementation and the database you use. The filter, in my opinion, is more flexible and easier to implement.
The copy-paste: I've defined a filter for authentication, which applies to every call and it is executed before the service (thanks to #PreMatching).
#PreMatching
public class AuthenticationRequestFilter implements ContainerRequestFilter {
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
if (headers == null) {
throw new...
}
// here I get parameters from the header, via headers.get("parameter_name")
// In particular, I get the profile, which I plan to use as a Jersey role
// then I authenticate
// finally, I inform the Principal and the role in the SecurityContext object, so that I can use #RolesAllowed later
requestContext.setSecurityContext(new SecurityContext() {
#Override
public boolean isUserInRole(final String arg0) {
//...
}
#Override
public boolean isSecure() {
//...
}
#Override
public Principal getUserPrincipal() {
//...
}
#Override
public String getAuthenticationScheme() {
//...
}
});
}
}
You have to include this filter class in your implementation of ResourceConfig,
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
// my init
// my packages
register(AuthenticationRequestFilter.class); // filtro de autenticación
// other register
}
}
Hope it helps!
If your need is to retrieve all the http headers binding into one object, a solution could be to use the #Context annotation to get javax.ws.rs.core.HttpHeaders; which contains the list of all request headers.
#POST
#Path("/user/{userId}/orders")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(#PathParam("userId") String someString, #Context HttpHeaders headers){
// You can list all available HTTP request headers via following code :
for(String header : headers.getRequestHeaders().keySet()){
System.out.println(header);
}
}
here is my actual implementatipn of UserAuthHeaderParamValueFactoryProvider class
import javax.inject.Inject;
import javax.inject.Singleton;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
import org.glassfish.jersey.server.model.Parameter;
#Singleton
public class UserAuthHeaderParamValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
protected UserAuthHeaderParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(Parameter parameter) {
Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(String.class))) {
return null;
}
return new AbstractContainerRequestValueFactory<String>() {
#Override
public String provide() {
//you can use get any header value.
return getContainerRequest().getHeaderString("Authorization");
}
};
}