Java bean validation on Spring MVC Controller PathVariables - spring

I am trying to get Java Bean validation annotations to work with path variables and query parameters in Spring MVC controller. (Environment: Spring Boot v1.3.5, Springxxx 4.2.6, programming language Kotlin 1.0.3)
e.g.
#RequestMapping(value = "/{someId}" ...)
fun getSomething(**#SomeValidId** #PathVariable("someId") someId: String):...
I have added org.springframework.validation.beanvalidation.MethodValidationPostProcessor as described in https://raymondhlee.wordpress.com/2015/08/29/validating-spring-mvc-request-mapping-method-parameters/ and also added org.springframework.validation.beanvalidation.LocalValidatorFactoryBean as the validatorFactory to the above.
#Configuration
...class .... {
...
#Bean
open fun localValidatorFactoryBean() = LocalValidatorFactoryBean()
#Bean
open fun methodValidationPostProcessor() : MethodValidationPostProcessor {
val methodValidationPostProcessor = MethodValidationPostProcessor()
methodValidationPostProcessor.setValidator(localValidatorFactoryBean())
return methodValidationPostProcessor
}
}
But when I annotate the Controller class (or the interface it implements) with
org.springframework.validation.annotation.Validated as suggested looks like the controller class is proxied (which seems to be as expected - https://github.com/spring-projects/spring-security/issues/3215).
#Validated
interface SomeResource {
....
#RestController
#RequestMapping("/somepath")
class SomeController ......: SomeResource ....
But this causes the Spring mvc request mapping setup to ignore the SomeController. Debugging through the Spring framework code looked like org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods() goes through the list of beans and tries to detect handler methods but the above controller is ignored by the looks of it as it encounters a proxy instance and it doesn't carry the #Controller or #RequestMapping annotations.
Does anyone have any idea what's missing? There seems to be a lot of information out there that seem to suggest this should be possible, but couldn't find a working example .

Well I found the issue - it was because the proxy created for the controller was a JDK Dynamic proxy. When I forced it to be a CGLIB proxy it started working alright.
By default Kotlin classes are final and therefore forced to use JDK Dynamic proxies, but marking the controller as 'open' was not sufficient to coerce it to use CGLIB. Had to add #Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) to the controller class
#RestController
#RequestMapping("/somepath")
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class SomeController ......: SomeResource ....

Related

(De-)Serializing Spring Boot ConfigurationProperties with Jackson

My spring Boot application uses a class annotated with #Configuration and #ConfigurationProperties:
#Configuration
#ConfigurationProperties(prefix = "my")
#Getter
#Setter
public class MyConfigurationProperties {
#Value("${timeout}")
private int defaultTimeout;
}
Now I'd like to read and update these configuration properties using a (private) REST interface, so I created the following controller.
#RestController
#RequestMapping(path = "config")
public class ConfigController {
final MyConfigurationProperties myConfig;
public ConfigController(MyConfigurationProperties myConfig) {
this.myConfig = myConfig;
}
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MyConfigurationProperties> get() {
return ResponseEntity.ok(myConfig);
}
}
Unfortunately this doesn't seem to work as I get the following exception when calling the endpoint:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.context.expression.StandardBeanExpressionResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
The JSON response even contains "strange" properties when disabling FAIL_ON_EMPTY_BEANS:
How would I be able to (de-)serialize this configuration class using Jackson?
When removing the annotations #Configuration and #ConfigurationProperties for testing purposes, the serialization works just fine. So it seems to have to do something with the class being a bean?
You are mixing things: configuration properties and autowiring a value. If you want to have a POJO as a configuration property class, drop the #Value annotation. You can also drop #Configuration annotation if you add #EnableConfigurationProperties to your main class (this way all #ConfigurationProperties classes will be automatically detected). If a problem persists, please update the question and show us how the properties prefixed with 'my' look like.

#Service/#Controller annotations creates a new bean without using #Bean annotation

I have a class which I have annotated with #Service #Scope
#Slf4j
#Service
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ProductDataModel {
#Value("${message}")
private String message;
The above code seems to be creating a bean for ProductDataModel, without using the #Bean annotation.
I am using #Autowired ProductDataModel productDataModel in my code, and the dependency productDataModel is not null, when used with above piece of Code.
How come the above code is creating bean ??
Ideally, I would have expected bean to created only when I use the below code
//I am not using this piece of code in my program., for reference only
#Configuration
public class OSCConfig {
#Bean
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
ProductDataModel productDataModel(){
return new ProductDataModel();
}
Can someone explain the difference between 2 pieces of code and when to use which one.
As #M. Deinum pointed out that we don't need to specify #Bean for each class when we declare #Service or #Controller annotation they are picked up by Spring Container if component-scanning is enabled for that package.
So good use case for using #Bean could be that
If the Class is in third party jar and you can not add #Service/#Controller annotations
If you want to add some custom logic inside the #Bean annotate methods
The #Service annotation is picked up by Spring when scanning for objects to create (as part of a package scan). It is an specialisation of the spring #Component annotation, but doesn't really add much other than providing an indication to users about its intended purpose. The #Controlller annotation is similar, but the bean created has specific characteristics.
The #Bean annotation as you have used it is also used when creating objects, and in this context it is on a method in a Configuration class, therefore the bean created is of the type returned by the method.

Spring #Component & #Bean annotation

I believe #Configuration annotation when used in conjunction with #Bean annotation in spring is used to replace xml configuration. However I saw a piece of code where #Bean was used in conjunction with #Component (defined at class level). Is this a valid declaration? Are there any any pros / cons in using #Component with #Bean annotation vs using #Configuration and #Bean.
EDIT:
Thanks #Sundar & #Biju. I did programmatic call between 2 bean methods under Component class. I saw different object values. However when I used Configuration , I saw the same bean values. Based on what you had explained , I assume a regular method call was made when I used #Component , whereas when I used #Configuration , I assume method annotated with #Bean was treated as a Spring Bean
Code
#Component
public class AppConfig {
#Bean(name="customerService")
public CustomerService getCustomerService(){
System.out.println(getService());
System.out.println(getService());
return getService();
}
#Bean
public CustomerService getService(){
return new CustomerServiceImpl();
}
}
Console Output
com.company.service.CustomerServiceImpl#68bbe345
com.company.service.CustomerServiceImpl#30b8a058
Code
#Configuration
public class AppConfig {
#Bean(name="customerService")
public CustomerService getCustomerService(){
System.out.println(getService());
System.out.println(getService());
return getService();
}
#Bean
public CustomerService getService(){
return new CustomerServiceImpl();
}
}
Console Output
com.company.service.CustomerServiceImpl#71623278
com.company.service.CustomerServiceImpl#71623278
It is a valid declaration, however there are catches - the one within a #Component is referred to as a lite-mode and dependencies cannot easily be injected for beans declared in this form. The recommendation is always to use #Bean in a #Configuration annotated class - here is a good reference on this - http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-java-basic-concepts
You can use #Component as an alternative for #Configuration. It’s official suggestion from spring team.
Simply declare your #Bean methods on classes not annotated with #Configuration (but typically with another Spring stereotype instead, e.g. #Component). As long as you don’t do programmatic calls between your #Bean methods, this is going to work just as fine, but conditions apply*.
Please refer more info in this link.
http://dimafeng.com/2015/08/29/spring-configuration_vs_component/

Spring can not register spring hateoas resource assembler

I am using spring hateoas in spring and got the problem is spring could not instance hateoas resource assembler , here is my snippet code:
UserHateoasResourceAssembler.java:
#Service
public class UserHateoasResourceAssembler extends ResourceAssemblerSupport<UserDTO, UserHateoasResource> {
public UserHateoasResourceAssembler() {
super(UserController.class, UserHateoasResource.class);
}
#Override
public UserHateoasResource toResource(UserDTO entity) {
UserHateoasResource resource = createResourceWithId(entity.getId(), entity);
return resource;
}
#Override
protected UserHateoasResource instantiateResource(UserDTO entity) {
return new UserHateoasResource(entity);
}
}
UserController.java:
#RestController
#RequestMapping("/api/")
public class UserController {
#Inject
private UserHateoasResourceAssembler userAssembler ;
....
}
The exception was thrown is "No qualifying bean of type [UserHateoasResourceAssembler] found for dependency. I know this root cause is can not create instance of assembler.
I tried to use #Service or #Component but both does not work. I also tried to use #Autowire instead, but did not work too. I have to fix that by adding #Scope( proxyMode = ScopedProxyMode.TARGET_CLASS). But I wonder if there is any another solution to resolve it instead of using #Scope ?
Thanks.
I found the elegant solution. Due to my application using generated code and it used #EnableAspectJAutoProxy, this annotation default set auto-proxy = false and using JDK proxy, so almost the instance of class that implementing an interface was not allowed. We have to #inject the interface instead. So to inject the implementation class, have 2 options here:
Set #EnableAspectJAutoProxy(proxyTargetClass = true )
Remove this annotation if we does not really need that.

how to use #Service annotation in Spring MVC to create the bean of Service layer

Can someone tell how to get the bean of service layer in spring MVC. One way to get the bean of service layer is by using #Service annotation but how to do that, I don't know.
Controller:
#Controller
public class ConfigureApplicationController {
#RequestMapping(value="/ConfigureApplication.html", method=RequestMethod.GET)
public ModelAndView getListOfAllConfigureApplication(){
AppConfigureServiceImpl getService=new AppConfigureServiceImpl();
ArrayList<ConfigureApplication> results =getService.getListOfAllAppConfigure();
ModelAndView model=new ModelAndView("ConfigureApplication");
model.addObject("results",results);
return model;
}
and serviceImpl is:
#Service("appConfigureServiceImpl")
public class AppConfigureServiceImpl implements AppConfigureService {
public ArrayList<ConfigureApplication> getListOfAllAppConfigure(){
#SuppressWarnings("resource")
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring-dispatcher-servlet.xml");
AppConfigureDAOImpl getAll=ctx.getBean("appConfigureDAOImpl", AppConfigureDAOImpl.class);
ArrayList<ConfigureApplication> results =getAll.getList();
return results;
}
In this i have made the object of AppConfigureServiceImpl (in service layer)then i invoke the method but by doing so i am not using dependency injection in spring. I know i can do this using #Service annotation but i don';t know the syntax. can someone help me to solve this problem.
put a plain #Service annotation over your AppConfigureServiceImpl (you don't have to specify the "appConfigureServiceImpl" like you did).
Then have the service instance injected automatically in your controller by adding the following inside ConfigureApplicationController class:
#Autowired
AppConfigureService appConfigureService;
Now you can just call it like this: appConfigureService.getListOfAllAppConfigure();
Note that for the injection to happen, you need to make sure that you have set componentScan property in your configuration file to scan the packages that contain the classes to be injected. In your case, the package that contains AppConfigureServiceImpl.
<context:component-scan base-package="com.my.servicepackage" />
Note also that you should do the same with your dao instead of creating a new application context and getting it from the there. I.e. add a
#Autowired
AppConfigureDAO appConfigureDAO;
property inside your AppConfigureServiceImpl and use that.

Resources