pom.xml version info:
springfox-swagger2: 2.5.0
swagger-core: 1.5.10
springfox-swagger-ui: 2.6.1
springboot: 1.5.3
I has a project with swagger2 and springboot.
The project code without #Aspect works very well.The code reads as follows.
public interface TestApi {
WfExecution test(Long temp);
}
#Api(value = "TestAPI")
#RequestMapping(value = "/test")
#RestController
public class TestApiImpl implements TestApi {
#Override
#RequestMapping(value = "/test")
#ApiOperation(value = "", notes = "", produces = MediaType.APPLICATION_JSON)
public WfExecution test(#ApiParam(value = "", required = true) #RequestParam(required = true, value = "temp")
Long temp) {
return new WfExecution();
}
}
the right result:
But when I add the follow code, the swagger-ui doesn't show the test-api-impl.
#Aspect
#Component
public class LoggerAop {
#Before("execution(* com.XXX.controller.impl.TestApiImpl.*(..))")
public void doBeforeAdvice(JoinPoint joinPoint){
System.out.println("XXX");
}
}
the error result:
Is there a conflict between swagger and spring AOP?
#egg
I setup the similar project and faced a same issue.
After setting the proxyTargetClass property to true in #EnableAspectJAutoProxy annotation as below, the issue got resolved.
#EnableAspectJAutoProxy(proxyTargetClass=true)
This issue occurs only when we are using the interface for controller.
To quote the use of this property EnableAspectJAutoProxy from Java doc.
Users can control the type of proxy that gets created for {#code FooService} using
the {#link #proxyTargetClass()} attribute. The following enables CGLIB-style 'subclass'
proxies as opposed to the default interface-based JDK proxy approach.
This answer is for those who is still facing the issue
#Aspect is basically a filter. If you exclude the swagges resources it will start working.
you can use
#Pointcut("within(com..*..*Controller)")
#Pointcut("within(com..*..*Service)")
so it will scan only those pacakges which is starting from com...
Related
In my controller I currently added the following annotation #CrossOrigin:
#RestController
#RequestMapping(value = "/dev/test")
#CrossOrigin
public class MyController {
...
}
And also wondering the following implementation in WebConfig:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
private String allowedRequest = "/**";
private String allowedOrigins = "*";
private String[] allowedMethods = {"GET", "POST", "DELETE", "OPTIONS"};
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping(allowedRequest).allowedOrigins(allowedOrigins)
.allowedMethods(allowedMethods);
}
}
Are those two options provide the same result? And are there any difference from security standpoint (which one is more secure than the other)?
Thank you!
WebMvcConfigurer#addCorsMappings(CorsRegistry) creates a global CORS configuration applied to all controllers, and #CrossOrigin allows for a more fine-grained control over it. For the case when they are used together, as stated in the javadoc of #CrossOrigin:
The rules for combining global and local configuration are generally additive -- e.g. all global and all local origins. For those attributes where only a single value can be accepted such as allowCredentials and maxAge, the local overrides the global value.
I'm trying to create a custom annotation for enabling functionality based on feature flags. I'm basing my approach on the ConditionalOnProperty annotation, but to enable code reuse I want to define a common prefix that can be used wherever I need this functionality.
I have defined my annotation as below.
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
#Documented
#ConditionalOnProperty(prefix = "foo.bar")
public #interface ConditionalOnFeature {
#AliasFor(annotation = ConditionalOnProperty.class, attribute = "value")
String[] value();
}
I'm using the AliasFor annotation to set the value attribute in the ConditionalOnProperty annotation, and hardcoding my prefix as foo.bar (all my features will sit under this property). As far as I understand Spring annotation overriding, this should work.
However when I use this on a class (for example a controller), the code fails to compile, stating that The name or value attribute of #ConditionalOnProperty must be specified.
#RestController
#ConditionalOnFeature("enable-fancy-controller")
public class FancyController {
#RequestMapping(value = "/fancy-method", method = RequestMethod.GET)
public String fancyMethod() {
return "Fancy";
}
}
However it works perfectly fine when I instead use my annotation on a method. Compiles successfully and behaves as intended.
#RestController
public class FancierController {
#ConditionalOnFeature("enable-fancier-method")
#RequestMapping(value = "/fancier-method", method = RequestMethod.GET)
public String fancierMethod() {
return "Fancier";
}
}
Have I configured my annotation wrong? Or is this some bug with Spring?
I'm trying to implement an OGC API - Features service using Spring Boot. The specification includes links to self, parent collections and such, so I figured Spring HATEOAS could help with that. Unfortunately, I'm having trouble with the bbox-crs parameter.
An example demonstration:
#RestController
public class DemoController {
#GetMapping(path = "/link", produces = "application/geo+json")
public Link getLink(#RequestParam(required = false, name = "bbox-crs") String bboxCrs) {
return linkTo(methodOn(DemoController.class).getLink(bboxCrs))
.withSelfRel()
.expand()
.withType("application/geo+json");
}
}
Test:
#SpringBootTest
#AutoConfigureMockMvc
class DemoApplicationTests {
#Autowired
private MockMvc mockMvc;
#Test
public void getLinkWithParam() throws Exception {
String expectedJson = new ObjectMapper().writeValueAsString(
new Link("http://localhost/link?bbox-crs=hello").withType("application/geo+json"));
mockMvc.perform(get("/link?bbox-crs=hello"))
.andExpect(content().contentType("application/geo+json"))
.andExpect(content().json(expectedJson));
}
#Test
public void getLinkNoParam() throws Exception {
String expectedJson = new ObjectMapper().writeValueAsString(
new Link("http://localhost/link").withType("application/geo+json"));
mockMvc.perform(get("/link"))
.andExpect(content().contentType("application/geo+json"))
.andExpect(content().json(expectedJson));
}
}
The first test succeeds, but the second test fails with the error Illegal character in path at index 23: http://localhost/link{?bbox-crs}.
According to issue #799, this is working as intended, as the URI Template spec does not allow for hyphens in variable names. I'm trying to build an URI, though, not an URI Template. Is there some way to
achieve what I'm after? Maybe by configuring Spring or by creating the link in a different way?
I'm starting to learn Spring Boot, and I'm following a tutorial on youtube. However, there is an weird thing happening on my project. I just created a Controller called GreetingController. Below is the complete code of the class
#RestController
#EnableAutoConfiguration
public class GreetingController {
private static BigInteger nextId;
private static Map<BigInteger, Greeting> greetingMap;
private static Greeting save(Greeting greeting) {
if (greetingMap == null) {
greetingMap = new HashMap<BigInteger, Greeting>();
nextId = BigInteger.ONE;
}
greeting.setId(nextId);
nextId = nextId.add(BigInteger.ONE);
greetingMap.put(greeting.getId(), greeting);
return greeting;
}
static {
Greeting g1 = new Greeting();
g1.setText("Hello World");
save(g1);
Greeting g2 = new Greeting();
g2.setText("Hola Mundo");
save(g2);
}
#RequestMapping(value = "/api/greetings", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Greeting>> getGreetings() {
Collection<Greeting> greetings = greetingMap.values();
return new ResponseEntity<Collection<Greeting>>(greetings,
HttpStatus.OK);
}
}
The controller is under the following package:
However, when I bootstrap the application with the URL http://localhost:8080/api/greetings the following error appears on my page:
But, when I put the GreetingController in the same package of Application class, as the image below:
And then get the same URL http://localhost:8080/api/greetings, I got the right response:
Can anyone explain me why?
Rename your com.example package to org.example. Spring boot scans for controllers all subpackages of package of class when you place your #SpringBootApplication annotation.
Or put #ComponentScan("org.example") on the same class. This way you tell spring boot where to search your controllers (and other beans).
If you want to support having a controller in another package, you need to include it in the component scan of your Application.
In Application.java, you could add the following:
#ComponentScan({com.example, org.example})
By default, the package that Application is in will be included in the ComponentScan, which is why it was working for you when you had the controller in the same package as Application.
Also, you don't need the #EnableAutoConfiguration annotation on your controller, FYI.
Both 'aop:aspectj-autoproxy' and 'mvc:annotation-driven' are present in the XML config.
Both of these classes are defined as a bean inside of the same XML.
Using Spring 3.2.3.RELEASE and Google App Engine 1.8.1 in a local/dev environment.
My pointcut does not execute.
My advice. Declared inside a class annotated with #Aspect.
#Component
#Aspect
public class RequestLimiter {
private MemcacheService cache = MemcacheServiceFactory.getMemcacheService();
#Pointcut("within(#pcs.annotations.LimitRequests com.zdware.pcs.controllers.PingCollectorController)")
public void methodRequestLimited(){}
#Around("methodRequestLimited() && args(req,limitRequests)")
public Object requestGateWay(ProceedingJoinPoint jp, HttpServletRequest req,LimitRequests limitRequests) throws Throwable {
// do stuff
}
}
The method I am using to test in the controller layer.
#Controller
public class PingCollectorController {
#RequestMapping(value="/test")
#LimitRequests(requestTimeLimit = 1, functionName = "Test")
public String test(){
return "test"; // this will return me to a jsp that doesnt exist, but my advice is still not executing.
}
}
Is CGLIB in the classpath? It will be needed to generate the proxy (since your controller does not implement an interface, spring cannot use a simpler JDK proxy).