Exception handing in Spring Boot Rest API ResponseStatusException - spring

While running the program saying remove the catch clause.
#RestController #RequestMapping(value = "/api/")
public class EmployeeController {
private EmployeeService employeeService;
#Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
#GetMapping(value = "employee")
public List<Employee> getAllEmployee() {
try {
return employeeService.findAllEmployees();
} catch (MyResourceNotFoundException ex) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Employee not Found", ex);
}
}
}
This is the exception Class
#ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Employee Not Found")
public class MyResourceNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
public MyResourceNotFoundException(String errorMessage) {
super(errorMessage);
}
}
Kindly find below screenshot. This is the exception which is being thrown while running the application.

I think there is a logical error in getAllEmployee method. Because, if in employeeService.findAllEmployees() there will be no employee, then by the logic of code it should return list of Employee with size 0. So, I think your code should look like this:
#GetMapping(value = "employee")
public List<Employee> getAllEmployee() throws MyResourceNotFoundException {
List<Employee> employees = employeeService.findAllEmployees();
if (employees.size() > 0) return employees;
else throw new MyResourceNotFoundException("Employee not Found");
}

Related

NullPointerException thrown during junit test without #SpringBootTest annotation, but not with the annotation

When I remove the #SpringBootTest annotation, I get a NullPointerException during this test:
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class ExceptionInterceptorTests {
private AysUserProvisException aysUserProvisException =
new AysUserProvisException("Failed","True", "Failed to create user. User already exists.", null);
#InjectMocks #Spy ExceptionInterceptor exceptionInterceptorSpy;
#Test
void testAysUserProvisException_generateCorrectResponseSchema() {
ResponseEntity<Object> response = exceptionInterceptorSpy.handleAysUserProvisException(aysUserProvisException);
AysUserProvisResponse exceptionResponse =
new AysUserProvisResponse(
"Failed", "True", "Failed to create user. User already exists.", null);
ResponseEntity<Object> expected =
new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
assertEquals(response.getBody(), expected.getBody());
}
It is thrown when attempting to execute this method:
#ControllerAdvice
public class ExceptionInterceptor extends ResponseEntityExceptionHandler {
#ExceptionHandler(AysUserProvisException.class)
public final ResponseEntity<Object> handleAysUserProvisException(AysUserProvisException ex) {
AysUserProvisResponse exceptionResponse =
new AysUserProvisResponse(
ex.getStatus(), ex.getIsErrorOccurred(), ex.getMessage(), ex.getError());
return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
Here is the AysUserProvisResponse class:
public class AysUserProvisResponse {
private String status;
private String isErrorOccurred;
private String message;
private Error error = new Error();
public AysUserProvisResponse() {
super();
}
public AysUserProvisResponse(String status, String isErrorOccurred, String message, Error error) {
super();
this.status = status;
this.isErrorOccurred = isErrorOccurred;
this.message = message;
this.error = error;
}
How does the #SpringBootTest annotation avoid this exception? Why is it necessary?
You have to upload the spring context if in your code you are using the annotations or trying to inject beans.
Try to mock the dependencies of your Exception class and inject mocks into ExceptionInterceptor class

EmptyResultDataAccessException when testing Spring controller

In my app, there is a controller, a service, a repo and a class. I am writing unit test to verify my PUT request. In postman, the put request works fine, however, when testing in JUnit test, it throws EmptyResultDataAccessException eror. Many other tests have the same problem and all of them require to find a specific entry in the repo by id. I think this is the problem. Please help me on this.
#Data
#Entity
public class ErrorMessage {
private #Id #GeneratedValue Long id;
private String message;
private int code;
public ErrorMessage() {
}
public ErrorMessage(int code, String message) {
this.code = code;
this.message = message;
}
}
#Repository
interface ErrorMessageRepository extends JpaRepository<ErrorMessage, Long> {
List<ErrorMessage> findByCode(int code);
}
#Service
public class ErrorMessageService {
#Autowired
ErrorMessageRepository repository;
#Transactional
public List<ErrorMessage> getAll()
{
return repository.findAll();
}
#Transactional(readOnly = true)
public Optional<ErrorMessage> getById(Long id)
{
return repository.findById(id);
}
#Transactional(readOnly = true)
public List<ErrorMessage> getByCode(int code)
{
return repository.findByCode(code);
}
#Transactional
public ErrorMessage saveOne(ErrorMessage messages)
{
return repository.save(messages);
}
#Transactional
public Optional<ErrorMessage> deleteById(long id)
{
Optional<ErrorMessage> em = repository.findById(id);
repository.deleteById(id);
return em;
}
#Transactional
public ErrorMessage updateById(long id, ErrorMessage newMessage)
{
ErrorMessage m = repository.findById(id).get();
m.setCode(newMessage.getCode());
m.setMessage(newMessage.getMessage());
repository.save(m);
return m;
}
}
class ErrorMessageController {
private static final Logger log = LoggerFactory.getLogger(ErrorMessageController.class);
#Autowired
ErrorMessageRepository repository;
#Autowired
private ErrorMessageService ems;
#GetMapping("/errormessages")
public List<ErrorMessage> getAll() {
return ems.getAll();
}
#GetMapping("/errormessagesbycode/{code}")
public List<ErrorMessage> getByCode(#PathVariable int code) {
return ems.getByCode(code);
}
#GetMapping("/errormessage/{id}")
ErrorMessage getById(#PathVariable Long id) {
return ems.getById(id)
.orElseThrow(() -> new MessageNotFoundException(id));
}
#PostMapping("/errormessage")
ErrorMessage newMessage(#RequestBody ErrorMessage newMessage) {
return ems.saveOne(newMessage);
}
#DeleteMapping("/errormessage/{id}")
Optional<ErrorMessage> deleteMessage(#PathVariable Long id) {
return ems.deleteById(id);
}
#PutMapping("/errormessage/{id}")
ErrorMessage updateMessage(#PathVariable Long id, #RequestBody ErrorMessage newMessage) {
return ems.updateById(id, newMessage);
}
}
#SpringBootTest
#AutoConfigureMockMvc
public class ErrorMessageTest {
private static ErrorMessage em, emId;
private static ObjectMapper mapper;
#Autowired
private MockMvc mockMvc;
#BeforeAll
public static void init() throws Exception {
mapper = new ObjectMapper();
em = new ErrorMessage(400, "bad request0");
emId = new ErrorMessage(400, "bad request0");
emId.setId(Long.valueOf(1));
}
#Test
void putMessage() throws Exception {
ErrorMessage modifiedMessage = new ErrorMessage(400, "modified");
this.mockMvc.perform(MockMvcRequestBuilders
.put("/errormessage/{id}", emId.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(modifiedMessage)))
.andExpect(status().isOk())
.andExpect(content().string(mapper.writeValueAsString(modifiedMessage)));
}
}
Try this
#Test
void putMessage() throws Exception {
ErrorMessage modifiedMessage = new ErrorMessage(400, "modified");
ErrorMessageService errorMessageService = Mockito.mock(ErrorMessageService.class);
Mockito.when(errorMessageService.updateById(Mockito.any(), Mockito.any())).thenReturn(modifiedMessage);
this.mockMvc.perform(MockMvcRequestBuilders
.put("/errormessage/{id}", emId.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(modifiedMessage)))
.andExpect(status().isOk())
.andExpect(content().string(mapper.writeValueAsString(modifiedMessage)));
}
I found out the bug. The order of the unit test is random. All i need to do is use #Order to ensure the order.

How to inject service inside supplier. Repository is null

I created a factory pattern using supplier. That's ok and it worked fine. The path of the right service is OK, but inside the service that will calculate, the repositories are null. It seems is not being autowired.
I tried to autowire and annotate the classes with #Service and #Component and still not work.
#Service
public class Service {
public responseDTO calculate(Contract contract, Request request) {
Supplier<TypeFactory> type = TypeFactory::new;
//HOW TO AUTOWIRE THIS?
return type.get().getCalculationMethod(contract.getId()).calculate(request);
}
}
#Service
public class TypeFactory {
final static Map<Integer, Supplier<Calculator>> calculationTypeMap = new HashMap<>();
static {
calculationTypeMap.put(1, ContractOneType::new);
calculationTypeMap.put(2, ContractTwoType::new);
}
public Calculator getCalculationMethod(Integer type) {
Supplier<Calculator> method = calculationTypeMap.get(type);
if (method != null) {
return method.get();
}
throw new IllegalStateException("Type not found");
}
}
#Service
public interface Calculator {
ResponseDTO calculate(Request Request);
}
#Service
public class ContractOneType implements Calculator {
#Autowired
private ContractRepository contractRepository;
public ResponseDTO calculate(Request request) {
ResponseDTO responseDTO = new ResponseDTO();
Contract contract = contractRepository.findById(request.getId()).orElseThrow(() -> new NotFoundException("id not found"));
//some calculations here with the contract
return responseDTO;
}
}
The contractRepository is null, is not being autowired. It must be.
Error messages from my code:
2019-07-08 10:19:33.078 ERROR
[-,21fa294c89e1e207,21fa294c89e1e207,false] 19477 ---
[nio-8080-exec-1] c.l.d.t.s.h.GeneralExceptionHandler :
msg="Exception", stacktrace="java.lang.NullPointerException
I found a solution changing my supplier that is creating new instances, I just create instances for my implementations and set #Autowired for them.
And that's why my repository is not being #Autowired.
Here's my code:
#Service
public class TypeFactory {
final static Map<Integer, Supplier<Calculator>> calculationTypeMap = new HashMap<>();
#Autowired
ContractOneType contractOneType;
#Autowired
ContractTwoType contractTwoType;
static {
calculationTypeMap.put(1, contractOneType);
calculationTypeMap.put(2, contractTwoType);
}
public Calculator getCalculationMethod(Integer type) {
Supplier<Calculator> method = calculationTypeMap.get(type);
if (method != null) {
return method.get();
}
throw new IllegalStateException("Type not found");
}
}
#Component
public class ContractOneType implements Calculator {
#Autowired
private ContractRepository contractRepository;
public ResponseDTO calculate(Request request) {
ResponseDTO responseDTO = new ResponseDTO();
Contract contract = contractRepository.findById(request.getId()).orElseThrow(() -> new NotFoundException("id not found"));
//some calculations here with the contract
return responseDTO;
}
}
public interface Calculator {
ResponseDTO calculate(Request Request);
}

org.springframework.web.HttpMediaTypeNotSupportedException

when i am trying to get values by id ..i got error like this in postman
{
"timestamp": 1547708533031,
"status": 500,
"error": "Internal Server Error",
"exception":"org.springframework.http.converter.HttpMessageNotWritableException",
"message": "Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.Cetegory.Entites.ArtistRegister[\"subcetgory\"]->com.Cetegory.Entites.SubCetegory_$$_jvst706_1[\"handler\"])",
"path": "/getartist/2"
}
this is contoller for get data by id
#RestController
public class RegisterController {
#Autowired
ArtistService artser;
#PostMapping(value="/addArtist",produces="application/json")
#ResponseBody public ArtistRegister addArtist(#RequestBody ArtistRegister artist) {
ArtistRegister artRegister = null;
try {
artRegister = artser.addArtist(artist);
} catch (Exception e) {
e.printStackTrace();
}
return artRegister;
}
#RequestMapping(value="/getartist/{artist_id}",method=RequestMethod.GET,produces="application/json")
#ResponseBody public ArtistRegister getArtistDetails(#PathVariable ("artist_id") int artist_id ,HttpServletRequest request,
HttpServletResponse response) throws Exception{
return artser.getArtistDetails(artist_id);
}
#RequestMapping(value="/delete/{artist_id}",method=RequestMethod.DELETE,produces="application/json")
public void deleteById(#PathVariable (value="artist_id") int artist_id,HttpServletRequest request,
HttpServletResponse response) throws Exception{
artser.deleteById(artist_id);
}
#RequestMapping(value = "/updateartist", method = RequestMethod.PUT, produces = "application/json")
public ArtistRegister updateArtist(#RequestBody ArtistRegister artreg, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
return artser.updateArtist(artreg);
}
this is service
#Service
#Transactional
public class ArtistService {
#Autowired
private ArtistRepository artrep;
#Autowired
private RegisterDAO artdao;
public ArtistRegister addArtist(ArtistRegister artreg) {
ArtistRegister artReg = null;
try {
artReg = artrep.save(artreg);
} catch (Exception e) {
e.printStackTrace();
}
return artReg;
}
public ArtistRegister getArtistDetails(int artist_id) {
return artdao.getArtistDetails(artist_id);
}
public void deleteById(int artist_id) {
artdao.deleteById(artist_id);
}
public ArtistRegister updateArtist(ArtistRegister artreg) {
return artdao.updateArtist(artreg);
}
}
this is DAO
#Repository
#Transactional
public class RegisterDAO {
private static final Logger logger = LoggerFactory.getLogger(SubCetegoryDAO.class);
#Autowired
SessionFactory sessionFactory;
#Autowired
EntityManager entitymanager;
public ArtistRegister getArtistDetails(int artist_id) {
try
{
String hql = "FROM ArtistRegister a where a.artist_id=?";
return (ArtistRegister) entitymanager.createQuery(hql).setParameter(1, artist_id).getSingleResult();
}
catch (EmptyResultDataAccessException e)
{
return null;
}
catch (Exception e)
{
logger.error("Exception in getUser"+ e.getMessage());
return null;
}
}
Remove #JsonManagedReference annotation and update fetch type to LAZY, by following way:
#OneToOne(targetEntity = SubCetegory.class, cascade = CascadeType.MERGE,fetch=FetchType.LAZY)
#JoinColumn(name = "sub_cetegory_id")
What are fetch types Lazy and Eager?
The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed.
REFERENCES
Official documentation fetch type

Spring Boot Isolation.SERIALIZABLE not working

I need help with this scenario, in theory the isolation level of Serializable should stop delete from happening, but in this scenario it still deletes the row with id 1, I have tried #EnableTransactionManagement and isolation repeatable read, it still doesn't block the delete nor cause the delete to throw exception
In summary, I need to stop any delete invocation whenever the update method is still ongoing
I am using H2 in memory database for this sample
Thanks
Entity:
public class Something {
#Id
private Integer id;
private String name;
private String desc;
}
Repo:
public interface SomeRepository extends JpaRepository<Something, Integer> {
}
Service:
#Service
public class SomeService {
#Autowired
private SomeRepository someRepository;
public void deleteSomething2(Something something) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
someRepository.delete(something);
}
#Transactional(isolation = Isolation.SERIALIZABLE)
public void updateSomething2(Something something) {
Something something1 = someRepository.findById(1).get();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
something1.setName("namanama");
someRepository.saveAndFlush(something1);
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class DemoApplicationTests {
#Autowired
private SomeService service;
#Test
public void test() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Future> futures = new ArrayList<>();
futures.add(executorService.submit(() -> service.updateSomething2(Something.builder().id(1).name("namaone").build())));
futures.add(executorService.submit(() -> service.deleteSomething2(Something.builder().id(1).build())));
while(futures.stream().filter(f -> f.isDone() == false).count() > 0) {
Thread.sleep(3000);
}
List<Something> all = service.findAll();
System.out.println(all);
}
}

Resources