Enabling CORS Sprint Boot RestController - spring

What will be the result of the following:
Is set at class level:
#CrossOrigin(origins = "https://hostname", maxAge = "3000")
And at method level, I have:
#CrossOrigin
Will the method be applied with the origin and maxAge, or will it take all the defaults from #CrossOrigin?
I understand that a mixed configuration can be applied to a method if it's annotated at class level and method level - But this set up seems backward to me

Will the method be applied with the origin and maxAge, or will it take all the defaults from #CrossOrigin?
It will use both and combine configurations from both global and local annotations. When combining non null values are taken. So your Class level annotation has values and Method level annotation has no values then Class level values will be applied.
Check CorsConfiguration.combine method for more details.

Related

Spring #RequestMapping value annotations

I want to learn that is there any difference between #RequestMapping(/home) and #RequestMapping(value="/home")
Thanks,
As per Spring , both are same. The first one is used when only one url maps to a path.
#RequestMapping("/home") will map the urls:
<hostname>:<port>/home to the class or method on which the annotation has been applied.
The second one is used when you have more urls to map to same path.
#RequestMapping(value="/home") will do the same as first one. but
#RequestMapping(value = {
"/home",
"/someotherurl",
"/moreUrl"
})
will map the following url:
<hostname>:<port>/home
<hostname>:<port>/someotherurl
<hostname>:<port>/moreUrl
to the method or class on top of which the annotation is applied.
Refer: https://dzone.com/articles/using-the-spring-requestmapping-annotation for more details.
Assuming you mean #RequestMapping("/home") not #RequestMapping(/home) then no, there is no difference.
For annotations with a property named value this is also assumed to be the default and can be passed into the annotation definition without reference to value=. However, this is only valid if you want to define a single property. Otherwise the value= is required.
e.g.:
#RequestMapping(value = "/home", method = RequestMethod.GET)

Automatically document #PathVariable annotated parameters within #ModelAttribute annotated methods

In our REST-API we need to be multi-tenant capable. For achiving this all rest controllers subclass a common REST controller which defines a request mapping prefix and exposes a model attribute as follows
#RequestMapping(path = "/{tenantKey}/api")
public class ApiController {
#ModelAttribute
public Tenant getTenant(#PathVariable("tenantKey") String tenantKey) {
return repository.findByTenantKey(tenantKey);
}
}
Derived controllers make use of the model attributes in their request mapping methods:
#RestController
public class FooController extends ApiController {
#RequestMapping(value = "/foo", method = GET)
public List<Foo> getFoo(#ApiIgnore #ModelAttribute Tenant tenant) {
return service.getFoos(tenant);
}
}
This endpoint gets well documented in the swagger-ui. I get an endpoint documented with a GET mapping for path /{tenantKey}/api/foo.
My issue is, that the {tenantKey} path variable is not documented in swagger-ui as parameter. The parameters section in swagger is not rendered at all. If I add a String parameter to controller method, annotating it with #PathVariable("tenantKey) everything is fine, but I don't want a tenantKey parameter in my controller method, since the resolved tenant is already available as model attribute.
So my question is: Is there a way do get the #PathVariable from the #ModelAttriute annotated method in ApiController documented within swagger-ui in this setup?
Project-Setup is
Spring-Boot (1.4.2)
springfox-swagger2 (2.6.1)
springfox-swagger-ui (2.6.1)
This is certainly possible. Model attributes on methods are not supported currently. Instead, you could take the following approach.
Mark the getTenant method with an #ApiIgnore (not sure if it gets treated as a request mapping.)
In your docket you can add tenantKey global path variable (to all end points). Since this is a multi-tenant app it's assuming this applies to all endpoints.

Spring Boot MVC request mapping overrides static resources

I want to have rest controller in Spring Boot to handle all requests like this: "/{arg}", EXCEPT "/sitemap.xml". How can I achieve that?
You could specify your request mapping on the controller level via regex and exclude some resources (e.g. 'excludeResourceA' and 'excludeResourceB') with:
#RestController
#RequestMapping(value = "/{arg:(?!sitemap.xml|excludeResourceA|excludeResourceB).*$}")
public class YourRestController {
// your implementation
}
Of course you can also specify the request mapping on the method level with the same regex relative to your controller path matching and you can pass the argument with #PathVariable("arg") String arg in your method signature to your method body if you need it.

how to apply user defined properties value to #RequestMapping

I have several #RequestMapping which value will subject to change from "/XXX" to "/V100" on someday. So I need to define it in properties. I've googled and there's way using application.properties but I have to keep "/XXX" value in a user defined properties like a "local.properties". Is it possible to define #RequestMapping value on a user defined properties?
#Controller
#RequestMapping("/XXX")
public class MyController {
...
}
** UPDATE : tried several hours and get it to work.
my.properties
api.version=V100
mvc-context.xml
<context:property-placeholder ignore-unresolvable="true" location="/WEB-INF/config/property/my.properties"/>
controller
#RequestMapping("/${api.version}")
tomcat log
localhost-startStop-1> [2016-04-28 15:01:35.410] [INFO] [RequestMappingHandlerMapping] [534] Mapped "{[/V100/detail],methods=[GET]}"...
In addition to the xml solution provided by #JustinB, here is an annotation-only solution (tested with Spring Boot):
#Controller
#PropertySource(value = "classpath:/user.properties", ignoreResourceNotFound = true)
#RequestMapping("/${api.version:}")
public class MyController {
...
}
The value of api.version is read from If src/main/resources/user.properties if it exists. If the file is missing or api.version is not set, it will default to an empty string.
Beware, if api.version is also defined in application.properties it will take precedence whether or not user.properties exists and api.version is set in it.
More examples of #PropertySource are provided here.

What is purpose of #ConditionalOnProperty annotation?

I just modified spring boot configuration, and encountered
#ConditionalOnProperty(prefix = "spring.social.", value = "auto-connection-views")
from org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration
#Bean(name = { "connect/twitterConnect", "connect/twitterConnected" })
#ConditionalOnProperty(prefix = "spring.social.", value = "auto-connection-views")
public View twitterConnectView() {
return new GenericConnectionStatusView("twitter", "Twitter");
}
I don't understand purpose of this annotation. I guess this might be enable to use bean only if property value exist(e.g. "spring.social", "auto-connection-views").
The annotation is used to conditionally create a Spring bean depending on the configuration of a property. In the usage you've shown in the question the bean will only be created if the spring.social.auto-connection-views property exists and it has a value other than false. This means that, for this View bean to be created, you need to set the spring.social.auto-connection-views property and it has to have a value other than false.
You can find numerous other uses of this annotation throughout the Spring Boot code base. Another example is:
#ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
public AmqpAdmin amqpAdmin(CachingConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
Note the use of matchIfMissing. In this case the AmqpAdmin bean will be created if the spring.rabbitmq.dynamic property exists and has a value other than false or the property doesn't exist at all. This makes the creation of the bean opt-out rather than the example in the question which is opt-in.
In case you are using this property on TYPE-level, i.e. on one of your #Configuration classes... Keep in mind that in such case the annotation is evaluated/checked against the default properties file, i.e. application.properties
#ConditionalOnProperty on TYPE level w/ #Configuration
Rather, it is the opposite. A precondition for implementing the method, if the property is set in the environment (development, approval, production) and is true value with the method can be executed.
If the property is not set in the environment annotation not prevented the execution of the method.

Resources