Springboot #Size constraint on property of bean not triggered - spring-boot

I have the following API setup:
CONTROLLER:
#PostMapping(path = "/post", consumes = "application/json", produces = "application/json")
public ResponseEntity<Object> receiveData(#Valid #RequestBody ArrayList<Person> persondata) {
}
BEAN:
#Component
public class Person {
#JsonProperty(value="name",required = true)
#Size(min=1)
private String name;
public Person(#JsonProperty(value="name", required = true) #Size(min=1) String name) {
this.name = name;
}
When I send the following requestbody through postman, it does not trigger the #Size constraint as expected:
[
{"name":"Pamela"},
{"name":"John"},
{"name":""}
]

Related

Error locating String field in Spring Boot

I'm trying to find a company by its CNPJ(Brazilian corporate tax payer registry number) in a DB (H2), but it's returning an error
{
"timestamp": "2022-03-30T19:30:23.823+00:00",
"status": 404,
"error": "Not Found",
"path": "/companies/cnpj/30101554000146"
}
I've tried other alternatives using:
http://localhost:8080/companies/cnpj/'30.101.554/0001-46', http://localhost:8080/companies/cnpj/"30.101.554/0001-46",
but the error persists. I implemented like this :
#Entity
#Table(name = "company")
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#CNPJ
private String cnpj;
//skipped
}
public interface CompanyRepository extends JpaRepository<Company,Long> {
Optional<Company> findByCnpj(String cnpj);
}
public class CompanyDTO {
private Long id;
private String name;
private String cnpj;
//skipped
}
#Service
#Transactionalpublic class CompanyService {
#Autowired
private CompanyRepository companyRepository;
#Transactional(readOnly = true)
public CompanyDTO findById(Long id) {
Company resultado = companyRepository.findById(id).get();
CompanyDTO dto = new CompanyDTO(resultado);
return dto;
}
#Transactional(readOnly = true)
public CompanyDTO findByCnpj(String cnpf) {
Optional<Company> resultado = companyRepository.findByCnpj(cnpf);
CompanyDTO dto = new CompanyDTO(resultado.get());
return dto;
}
}
#RestController
#RequestMapping(value = "/companies")public class CompanyController {
#Autowired
private CompanyService companyService;
#GetMapping(value = "/{id}")
public CompanyDTO findById(#PathVariable Long id) {
return companyService.findById(id);
}
#GetMapping(value = "/cnpj/{cnpj}")
public CompanyDTO findByCnpj(#PathVariable String cnpj) {
return companyService.findByCnpj(cnpj);
}
}
The expected output would be:
[
{"id": 1,
"nome": "Company 123",
"cnpj": "30.101.554/0001-46"
}
]
UPDATE:
I changed #GetMapping(value = "/cnpj/{cnpj}") to #GetMapping(value = "/cnpj/**") and:
#GetMapping(value = "/cnpj/**")
public CompanyDTO findByCnpj(HttpServletRequest request) {
return companyService.findByCnpj(request.getRequestURI().split(request.getContextPath() + "/cnpj/")[1]);
}
Works for me! Thanks
As explained here, pathParams with slashes can be realy tricky while using spring-boot. This article explains pretty well what to do to avoid getting an error 404 when your pathVariable has a slash.

How to annotate request body to describe examples

I'm struggling with describe the requestBody correctly.
I have this Dto as Request body:
public #Data class ContactDto {
#Parameter(description = "Mailadress required if messageType is MAIL")
private String mailAddress;
#Parameter(description = "Phonenumber required if messageType is not MAIL", example =
"0041791234567")
private String phoneNumber;
#Parameter(description = "Message type which will be used to inform the user", examples = {
#ExampleObject(name = "SMS", value = "SMS"),
#ExampleObject(name = "MAIL", value = "MAIL")
})
private MessageType messageType;
}
And this in the Controller:
#PostMapping(consumes = "application/json")
public ResponseEntity<Object> createWichtel(#RequestBody() final WichtelDetailsDto wichtelDetailsDto)
{
return new ResponseEntity<>(HttpStatus.CREATED);
}
I'm using Spring with springdoc-openapi-ui
But when I'm opening the swagger-ui, the description above does not show.
What is the error here?
Just use #ApiParam
public #Data class ContactDto {
#ApiParam(value = "Mailadress required if messageType is MAIL")
private String mailAddress;
#ApiParam(value = "Phonenumber required if messageType is not MAIL", example =
"0041791234567")
private String phoneNumber;
#ApiParam(value = "Message type which will be used to inform the user", example = "{(name = \"SMS\", value = \"SMS\")}")
private MessageType messageType;

How to send model property, the property is the model too in spring

