Consider the two frameworks shown below. Here I need to validate the bean
Controller
In controller I m using #Valid and does the java validation. Works fine
#RequestMapping("")
void testIt(#Valid #RequestBody User user){
}
Normal Spring application without controller
Is there any way to do validation here. Its not a controller and #Valid doesn't work here.
Anyways to use #Valid or any similar type of validation for normal function?
void testIt(#Valid User user){
}
You can enable method validation by declaring beans of type org.springframework.validation.beanvalidation.MethodValidationPostProcessor and org.springframework.validation.beanvalidation.LocalValidatorFactoryBean and annotating the class containing testIt() with the #Validated annotation.
#Validated
#Component
public class TestIt {
public void testIt(#Valid User user) {
...
}
}
ConstraintViolationException will be thrown if validation errors occur when calling testIt(). Also, make sure you have Hibernate Validator in your classpath.
Related
I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure
With the following validation setup in an annotated MVC controller:
#RestController
#RequestMapping("/users")
#Validated // <-- without this, the #Size annotation in setPassword() has no effect
public class UserController {
#PutMapping("/{id}/password")
public void setPassword(#PathVariable long id, #RequestBody #Size(min = 8) String password) {
/* ... */
}
#PutMapping("/{id}/other")
public void setOther(#PathVariable long id, #RequestBody #Valid MyFormObject form) {
/* ... */
}
}
#Validated on the controller is required for the method parameter since it's not a "complex" object. In comparison, the #Valid annotation on the setOther method works without the #Validated annotation.
Why is #Validated required? Why not enable it by default? Is there a cost to its use?
edit
Note that Difference between #Valid and #Validated in Spring is related (I read it before asking this), but it doesn't address the why in my question.
Validation of objects is done by Hibernate Validator using the annotations from Jakarta Bean Validation 2.0. Something needs to trigger hibernate validator to run.
SpringMVC calls the controller methods when it sees a parameter with #Valid it will pass that object to hibernate validator. Hibernate validator will
Examine the class of the object to figure out what validation rules have been put on the class fields
Execute the validation rules against the fields marked up with validation annotations.
So in this case
#PutMapping("/{id}/other")
public void setOther(#PathVariable long id, #RequestBody #Valid MyFormObject form) {
/* ... */
}
MyFormObject has annotations on it that the hibernate validator can find to validate the object.
In this case
#PutMapping("/{id}/password")
public void setPassword(#PathVariable long id, #RequestBody #Size(min = 8) String password) {
/* ... */
}
java.lang.String does not have any annotations defined on it for hibernate validator to discover.
#Valid comes from the Bean validation package javax.validation.Valid while #Validated comes from Spring org.springframework.validation.annotation.Validated
#Validated annotation activates the Spring Validation AOP interceptor and it will examine method parameters to see if they have any validation annotations on them, if they do then Spring will call hibernate validator with each specific annotation for example #Size(min = 8) String password means call hibernate size validator and pass the value of the parameter password in this case hibernate validator does not need to scan java.lang.String to see if it has validation annotations on it. #Validated works on any spring #Component you can use it on #Service classes for example.
There is extra overhead for using #Validated similar to using #Transactional so that is why you have to opt into it. In the case of javax.validation.Valid Spring MVC needs to check the annotations on the controller method parameters so when it sees #Valid it is easy for it to send that object the Hibernate Validator without needing to add an AOP interceptor.
If I have a Spring webapp, with an endpoint like so:
#Autowired
UnpublishedStuffFactory unpublishedStuffFactory;
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
#ResponseBody
public OutputStuff update(#RequestBody Stuff stuff, #PathVariable String id) {
UnpublishedStuff uStuff = unpublishedStuffFactory.get(stuff);
//handle the request
}
UnpublishedStuffFactory.java:
#Component
public class UnpublishedStuffFactory {
#Autowired
//some autowired beans
public UnpublishedStuff get(Stuff stuff) {
return new UnpublishedStuff(stuff, /*some autowired beans*/);
}
}
So Stuff is my domain object (simple POJO). OutputStuff is something I generate (some metadata etc) and return if update was ok.
It all works fine, however I would like spring to automatically execute this factory method when request comes in, and inject UnpublishedStuff to the update method, instead of injecting Stuff.
Basically UnpublishedStuff is kind of a decorator around Stuff that adds functionality via other autowired beans (from the factory) to validate, publish etc to Stuff (I do not want this functionality in Stuff, I want it to stay a basic POJO, hence the decorator).
Is there a way to do this? Or maybe there is a better approach to this stuff?
Thanks for help :)
I am trying to implement the registration controller for a Rest API. I have read about where to place #Transactional quite a bit. (Not at DAO level but at the services maybe orchestrated). In my use case I want not only services but also a hibernate validation to use the same transaction.
This is the code of the controller:
#Autowired
private UserService userService;
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
#Transactional
public DefaultResponse register(#Valid RegisterIO registerIO, BindingResult errors) {
DefaultResponse result = new DefaultResponse();
if (errors.hasErrors()) {
result.addErrors(errors);
} else {
userService.register(registerIO);
}
return result;
}
I have written an custom contraint annotation, which validates an attribute of the parameter registerIO. Both, this validator and userService.register(registerIO); access the database (check if the email address is already in use).
Therefore I want both methods use the same Hibernate session and transaction.
This approach results in the following exception:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
The problem is the #Transactional annotation. When I place this annotation at the methods witch call the database everything works find but two transactions are startet. I suspect that when i place it at the register Method the hibernate validation is performed before #Transactional starts the transaction for this method.
I developed the following functional workaround but I am not happy with it. This codes does not use the #Valid annotation but calls the validator by itself:
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
#Transactional
public DefaultResponse register( RegisterIO registerIO, BindingResult errors) {
DefaultResponse result = new DefaultResponse();
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();
Set<ConstraintViolation<RegisterIO>> valResult = validator.validate(registerIO);
I try to summarise my question:
Using Spring MVC and Hibernate-Validation together with #Valid and #Transactional, how is it possible to encapsulate the whole request into one transaction?
Thank you :)
Your workaround could be improved by using a single Validator and injecting it intp the controller. Have you tried:
#Autowired
private Validator validator;
This way you skip the overhead of creating the validator on each request.
You should also be careful with race conditions. While you are checking the database whether a given email exists another request can create this record, so that you still get an exception at the time you insert the data.
I have a hierarchy of model classes in my Spring/Hibernate application.
When submitting a POST form to a Spring MVC controller, is there any standard way of specifying the type of the object being submitted, so Spring can instantiate the correct subclass of the type declared in the receiving method's #ModelAttribute or #RequestParam?
For example:
public abstract class Product {...}
public class Album extends Product {...}
public class Single extends Product {...}
//Meanwhile, in the controller...
#RequestMapping("/submit.html")
public ModelAndView addProduct(#ModelAttribute("product") #Valid Product product, BindingResult bindingResult, Model model)
{
...//Do stuff, and get either an Album or Single
}
Jackson can deserialize JSON as a specific subtype using the #JsonTypeInfo annotation. I'm hoping Spring can do the same.
Jackson can deserialize JSON as a specific subtype using the
#JsonTypeInfo annotation. I'm hoping Spring can do the same.
Assuming you use Jackson for type conversion (Spring uses Jackson automatically if it finds it on the classpath and you have <mvc:annotation-driven/> in your XML), then it has nothing to do with Spring. Annotate the types, and Jackson will instantiate the correct classes. Nevertheless, you will have to do instanceof checks in your Spring MVC controller method.
Update after comments:
Have a look at 15.3.2.12 Customizing WebDataBinder initialization. You could use an #InitBinder method that registers an editor based on a request parameter:
#InitBinder
public void initBinder(WebDataBinder binder, HttpServletRequest request) {
String productType = request.getParam("type");
PropertyEditor productEditor;
if("album".equalsIgnoreCase(productType)) {
productEditor = new AlbumEditor();
} else if("album".equalsIgnoreCase(productType))
productEditor = new SingleEditor();
} else {
throw SomeNastyException();
}
binder.registerCustomEditor(Product.class, productEditor);
}