Created Custom annotation and add annotation at method level and pass value to Spring-Aspect.
springboot: application.properties spring.event.type=TEST
Output: PreHook Value|${spring.event.type}
I am expecting : TEST
Can someone please help how to populate value from properties file and inject to annotation.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface PreHook {
String eventType();
}
#Aspect
#Component
public class ValidationAOP {
#Before("#annotation(com.example.demo.annotation.PreHook)")
public void doAccessCheck(JoinPoint call) {
System.out.println("ValidationAOP.doAccessCheck");
MethodSignature signature = (MethodSignature) call.getSignature();
Method method = signature.getMethod();
PreHook preHook = method.getAnnotation(PreHook.class);
System.out.println("PreHook Value|" + preHook.eventType());
}
}`
#RestController
public class AddController {
#GetMapping("/")
#PreHook(eventType = "${spring.event.type}")
public String test() {
System.out.println("Testcontroller");
return "Welcome Home";
}
}
You have to add SPEL processing to you annotation to evaluate that expression. You should not expect Spring to handle everything for you magicaly out of the box.
public void doAccessCheck(JoinPoint call) {
///(....)
PreHook preHook = method.getAnnotation(PreHook.class);
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(preHook.eventType());
String parsedType= (String) exp.getValue();
System.out.println("PreHook Value|" + parsedType);
}
Please refer below link for details. you are just few steps away.
Use property file in Spring Test
Related
I create a custom annotation and HandlerInterceptorAdapter that will just get memberNo and print it out.
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface MyCustomAnnotation
{
String memberNo();
}
And on Controller something like this:
#MyCustomAnnotation(memberNo = "${someBodyObject.memberNo}")
#RequestMapping(value = "/test/", method = RequestMethod.GET)
public String test(#RequestBody SomeBodyObject someBodyObject) {
System.out.println("--- TEST ---");
return "-- FINISHED ---";
}
Request body SomeBodyObject have one filed and it's memberNo.
How can I inject that memberNo from RequestBody to HandlerInterceptorAdapter?
And is it possible to user Spring SpEL or something else to get data from Body and send to AnnotationResolver?
Or maybe there is some other way to do this?
I try like this and response is: ${token.memberNo} as a String
That's not possible.
Annotations require constant values and a method parameter is dynamic.
I have annotation & want to send class name there as parameter:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
#Documented
public #interface PostApiRequest {
Class<?> value();
}
I attach annotation to method of parent class:
#PostApiRequest(value = ...)
#Override
public ResponseEntity<D> save(#RequestBody D dto) {
Application don't know, which inheritor shall call this method, than I want to send inheritor there to work with its properties later. I should see any like this:
#PostApiRequest(value = this.class) //send inheritor
#Override
public ResponseEntity<D> save(#RequestBody D dto) {
but it not works.
Please, give advice, how to do it?
Is there a way to get Spring AOP to recognize the value of an argument that has been annotated? (There is no guarantee in the order of the arguments passed into the aspect, so I'm hoping to use an annotation to mark the parameter that needs to be used to process the aspect)
Any alternative approaches would also be extremely helpful.
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface Wrappable {
}
#Target({ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface Key {
}
#Wrappable
public void doSomething(Object a, #Key Object b) {
// something
}
#Aspect
#Component
public class MyAspect {
#After("#annotation(trigger)" /* what can be done to get the value of the parameter that has been annotated with #Key */)
public void trigger(JoinPoint joinPoint, Trigger trigger) { }
Here is an example of an aspect class which should process a method tagged with #Wrappable annotation. Once the wrapper method is called, you can iterate over method parameters to find out if any parameter is tagged with the #Key annotation. The keyParams list contains any parameter tagged with a #Key annotation.
#Aspect
#Component
public class WrappableAspect {
#After("#annotation(annotation) || #within(annotation)")
public void wrapper(
final JoinPoint pointcut,
final Wrappable annotation) {
Wrappable anno = annotation;
List<Parameter> keyParams = new ArrayList<>();
if (annotation == null) {
if (pointcut.getSignature() instanceof MethodSignature) {
MethodSignature signature =
(MethodSignature) pointcut.getSignature();
Method method = signature.getMethod();
anno = method.getAnnotation(Wrappable.class);
Parameter[] params = method.getParameters();
for (Parameter param : params) {
try {
Annotation keyAnno = param.getAnnotation(Key.class);
keyParams.add(param);
} catch (Exception e) {
//do nothing
}
}
}
}
}
}
We cannot get the parameter annotation value as an argument to AOP like we are doing it for the method annotation because the annotation is not an actual parameter and in there you can only reference actual arguments.
args(#Key b)
This annotation will give you the value of Object(b) not the value of #Key annotation.
We can do in this way to get the value of the parameter annotation:
MethodSignature methodSig = (MethodSignature) joinpoint.getSignature();
Annotation[][] annotations = methodSig.getMethod().getParameterAnnotations();
if (annotations != null) {
for (Annotation[] annotArr : annotations) {
for (Annotation annot : annotArr) {
if (annot instanceof KeyAnnotation) {
System.out.println(((KeyAnnotation) annot).value());
}
}
}
}
I am trying to use the Meta-annotation of spring using the aliasFor annotation to create a custom annotation for the springs RequestParam
Simply 'extend/replace'
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface RequestParam {
#AliasFor("name")
String value() default "";
----
}
with my annotation
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface QueryParam {
#AliasFor(annotation = RequestParam.class, attribute = "name")
String name() default "";
#AliasFor(annotation = RequestParam.class, attribute = "required")
boolean required() default false;
#AliasFor(annotation = RequestParam.class, attribute = "defaultValue")
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
This way it throws the Exception
org.springframework.core.annotation.AnnotationConfigurationException: #AliasFor declaration on attribute [name] in annotation [package.QueryParam] declares an alias for attribute [name] in meta-annotation [org.springframework.web.bind.annotation.RequestParam] which is not meta-present.
Problem is that without the RequestParam annotated on the QueryParam this doesn't work. And it is not possible to put the RequestParam as it PARAMETER targeted.
#RequestParam <--This is not possible.
public #interface QueryParam
So is there another way to achieve this ?
Basically what you want to achieve is not possible now, at least for the Spring v 4.3.3 There are main two problems, the first one is the fact that annotations like #RequestParam are declared with #Target(ElementType.PARAMETER) which make it impossible to be used as part of meta annotations. Furthermore, Spring MVC looks up annotations on method parameters using org.springframework.core.MethodParameter.getParameterAnnotations() which does not support meta-annotations or composed annotations. But if you really need some customizations there you can use HandlerMethodArgumentResolver instead of meta annotations.
So you code will look something like
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface QueryParam {
String name() default "";
boolean required() default false;
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
Then using the HandlerMethodArgumentResolver add the custom logic which you need.
public class QueryParamResolver implements HandlerMethodArgumentResolver {
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(QueryParam.class) != null;
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
QueryParam attr = parameter.getParameterAnnotation(QueryParam.class);
// here you can use any logic which you need
return webRequest.getParameter(attr.value());
}
}
Then we need to register our HandlerMethodArgumentResolver
#Configuration
#EnableWebMvc
public class Config extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new QueryParamResolver());
}
}
And last lets use our custom annotation
#GetMapping("/test")
public String test(#QueryParam("foo") String foo){
// something here
}
i had same problem and I entered the wrong package for GetAmpping. I must import «import org.springframework.web.bind.annotation.GetMapping» .
The annotation class Get.java
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#interface Get {
String value();
}
The annotation class Field.java
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#interface Field {
String value();
}
The interface class GetInterface.java
public interface GetInterface {
#Get("/group/user?")
void getUser(#Field("id") String id);
}
I want to use this GetInterface in the following, how can I get the annotation name so I can use that as the parameter attribute to construct a get url with query parameters
public class Request implements GetInterface {
#Override
public getUser(String id) {
String getPath = "/group/user?"; //How can I get this path from the annotation?
String name = "how can I get the name attribute 'id'????";
String value = id; //this will be 123 in this example
//with the name an value, I can then construct a url like this
//https://www.foo.com/group/user?id=123
}
public static void main(String[] args) {
getUser("123);
}
}
Do the following:
Method m = GetInterface.class.getMethod("getUser");
Get getAnnotation = m.getAnnotation(Get.class)
Field fieldAnnotation = m.getParameters()[0].getAnnotation(Field.class)
String path = getAnnotation.value();
String fieldName = fieldAnnotation.value();