I have two models.
#Entity
class Product {
#Id
private String id;
private String name;
#ManyToOne(optional = false)
#JoinColumn(name = "category_id", referencedColumnName = "id")
#NotNull(groups = {CREATE.class, UPDATE.class})
private Category category;
...
}
#Entity
class Category {
#Id
private String id;
private String name;
...
}
#RestController
#RequestMapping(path = "/product")
class ProductController {
#RequestMapping(method = RequestMethod.POST)
public void create(#ModelAttribute Product product) {
...
}
}
I want send request to ProductController:
http POST http://localhost:8080/product name=='Product 1' category=1
The param category is id of Category into db, but spring does not understand it.
Is it possible to do this?
Well, your entitiy classes are ok, but it's really weird to see parameters in the POST request especially in so sort as you have it placed here.
Here is my sample that is working properly
public class Product {
private String id;
private String name;
private Category category;
******
}
public class Category {
private String id;
private String name;
*******
}
#RestController
#RequestMapping(path = "/product")
public class ProductController {
#RequestMapping(method = RequestMethod.POST)
public void create(#ModelAttribute Product product) {
Product prd1 = product;
prd1.getId();
}
}
And just in case here is an appConfig:
#Configuration
#EnableWebMvc
public class AppConfig {
}
That is all. Now your contorller is expecting to get a message that is a Product instance.
Let's go onward. It's pretty weird to see parameters in the POST query. I've had some test and they are ok - just pass the data as a request body! Whatever you cose. For instance let's modify controller as it shown below:
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public void create(#ModelAttribute Product product) {
Product prd1 = product;
prd1.getId();
}
}
And now you have to send a POST message with a body that contains a Product data in a JSON format, i.e
{ "id": 1 }
and it works for all other formats that are supported by spring

Get URL parameter for crit use Spring MVC Hibernate

I want to be list out all my users with criteria of where id = formId. The code is working but just that it list out all the users instead of being filtered by formId. Please tell me where i did wrongly. Do tell me if you need any more info to solve this!
controller
*url = http://localhost:8080/User/Panda?Id=1
#RequestMapping(value = {"/{name}?Id={id}" }, method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #PathVariable("id") Integer id) {
logger.info("Users List Page - Id = " + id);
List<User> user = service.findAllUsers(id);
model.addAttribute("users", user);
return "user/list";
}
Service
public List<User> findAllUsers(Integer id) {
return dao.findAllUsers(id);
}
DAO Class
public interface UserDao {
List<User> findAllUsers(Integer id);
}
*DAOImpl Class
#SuppressWarnings("unchecked")
public List<User> findAllUsers(Integer id) {
Criteria crit = createEntityCriteria();
crit.add(Restrictions.eq("formId",id));
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<User> users = (List<Usert>) crit.list();
return users;
}
*for createEntityCriteria() i created in another class call abstractDao and extends to it.
private final Class<T> persistentClass;
#SuppressWarnings("unchecked")
public AbstractDao(){
this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
protected Criteria createEntityCriteria(){
return getSession().createCriteria(persistentClass);
}
Class Entity
#Entity
#Table(name="USER")
public class User implements Serializable{
#NotEmpty
#Column(name="formId", nullable=false)
private Integer formId;
#NotEmpty
#Column(name="FIRST_NAME", nullable=false)
private String firstName;
#NotEmpty
#Column(name="LAST_NAME", nullable=false)
private String lastName;
public Integer getFormId() {
return formId;
}
public void setFormId(Integer formId) {
this.formId= formId;
}
...
}
value = {"/{name}?Id={id}" }
This is wrong way to extract URL param. If you want to get URL param, you should pass it to your method using #RequestParam annotation:
#RequestMapping(value = {"/{name}" }, method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #RequestParam("Id") Integer id) {
//...
}
Spring automatically pass value that you need. For example in case of ?Id=1 Spring will pass 1 to your controller
In your url /{name} is a path variable and is annotated with #PathVariable like in:
#RequestMapping(value = "/foo/bar/{name}", method = GET)
#ResponseBody
public String getBarByName(#PathVariable String name) { ... }
And ?Id=id is a request parameter and is annotated wiht #RequestParam so if we map to url like this one:
http://localhost:8080/api/foo/bar?id=100
we do it like this
#RequestMapping(value = "/foo/bar", method = GET)
#ResponseBody
public String getBarById(#RequestParam("id") Integer id) { ... }
So to combine them to map to your url:
#RequestMapping(value = {"/{name}" }, params = "id", method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #PathVariable String name, #RequestParam("id" Integer id)) { ... }

springboot exceptionhandling without controller class

How to handle exception handling in Spring Boot 1.5.4 without controller class? Currently, I have only entity & repository class as below.
Task.class: (entity)
#Entity
#Table(name = "task")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Length(min = 1)
private String name;
public Task() {
}
public Task(String name) {
this.name = name;
}
public Task(Long id, String name) {
this.name = name;
}
public long getId() {
return id;
}
public String getName(){
return name;
}
}
Repository.class:
public interface TaskRepository extends PagingAndSortingRepository<Task, Long> {
}
POST method: return 200 ok
http://localhost:8080/tasks
{
"name" : "test"
}
But,
{
"name" : ""
}
returns 500 , instead of 400 error.
Pls let me know, if any way to handle this exception without a controller class.
You could use a global #ExceptionHandler with the #ControllerAdvice annotation. Basically, you define which Exception to handle with #ExceptionHandler within the class with #ControllerAdvice annotation, and then you implement what you want to do when that exception is thrown.
Like this:
#ControllerAdvice(basePackageClasses = RepositoryRestExceptionHandler.class)
public class GlobalExceptionHandler {
#ExceptionHandler({ValidationException.class, JsonParseException.class})
public ResponseEntity<Map<String, String>> yourExceptionHandler(Exception e) {
Map<String, String> response = new HashMap<String, String>();
response.put("message", "Bad Request");
return new ResponseEntity<Map<String, String>>(response, HttpStatus.BAD_REQUEST);
}
}
See also: http://www.ekiras.com/2016/02/how-to-do-exception-handling-in-springboot-rest-application.html

Resources