Spring AOP - method aspect is not invoked - spring

Sorry: Google Traductor (english basic)
Interface implemented by aspect:
public interface MinReader {
void interceptThoughts();
}
MinReader class that implements the interface, which contains the "Aspect"
#Aspect
public class Magician implements MinReader {
#Pointcut("within(paquetea.paqueteb.*)")
public void thinking() {
}
#Override
#Before("thinking()")
public void interceptThoughts() {
// Codigo
}
}
This is a part of my JavaConfig:
#Configuration
#EnableAspectJAutoProxy
public class SpringIdolConfig {
#Bean
public MinReader magician() {
return new Magician();
}
// Otros bean
}
the problem is that the "interceptThoughts" method is never invoked.
My "solution" is to change the return type of method "magician" in my JavaConfig:
"MinReader" -> "Magician"
#Bean
public Magician magician() {
return new Magician();
}
Why is that?
Is there any way to use "MinReader" instead of "Magician"?
UPDATE: these are the other beans:
package paquetea.paqueteb;
public interface Thinker {
void thinkOfSomething(String thoughts);
}
package paquetea.paqueteb;
public class Volunteer implements Thinker {
#Override
public void thinkOfSomething(String thoughts) {
//code
}
}
This is my full javaconfig:
#Configuration
#EnableAspectJAutoProxy
public class SpringIdolConfig {
#Bean
public MinReader magician() {
return new Magician();
}
#Bean
public Thinker volunteer() {
return new Volunteer();
}
}

I'm guessing a bit, but I think one of your problems is that you've got the pointcut expression wrong. If I've read the examples in here right, you should use:
#Pointcut("within(paquetea.paqueteb..*)")
Note the ..*, and not the .* that you had. I find that when I get pointcuts wrong, they can be very difficult to debug, as their normal way of failing is to just silently not attach to anything. (My preferred technique is to attach to methods annotated with a custom annotation; that makes it easy to control what's happening and easy to debug.)

Related

Spring boot 2.0 custom converter being ignored

I've either completely miss-understood converters, or all the examples/blogs/docs I've found are assuming I've done a step... My understanding is that when I post a String, the converter will pick it up and give the Controller a POJO instead.
The problem I have is the converter is never being called.
The payload coming into the controller is a standard JSON API string
{
"data":{
"attributes":{
"created-date":null,
},
"type":"steaks"
}
}
The converter:
#Slf4j
#Configuration
public class SteakConverter implements Converter<String, Steak> {
#Override
public Steak convert(String value) {
log.info("converter value {}", value);
return new Steak.builder().build();
}
}
The controller:
#Slf4j
#CrossOrigin
#RestController
public class SteakController {
#PostMapping("/steaks")
public ResponseEntity<String> create(#RequestBody Steak steak) {
}
}
From reading all the blogs and docs I can find this should be all that's needed. However I've also tried manually registering with the following:
#Slf4j
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addFormatters(FormatterRegistry registry) {
log.info("Converter registered");
registry.addConverter(new SteakConverter());
}
}
This is called during application startup.
The only thing I can think of is that the converter/controller doesn't think the payload is in fact a String, so is ignoring it?
How can I debug this, or just make it work?
Here is a working sample application that shows my problem.
Cheers

Custom AbstractEndpoint listening to "/" (root)

