So what I am trying to do is to create embedded classes with validation in each class and then get the desired error message when I enter an illegal value. When I have embedded classes, validation suddenly stops working for some reason. I have extracted the core of the problem in the classes below
UserController Class:
// UserController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
#RestController
public class UserController {
public void printUsers(#Valid List<User> users) {
System.out.println(users.get(0).getPeople().get(0).getAge());
}
#GetMapping("/")
public void getUser() {
List<User> users = new ArrayList<>();
Person person = new Person();
person.setAge(-10.0);
person.setFirstName("Test");
person.setLastName("Embedded Validation");
List<Person> persons = new ArrayList<>();
persons.add(person);
User user = new User(persons);
users.add(user);
printUsers(users);
}
}
User Class:
// User.java
package com.example.demo;
import lombok.Builder;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
#Data
#Builder
public class User {
#NotNull
private List<Person> people;
}
Person Class:
// Person.java
package com.example.demo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Person {
#NotNull
#DecimalMin("0.0")
private double age;
#NotNull
private String firstName;
#NotNull
private String lastName;
}
If you run this it will print -10.0, but I have explicitly told the Person class to have a min DecimalVal of 0.0, so my assignment of person.setAge(-10.0); in the UserController class should not be allowed.
How come validation on embedded classes do not work?
Related
My scenario is as follows:
There are several entities, and I need to send custom designed email for each entity "by Id". For example, I am trying to send the email by this URL for "babs" entity:
http://localhost:8081/api/v1/test/babss/sendmail/b1d0c331-35ac-430d-87ca-1718b06351c3
Sample entity for BaBS:
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import javax.persistence.*;
import java.util.UUID;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "babs")
public class BaBs {
#Id
#Column(name = "id")
private UUID id;
#Column(name = "accountCode")
private String accountCode;
#Column(name = "accountName")
private String accountName;
#Column(name = "eMail")
private String eMail;
#ManyToOne
#JsonBackReference
#JoinColumn(name = "accountid")
private Account account;
}
email Sending Service
import gokhan.mutabakatcore.models.BaBs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
#Component
public class SentBaBsEmail {
#Autowired
private JavaMailSender sender;
public HttpStatus mailBaBs(BaBs baBs) throws MailException {
SimpleMailMessage mail = new SimpleMailMessage();
mail.setTo(baBs.getEMail());
mail.setSubject("Trial Mail for Sending BaBs");
mail.setText("Normally Details from Object ");
sender.send(mail);
System.out.println("eMail sent");
return HttpStatus.GONE;
}
}
Corresponding part of BaBS Controller
import gokhan.mutabakatcore.models.BaBs;
import gokhan.mutabakatcore.services.BaBsService;
import gokhan.mutabakatcore.utils.SentBaBsEmail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
#RestController
#RequestMapping("/api/v1/test/babss")
public class BaBsController {
private final BaBsService baBsService;
public BaBsController(BaBsService baBsService) {
this.baBsService = baBsService;
}
#Autowired
SentBaBsEmail baBsEmail;
#RequestMapping(value = "/sendmail/{Id}", method = { RequestMethod.GET, RequestMethod.POST })
public ResponseEntity<?> eMailBaBsByCustomerId(#PathVariable("Id") UUID uuid){
try{
if (!baBsService.findById(uuid).equals(Optional.empty())){
// Converts Optional Object to Normal Object
BaBs baBs = (BaBs) toList(baBsService.findById(uuid));
baBsEmail.mailBaBs(baBs);
return new ResponseEntity(baBs ,HttpStatus.CREATED);
}
return new ResponseEntity<>("Unrecorded BaBS!", HttpStatus.BAD_REQUEST);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
Application.properties Mailing part
#SMTP Email Properties
spring.mail.host=mail.xyz.com
spring.mail.port=587
spring.mail.username=info#xyz.com
spring.mail.password=password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.starttls.enable=true
spring.mail.properties.mail.starttls.required=true
Relavant POM.xml dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
The error I got:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Aug 06 08:39:31 EET 2022
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
I'll appreciate if you can show me the issue...
I recently began working on creating a REST API using Spring Boot. While running the code, though I don't get any error, I get a blank screen when using localhost:8080/expenses/ and I'm not sure why.
My Entity Class
import javax.persistence.*;
import java.math.BigDecimal;
import java.sql.Date;
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "tbl_expenses")
public class Expense {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name ="expense_name")
private String name;
private String description;
#Column(name ="expense_amount")
private BigDecimal amount;
private String category;
private Date date;
}
My Expense Controller
package in.pranay.expensetrackerapi.controller;
import in.pranay.expensetrackerapi.entity.Expense;
import in.pranay.expensetrackerapi.service.ExpenseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class ExpenseController {
#Autowired
private ExpenseService expenseService;
#GetMapping("/expenses")
public List<Expense> getAllExpenses() {
return expenseService.getAllExpenses();
}
}
My Repository
package in.pranay.expensetrackerapi.repository;
import in.pranay.expensetrackerapi.entity.Expense;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ExpenseRepository extends JpaRepository<Expense, Long> {
}
My Application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/expensetracker
spring.datasource.username=root
spring.datasource.password=pranay#1404
Can anyone please help me solve the issue?
I Created a simple Springboot Application with H2 DB. Not able to start the spring boot Application getting below error on startup. I have added all the necessary configurations.
Exception encountered during context initialization - cancelling
refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'studentController': Unsatisfied
dependency expressed through field 'studentService'; nested exception
is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'com.example.test.serviceimpl.StudentServiceImpl' available: expected
at least 1 bean which qualifies as autowire candidate. Dependency
annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Controller:
package com.example.test.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.example.test.serviceimpl.StudentServiceImpl;
import comm.example.test.model.Student;
#RestController
public class StudentController {
#Autowired(required=true)
private StudentServiceImpl studentService;
#GetMapping("/student")
private List<Student> getAllStudent() {
return studentService.getAllStudent();
}
#GetMapping("/student/{id}")
private Student getStudent(#PathVariable("id") Long id) {
return studentService.getStudentById(id);
}
}
Student Pojo class
package comm.example.test.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#AllArgsConstructor
#Entity
#Table(name="student")
public class Student {
#Id
#Column
private Long id;
#Column
private String name;
#Column
private int age;
#Column
private String email;
}
StudentService Interface:
package com.example.test.service;
import java.util.List;
import comm.example.test.model.Student;
public interface StudentService {
List<Student> getAllStudent();
Student getStudentById(Long id);
}
StudentServiceImpl:
package com.example.test.serviceimpl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.example.test.repository.serviceimpl.StudentRepositoryServiceImpl;
import com.example.test.service.StudentService;
import comm.example.test.model.Student;
public class StudentServiceImpl implements StudentService {
#Autowired
private StudentRepositoryServiceImpl serviceImpl;
#Override
public List<Student> getAllStudent() {
return serviceImpl.getAllStudent();
}
#Override
public Student getStudentById(Long id) {
return serviceImpl.getStudentById(id);
}
}
RepositoryService:
package com.example.test.repository.serviceimpl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.test.repository.StudentRepository;
import comm.example.test.model.Student;
#Service
public class StudentRepositoryServiceImpl {
#Autowired
private StudentRepository repo;
public List<Student> getAllStudent() {
List<Student> students = new ArrayList<Student>();
repo.findAll().forEach(student -> students.add(student));
return students;
}
public Student getStudentById(Long id) {
return repo.findById(id).get();
}
}
Repository:
package com.example.test.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import comm.example.test.model.Student;
#Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
}
Your StudentServiceImpl needs a #Service annotation to be injected.
I am trying to create restful api but my controller is not working and I'm getting the error shown below:
{
"timestamp": "2020-06-11T15:28:18.103+00:00",
"status": 404,
"error": "Not Found",
"message": "",
"path": "/path/findCarsAfterYear/2020"
}
Please help me to resolve this.
Entity Class
package com.example.demo.data;
import javax.persistence.*;
#Entity
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private long id;
#Column
private String model;
#Column
private Integer year;
// standard getters and setters
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
}
Repository Class
package com.example.demo.Repository;
import com.example.demo.data.Car;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface CarRepository extends JpaRepository<Car, Integer> {
#Query("Select wds from Car wds where year=?1 ")
List<Car> findCarsAfterYear(Integer year);
}
Service class
package com.example.demo.service;
import com.example.demo.Repository.CarRepository;
import com.example.demo.data.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
#Service
public class CarService {
#Autowired
CarRepository carRepository;
public List<Car> findCarsAfterYear(Integer id) {
return carRepository.findCarsAfterYear(id);
}
}
Controller class
package com.example.demo.Controller;
import com.example.demo.data.Car;
import com.example.demo.service.CarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#Controller
#RequestMapping(path="/test")
public class CarController {
#Autowired(required=true)
private CarService carService;
#GetMapping(value="/findCarsAfterYear/{id}")
public List<Car> findCarsAfterYear(Integer id) {
return carService.findCarsAfterYear(id);
}
}
Application Class
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
#EnableJpaRepositories("com.example.demo.Repository")
#EntityScan("com.example.demo.data")
#ComponentScan(basePackages="com.example.demo.service,com.example.demo.Controller")
#EnableCaching
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
In you want to use #Controller then you have to provide #ResponseBody explicitly.
#Controller
#RequestMapping(path="/test")
public class CarController {
#Autowired(required=true)
private CarService carService;
#GetMapping(value="/findCarsAfterYear/{id}")
#ResponseBody
public List<Car> findCarsAfterYear(Integer id) {
return carService.findCarsAfterYear(id);
}
}
But in case #RestController, which is combination of #Controllerand #ResponseBody
#RestController
#RequestMapping(path="/test")
public class CarController {
#Autowired(required=true)
private CarService carService;
#GetMapping(value="/findCarsAfterYear/{id}")
public List<Car> findCarsAfterYear(Integer id) {
return carService.findCarsAfterYear(id);
}
}
I hope this will be helpful.
I am new to testing. I have created a test case to perform a test on rest API using JUNIT Mockito. In my code I have created a test on method itemGetByid(), but when I run the test I get ApplocationContext error message. I don't know where I am going wrong.
Item Controller Test class
package com.example.demo.controller;
import com.example.demo.entities.Item;
import com.example.demo.entities.User;
import com.example.demo.service.ItemService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import java.util.*;
import static org.junit.Assert.*;
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(ItemController.class)
public class ItemControllerTest {
#Autowired
MockMvc mockmvc;
#Mock
ItemService itemService;
#InjectMocks
ItemController itemController;
#Test
public void itemGetById() {
Item item = new Item();
Mockito.when(itemController.getById(10L)).thenReturn(item);
Item i = itemController.getById(10L);
assertEquals(i, item);
}
}
Item entity class
package com.example.demo.entities;
import lombok.Data;
import javax.persistence.*;
#Data
#Entity
#Table(name = "Item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long itemId;
private Long customerId;
private String itemName;
private int itemPrice;
}
Item controller
package com.example.demo.controller;
import com.example.demo.entities.Item;
import com.example.demo.entities.User;
import com.example.demo.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("item")
public class ItemController {
private ItemService itemService;
#Autowired
public ItemController(ItemService itemService) {
this.itemService = itemService;
}
#PostMapping("/post")
public Item post(#RequestBody Item item) {
return itemService.post(item);
}
#GetMapping
public Iterable<Item> getAll() {
return itemService.get();
}
#GetMapping("/get")
public Item getById(Long id) {
return itemService.getItem(id);
}
#DeleteMapping("/delete")
public void deleteAll() {
itemService.deleteAll();
}
}
Item Service
package com.example.demo.service;
import com.example.demo.entities.Item;
import com.example.demo.userepository.ItemRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
#Service
public class ItemService {
ItemRepository itemRepository;
#Autowired
public ItemService(ItemRepository itemRepository) {
this.itemRepository = itemRepository;
}
public Item post(#RequestBody Item item) {
return itemRepository.save(item);
}
public Iterable<Item> get() {
return itemRepository.findAll();
}
public void deleteAll() {
itemRepository.deleteAll();
}
public Item getItem(Long id) {
return itemRepository.findById(id).get();
}
}
Item Repository
package com.example.demo.userepository;
import com.example.demo.entities.Item;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ItemRepository extends CrudRepository<Item, Long> {
}
For starters, you are using SpringJUnit4ClassRunner. Try the MockitoJunitRunner.
An ItemController instance is never created in the test, so that needs to be fixed as well.
The line below will fail because itemController is not a mock.
**Mockito.when(itemController.getById(10L)).thenReturn(item);**
If itemController is converted to a mock, with the when statement, the test method doesnt validate anything because the test tells Mockito to return the item in the when statement.
Assuming the intent is to validate the ItemController getById method, the Mockito.when statement needs to describe the call to the Mock ItemService.