Is there a way to create a custom, or use an existing, annotation to trigger code to run when the annotated method is called? Preferably, I would like to use Spring libraries.
For example:
#SendEmail("templateName")
public void doSomething() {
log.info("Something is happening");
}
public void sendEmail(String templateName) {
// This method is called everytime doSomething() is called
log.info("Sending email using template " + templateName);
}
#Component
#Aspect
public class Mail {
#After("execution (#com.yourdirectoryofyourcustomAnnotation.SendMail * *(..))")
public void sendEmail(JointPoint jp){
// it will send a mail after every method which tagged by your annotation
}
}
Related
As seen in the documentation, the standard way of declaring a route in Quarkus is with the #Path() annotation, like so :
#Path("myPath")
public class Endpoint {
#GET
public String hello() {
return "Hello, World!";
}
}
This will create the route GET /MyPath. However, #Path being an annotation, I have to give it constant expression.
I would like to be able to declare a route with a non constant expression, something like #Path(MyClass.class.getSimpleName())
I tried to implement something like this:
public class Endpoint {
public void initialize(#Observes StartupEvent ev) {
declareRoute(MyClass.class.getSimpleName(), HttpMethod.GET, this::hello);
}
public String hello() {
return "Hello, World!";
}
public void declareRoute(String path, HttpMethod method, Consumer handler) {
// TODO implement
}
}
This would create the route GET /MyClass But I have no idea how to implement declareRoute(). I tried to inject the Vertx Router since Quarkus seems to use it, but I did not find a way to add a route. Is this doable, and if so, how ?
You essentially need to do something like:
#ApplicationScoped
public class BeanRegisteringRoute {
void init(#Observes Router router) {
router.route("/my-path").handler(rc -> rc.response().end("Hello, World!"));
}
}
See this for more information
I have this aspect that is called on every method annotated with #LogActivity annotation.
#Aspect
#Component
public class EndpointAspect {
#Around("#annotation(LogActivity)")
public Object logActivity(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
// I want to access message here. see below
return result;
}
}
And this is one annotated method:
public class contrlr {
#LogActivity
#GetRequest("/home")
public String aMethod() {
String message = "some RUNTIME-GENERATED message"; // I want to send it to aspect
return "home.html"
}
}
I want to pass the message to aspect. note that message may not be hard-coded constant. How to do that?
New to Camel, so maybe I'm misunderstanding how processors and beans should interact. We have some logging to a database that we want to do throughout a camel route. The idea was to do this in a processor. However, we'd also like to do this logging from w/in the beans. Is that possible? I know I could pass it back as a return field from the bean...but it is already passing back a return.
A related question is how to pass that status, thinking it would be an exchange property or header.
Basically I want something along the lines of
processor
class EventStatusProcessor implements Processor {
#Override
void process(Exchange exchange) throws Exception {
// do some stuff, thinking this will be a header
}
}
route
from("direct:route1")
.bean(doSomething, 'doSomething')
.process(new EventStatusProcessor())
bean
#Component
#Slf4j
class DoSomething{
String doSomething()
//doing stuff
new EventStatusProcessor().process()
You can pass Exchange to method invoked with bean component too and set there headers/properties/body/whatever depending on your needs.
class DoSomething {
#SuppressWarnings("unused") //called via Camel bean invocation
public void doSomething(Exchange exchange){
exchange.setProperty("propertyFromDoSomething", "Hello, I am property");
exchange.getIn().setHeader("headerFromDoSomething", "Hi, I am header");
exchange.getIn().setBody("It's me, body!");
}
}
class EventStatusProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println(exchange.getIn().getHeader("headerFromDoSomething", String.class));
System.out.println(exchange.getProperty("propertyFromDoSomething", String.class));
System.out.println(exchange.getIn().getBody(String.class));
}
}
If you really need to call processor inside bean, as you are writing in title, extract processor to direct route and then invoke it with ProducerTemplate.
RouteBuilder
from("direct:log")
.process(new EventStatusProcessor());
DoSomething class
public class DoSomething {
#SuppressWarnings("unused") //called via Camel bean invocation
public void doSomething(Exchange exchange){
exchange.getContext().createProducerTemplate().sendBody("direct:log", "I am body and I will be passed to EventStatusProcessor");
}
}
I'm trying hystrix fallback method.
On localhost:8082, customer-service is running which returns name of the customer.
If the customer-service is down, fallback method should invoke. But it is not happening.
Below is the code snippet.
Please suggest.
#SpringBootApplication
#EnableDiscoveryClient
#EnableCircuitBreaker
#RestController
public class DemoHystrixApplication {
#GetMapping("/")
public String name() {
String str = getCustomerName();
return str;
}
#HystrixCommand(fallbackMethod = "getFallbackCustomerName")
private String getCustomerName() {
RestTemplate restTemplate = new RestTemplate();
URI uri = URI.create("http://localhost:8082");
return restTemplate.getForObject(uri, String.class);
}
private String getFallbackCustomerName() {
System.out.println("coming inside fallback method");
return "Resillient Customer";
}
public static void main(String[] args) {
SpringApplication.run(DemoHystrixApplication.class, args);
}
}
Both the methods i.e. the actual and fallback methods should be public and move these methods to a separate class and annotate it with #Component.
Give a try, hope this helps.
Your #HystrixCommand annotated method should be public.
Not sure about the fallback method but I would set it public as well.
This is because of AOP.
The Spring container injects aspect-aware bean when injecting a bean.
When the name() function is called at the user's request, the method of the aspect-aware bean is called so annotation works.
However, calling this.getCustomerName() directly within the name() calls getCustomerName() on the raw bean before it is wrapped in proxy. It doesn't know aspect. Therefore, annotation does not work.
You can also try stopping and starting the service, if you added the dependency of netflix-hystrix and have dev-tools to pick up changes while executing the service.
Fallback metod should be called from another bean. The problem is you are calling fallback method from RestController.
I have annotation defined as below
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface OTPFlow {
}
And class A defined as below
public abstract class A {
#OTPFlow
public ModelAndView doSomething() {
//do something and return ModelAndView
}
}
Class B is a controller defined as below
#Controller
#RequestMapping(value = {"/someurl"})
public class B extends A {
#RequestMapping(value = {"/get"}, method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView get(HttpServletRequest request, HttpServletResponse response) {
return doSomething();
}
}
Aspect is defined as
#Component
#Aspect
public class OTPAspect {
private static final Logger logger = LoggerFactory.getLogger(OTPAspect.class);
#Pointcut("#annotation(OTPFlow)")
public void OTPFlow() {}
#Around("OTPFlow()")
public Object checkOTP(ProceedingJoinPoint joinPoint) {
try {
logger.info("Inside Aspect");
return joinPoint.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
The problem is when i access "/someurl/get" url, the aspect does not execute. But when i annotate "get" method of class B, aspect executes.
So basically, annotated methods of superclass does not invoke Aspect.
What is the issue? Is there any other way to achieve this? Any help would be appreciated. Thanks
What happens when spring applies the aspect, is that spring creates proxies that wrap your controller instance to intercept calls and add the aspect behaviour before calling the instance method. This has the effect, that any call to "this" from within your controller instance is directly invoked on that instance and will not be intercepted by the wrapping proxy. Therefore, the "get" method is called on the proxy class, which in turn will call the "get" method of the controller instance, and when the latter tries to call the "doSomething" method it will not pass through the proxied "doSomething", but through the internal one.
The way to handle this situation is to apply aspects directly to the methods of your class that will be externally called, in your case directly on the "get" method instead of the "doSomething"
I want to offer an alternative to what M. Deinum and Marios have said correctly: Use AspectJ instead of Spring AOP. AspectJ does not rely on proxies, is faster, more powerful and integrates nicely with Spring as described in Spring manual, Section 9.8, Using AspectJ with Spring applications. With AspectJ what you want to do works out of the box.