I've implemented a starter that configures Swagger the way I like. In addition, I'd like to redirect every call to the app's root URL (e.g. localhost:8080) to /swagger-ui.html.
Therefore, I added an own AbstractEndpoint which is instantiated in the #Configuration class as follows:
#Configuration
#Profile("swagger")
#EnableSwagger2
public class SwaggerConfig {
...
#Bean
public RootEndpoint rootEndpoint() {
return new RootEndpoint();
}
#Bean
#ConditionalOnBean(RootEndpoint.class)
#ConditionalOnEnabledEndpoint("root")
public RootMvcEndpoint rootMvcEndpoint(RootEndpoint rootEndpoint) {
return new RootMvcEndpoint(rootEndpoint);
}
}
The respective classes look like this:
public class RootEndpoint extends AbstractEndpoint<String> {
public RootEndpoint() {
super("root");
}
#Override
public String invoke() {
return ""; // real calls shall be handled by RootMvcEndpoint
}
}
and
public class RootMvcEndpoint extends EndpointMvcAdapter {
public RootMvcEndpoint(RootEndpoint delegate) {
super(delegate);
}
#RequestMapping(method = {RequestMethod.GET}, produces = { "*/*" })
public void redirect(HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.sendRedirect("/swagger-ui.html");
}
}
As stated in public RootEndpoint(), the custom Endpoint is bound to /root. Unfortunately, I can't specify super(""); or super("/"); as those values throw an exception (Id must only contains letters, numbers and '_').
How can I achieve having a custom Endpoint listening to the root URL in a starter using #Configuration files to instantiate beans?
I solved it with an easier approach by adding a WebMvcConfigurerAdapter bean in the #Configuration:
#Bean
public WebMvcConfigurerAdapter redirectToSwagger() {
return new WebMvcConfigurerAdapter() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("").setViewName("redirect:/swagger-ui.html");
}
};
}

Spring 4 with caching and generic type autowiring

I'm using the latest version of Spring and I'm getting startup errors when I attempt to inject the same generic type twice and the generic type's implementation uses caching.
Below is the simplest example I can create to duplicate the error.
// build.gradle dependencies
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-web'
}
// MyApplication.java
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
// HomeController.java
#RestController
#RequestMapping(value = "/home")
public class HomeController {
#Autowired
public HomeController(
GenericService<String> s1,
GenericService<String> s2, // <-- Notice GenericService<String> twice
GenericService<Integer> s3
) {}
}
// GenericService.java
public interface GenericService<T> {
public T aMethod();
}
// IntegerService.java
#Service
public class IntegerService implements GenericService<Integer> {
#Override
#Cacheable("IntegerMethod")
public Integer aMethod() {
return null;
}
}
// StringService.java
#Service
public class StringService implements GenericService<String> {
#Override
#Cacheable("StringMethod")
public String aMethod() {
return null;
}
}
This compiles fine, but when I run the application, I get the following error:
No qualifying bean of type [demo.GenericService] is defined: expected single matching bean but found 2: integerService,stringService
I have not tried using qualifiers yet, but I'm guessing that would be a work-around. I will try it after posting this. Ideally, I'd like the autowiring of generics and caching to integrate out-of-box. Am I doing something wrong, or is there anything I can do to get it working?
Thank you!
If you would like to not have to use the #Qualifier in the constructor and still use the interfaces, you could just add a value to the service declarations.
#Service(value = "integerService")
public class IntegerService implements GenericService<Integer> {
#Override
#Cacheable("IntegerMethod")
public Integer aMethod() {
return 42;
}
}
#Service(value = "stringService")
public class StringService implements GenericService<String> {
#Override
#Cacheable("StringMethod")
public Integer aMethod() {
return 42;
}
}
Just to be sure, I created a project with Spring-Boot, compiled and ran it. So the above should work. It's basically the same as what you're already doing, but with less typing.
My previous answer (before modifying) was to do something like this:
// HomeController.java
#RestController
#RequestMapping(value = "/home")
public class HomeController {
#Autowired
public HomeController(
StringService s1,
StringService s2,
IntegerService s3
) {}
}
But you would have to not implement the interfaces to make this work.

#Specializes in Spring

