Validation of #RequestParam in Spring REST controller doesn't work - spring

I want to validete my GET method's params. I added tis dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
I wrote this controller:
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Min;
#Validated
#RestController
public class TestController {
#GetMapping(value = "/test")
public String getTest(#Min(value = 3, message = "min 3")
#RequestParam("hz") String hz,
#RequestParam("hz1") String hz1) {
return "test";
}
}
I added configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
#Configuration
public class Config {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
the request works fine! Why?
http://localhost:8088/test?hz=12&hz1=123

Related

Swagger-UI (v3) with org.springdoc does show and interpret enums incorrectly

I have a problem with my Swagger-UI: It does show Enums as intended.
Instead of a simple representation like CATEGORY1 it shows the full class like CATEGORY1(name=Cat 1) and also uses it in the requests like http://localhost:8080/file/byCategory?category=Category.CATEGORY1%28name%3DCat%201%29
I figured that I can send Requests (e.g. with Postman) with the correct Enum-descriptions and the server would respond, so the api itself works.
The dependencies important for this issue:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-data-rest</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>1.5.0</version>
</dependency>
I also use Spring Boot (2.4.0) and some other dependencies which shouldn't be part of the issue.
My Controller:
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
#Slf4j
#RestController
#RequestMapping("/file")
#CrossOrigin(origins = "http://localhost:4200")
#Tag(name = "Files")
public class GridFSController {
private final GridFsService service;
#Autowired
public GridFSController(GridFsService service) {
this.service = service;
}
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#Operation(summary = "Upload a document")
#ResponseBody
public ResponseEntity<String> upload(#RequestParam("file") MultipartFile file, #RequestParam("category") Category category) {
try {
if (ObjectUtils.isEmpty(file)) {
return ResponseEntity.ok().body("The uploaded file cannot be empty");
} else {
return ResponseEntity.ok().body(service.saveFile(file, category.getName()));
}
} catch (Exception e) {
log.error("[Upload Failed]", e);
return ResponseEntity.badRequest().body(e.getMessage());
}
}
#GetMapping(value = "/download", produces = MediaType.MULTIPART_FORM_DATA_VALUE)
#Operation(summary = "Download a document by its name")
public ResponseEntity<String> download(HttpServletResponse response, #RequestParam("fileName") String fileName) {
try {
service.downLoad(response, fileName);
return ResponseEntity.ok().body("SUCCESS");
} catch (Exception e) {
log.error("[Download Failed]", e.getMessage());
return ResponseEntity.badRequest().body(e.getMessage());
}
}
#GetMapping("/byCategory")
#Operation(summary = "Get information about all documents in a category")
public ResponseEntity<List<FileMetaDomain>> getByCategory(#RequestParam("category") Category category) {
List<FileMetaDomain> allFilesForCategory = service.getAllFilesForCategory(category.getName());
return ResponseEntity.ok(allFilesForCategory);
}
}
My Enum:
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
#ToString
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#Getter
public enum Category {
CATEGORY1("Cat 1"),
CATEGORY2("Cat 2"),
CATEGORY3("Cat 3");
private final String name;
}
My Swagger-UI however looks like this:
As mentioned, it works with Postman (even though at this point the response is just an empty array):
The point is the toString() method overriding. Try to remove the #ToString annotation.
Your Category should be:
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#Getter
public enum Category {
CATEGORY1("Cat 1"),
CATEGORY2("Cat 2"),
CATEGORY3("Cat 3");
private final String name;
}
And then the swagger-ui will show the enum values dropdown list:
Update:
If you need to keep the toString() method, you have to enrich the category parameter description on your controller. Your GET /byCategory endpoint code should look like:
#GetMapping("/byCategory")
#Operation(summary = "Get information about all documents in a category")
public ResponseEntity<List<FileMetaDomain>> getByCategory(#Parameter(name = "category", in = ParameterIn.QUERY, schema = #Schema(type = "string", allowableValues = {"CATEGORY1", "CATEGORY2", "CATEGORY3"})) Category category) {
List<FileMetaDomain> allFilesForCategory = service.getAllFilesForCategory(category.getName());
return ResponseEntity.ok(allFilesForCategory);
}

Spring rest controller does not validate my DTO

I have this request and response:
#Data
public class TestRequestDto {
#Min(7)
private String name;
}
#Data
public class TestResponseDto {
private String response;
}
And I have a controller:
package com.example.validation.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
#Slf4j
#RestController
public class TetController {
#PostMapping("/test")
public TestResponseDto getTestResponseDto(#Valid #RequestBody TestRequestDto request){
log.info(request.getName());
TestResponseDto response = new TestResponseDto();
response.setResponse("response");
return response;
}
}
I send a post request({"name":"test"}) with an invalid name but it works. What am I doing wrong?
Starting with Boot 2.3, we also need to explicitly add the spring-boot-starter-validation dependency

SpringBoot: Stereotype Annotations not working on Interface Level

package com.Test.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan({"com.Test.springboot"})
public class SpringBoot1Application {
public static void main(String[] args) {
SpringApplication.run(SpringBoot1Application.class, args);
}
}
Controller Class
package com.Test.springboot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.Test.springboot.model.Student;
import com.Test.springboot.model.StudentDao;
#Controller
public class StudentController {
#Autowired
private StudentDao studentDao;
#RequestMapping("/")
public String homePage() {
return "home";
}
StudentDao
#Repository
public interface StudentDao {
public Student addStudent(Student student);
public Student getStudent(long id);
public List<Student> getAllStudents();
public String deleteStudent();
}
If we change the stereotype(Repository) annotation to implementation class it's working fine. but Interface level throwing an error(org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.vitechinc.springboot.model.StudentDao' available:)
Try adding below code as a maven dependancy in the pom.xml file:
I got the same issue and after installing this dependency now its working,
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>

Error creating bean, Injection of autowired dependencies failed - 500 Internal Server Error

I have created a new Spring project and I have some trouble when I run the application. I am new to Spring development and I thing that the annotations are not placed properly. Any detailed explanation would be great for me for better understating. I am currently reading Spring in action, but if any other book or tutorial seems more accurate, please leave me a comment :)[this is the error that I am getting - 500 Internal Server Error].
This is my project:
HelloWorldConfiguration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#EnableWebMvc
#ComponentScan(basePackages = "com.websystique.springmvc")
public class HelloWorldConfiguration {
#Bean(name="HelloWorld")
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
HelloWordInitializer
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class HelloWorldInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(HelloWorldConfiguration.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
}
HelloWorldController
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import service.StudentService;
import java.util.HashMap;
import java.util.Map;
#Configuration
#Controller
#ComponentScan(basePackages = "com.websystique.springmvc")
#RequestMapping("/")
public class HelloWorldController {
public HelloWorldController(){
}
#Autowired
private StudentService studentService;
private Map<String, Student> persoaneAdaugate = new HashMap<String, Student>();
#RequestMapping(method = RequestMethod.GET)
public String sayHello(ModelMap model) {
model.addAttribute("greeting", "Hello World from Spring 4 MVC");
return "welcome";
}
#RequestMapping(value = "/helloagain", method = RequestMethod.GET)
public String sayHelloAgain(ModelMap model) {
model.addAttribute("greeting", "Hello World Again, from Spring 4 MVC");
return "welcome";
}
/***
* #ModelAttribute = binds a method parameter or a method return value to a named model attribute and then exposes it to a web view.
* #param student
* #param result
* #param modelMap
* #return
* That is, #ModelAttribute methods are invoked before the controller methods annotated with #RequestMapping are invoked.
* The logic behind the sequence is that, the model object has to be created before any processing starts inside the controller methods.
*/
#RequestMapping(value="/", method = RequestMethod.POST)
public String addStudent(#ModelAttribute("addStudent") Student student, BindingResult result, ModelMap modelMap){
if(result.hasErrors()){
return "error";
}
else {
studentService.addStudent(student);
}
/*modelMap.addAttribute("nume", student.getNume());
modelMap.addAttribute("prenume", student.getPrenume());
persoaneAdaugate.put(student.getNume(), student);
System.out.println("Persoane adaugate: " + persoaneAdaugate +"\n");
System.out.println("nume: " + student.getNume()+" si prenume: " +student.getPrenume());
*/
return "success";
}
}
StudentDao
import com.websystique.springmvc.model.Student;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public interface StudentDao {
List<Student> getAllStudents();
void addStudent(Student student);
}
StudentDaoImpl
import com.websystique.springmvc.model.Student;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Repository("studentDao")
#Service
#Transactional
public class StudentDaoImpl implements StudentDao{
#Autowired
private SessionFactory sessionFactory;
public List<Student> getAllStudents() {
return null;
// return sessionFactory.getCurrentSession().createQuery("from Date").list();
}
public void addStudent(Student student) {
sessionFactory.getCurrentSession().saveOrUpdate(student);
}
}
Student
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Table(name="DATE")
public class Student implements Serializable{
#Id
#NotEmpty
#Column(name="nume", unique=true, nullable=false )
private String nume;
#NotEmpty
#Column(name="prenume", nullable = false)
private String prenume;
protected Student(){
}
Student(String nume, String prenume){
this.prenume=prenume;
this.nume=nume;
}
public String getNume(){
return nume;
}
public void setNume(String nume){
this.nume=nume;
}
public String getPrenume(){
return prenume;
}
public void setPrenume(String prenume){
this.prenume=prenume;
}
#Override
public String toString(){
return "Numele adaugat: nume= " + nume +" si prenume= " +prenume;
}
}
StudentService
import com.websystique.springmvc.model.Student;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public interface StudentService {
List<Student> getAllStudents();
void addStudent(Student student);
}
StudentServiceImpl
import com.websystique.springmvc.dao.StudentDao;
import com.websystique.springmvc.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#Transactional
public class StudentServiceImpl implements StudentService {
#Autowired
private StudentDao studentDao;
#Transactional
public List<Student> getAllStudents() {
return studentDao.getAllStudents();
}
public void addStudent(Student student) {
studentDao.addStudent(student);
}
}

Annotation based springapplication with no web.xml not working

I am trying to build a spring project without the use of web.xml, but I am frequently getting this error, I've tried everything but so far nothing has solved the problem,
**Sep 15, 2015 11:36:50 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/TestApp/] in DispatcherServlet with name 'dispatcher'**
here is my configuration:-
package com.springWeb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcher ServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
System.out.println("\n\n\n\n\n\n now deploying");
return new String[]{ "/" };
}
}
My AppConfig Class
package com.springWeb.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.springweb.controller.*")
#Import({ SpringSecurityConfig.class })
public class AppConfig {
#Bean
public InternalResourceViewResolver viewResolver() {
System.out.println("\n\n\nello hello hello");
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
And My controller
package com.springWeb.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class TestController {
#RequestMapping(value = { "/", "/welcome**" }, method = RequestMethod.GET)
public String index() {
System.out.println("test est test ets tstsd");
return "index2";
}
}
I suspect it's your #ComponentScan directive. Try changing it to
#ComponentScan({"com.springWeb.*"})
Looks like you maybe have a type-o with com.springweb in all lowercase.

Resources