CDI has the feature of Specialization, and I'm looking for that in the Spring world.
Details.
In CDI, the #Specializes annotation allows one to change the behaviour of a bean just by overriding it. This is completely transparent to users of that bean, e.g. if we'd have
public class OneBean {
public String whoAmI() { return "OneBean"; }
}
#Specializes
public class AnotherBean extends OneBean {
#Override
public String whoAmI() { return "AnotherBean"; }
}
we could
public class SomewhereElse {
#Inject
OneBean oneBean; // we know nothing of AnotherBean here!
public void guessWhosThere() {
return oneBean.whoAmI(); // yet it returns "AnotherBean"
}
}
This gets really useful as soon as OneBean is actually used with and without AnotherBean. For example, if OneBean is in one.jar and AnotherBean is in another.jar, we can change the bean's behaviour just by reconfiguring the classpath.
Question. Does something like Specialization also exist in Spring?
I could only find the #Primary annotation, which however has a different semantics: #Primary does not replace one bean, but only marks one of multiple alternatives as the primary one. Especially, as I understood, I could not build a deep inheritance hierarchy as it's possible with #Specializes.
Short answer
In Spring 4, this is not possible. Period. Still, in 2016, nothing like this is possible with Spring's obsolete dependency injection model.
Seems like there is no similar annotation in spring, but you can achive it via #Qualifier.
Beans:
#Resource("oneBean")
public class OneBean {
public String whoAmI() { return "OneBean"; }
}
#Resource("anotherBean")
public class AnotherBean extends OneBean {
#Override
public String whoAmI() { return "AnotherBean"; }
}
SomewhereElse:
public class SomewhereElse {
#Autowired
#Qualifier("anotherBean")
OneBean oneBean;
public void guessWhosThere() {
return oneBean.whoAmI(); // returns "AnotherBean"
}
}
Edited.
Also you can develop your own annotation and use it in BeanPostProcessor, look at spring docs here
OR even better to use CustomAutowireConfigurer, see here
With Spring boot, you could probably get a similar result by leveraging its auto-configure mechanism, e.g. with a bean condition such as #ConditionalOnMissingBean:
public class OneBean {
public String whoAmI() { return "OneBean"; }
}
#Configuration
public class OneConfiguration {
#Bean
#ConditionalOnMissingBean
public OneBean getBean() { return new OneBean(); }
}
#Component
public class AnotherBean extends OneBean {
#Override
public String whoAmI() { return "AnotherBean"; }
}
However, you would have to make sure that all configurations are built accordingly if you don't know for sure which ones will be specialized:
public class OneBean {
public String whoAmI() { return "OneBean"; }
}
public class AnotherBean extends OneBean {
#Override
public String whoAmI() { return "AnotherBean"; }
}
public class YetAnotherBean extends AnotherBean {
#Override
public String whoAmI() { return "YetAnotherBean"; }
}
#Configuration
public class OneConfiguration {
#Bean
#ConditionalOnMissingBean
public OneBean getBean() { return new OneBean(); }
}
#Configuration
public class AnotherConfiguration {
#Bean
#ConditionalOnMissingBean
public AnotherBean getBean() { return new AnotherBean(); }
}
#Configuration
public class YetAnotherConfiguration {
#Bean
#ConditionalOnMissingBean
public YetAnotherBean getBean() { return new YetAnotherBean(); }
}
// and so on...

Spring AOP - advise super class method not overridden in subclass

public abstract class AService<T> {
public T needsToBeAdvised(T param) {
T result = doSomething(param);
return result;
}
}
#Service
public class BService extends AService<B> {
#Override
public T needsToBeAdvised(T param) {
return super.needsToBeAdvised(param);
}
}
#Service
public class CService extends AService<C> {}
// (B & C implement an interface AType)
#Component
#Aspect
public class MyAspect {
#Pointcut("execution(* package.AService+.needsToBeAdvised(*))")
private void aNeedToBeAdvised() {}
#AfterReturning(pointcut="aNeedToBeAdvised()", returning="param")
public void interceptNeedsToBeAdvised(JoinPoint joinPoint, AType param) {
// some action
}
}
Given this setup:
bService.needsToBeAdvised(bParam) //is intercepted
but,
cService.needsToBeAdvised(cParam) //is NOT.
How do I achieve this without overriding needsToBeAdvised() in CService?
EDIT:
I should add that BService and CService are both in the same package.
If I change my point-cut to the following:
#Pointcut("execution(* package.CService.needsToBeAdvised(*))")
cService.needsToBeAdvised(cParam) //is still not intercepted
The only way it works is if I override needsTobeAdvised() in CService
Are all services in the same package? Given from your example code, I suspect AService and BService to be in the package package, but CService to be in another package. If services indeed are in different packages, you have some options:
Move so that they are in the same package
Change you pointcut to be more generic, e.g. "execution(* *.A+.needsToBeAdvised(*))
Add more pointcuts

Resources