How to pass variable from #controller to #controlleradvice - spring

right now I make custom handler using controlleradvice and is working well. I want to add additional info to the custom validation that "the invoice process has been failed". how do I achieve that ? thank you

You can define you own exception object and uses it to pass the data from the controller method to the exception handler method.
First define an exception as :
public class InvoiceException extends RuntimeException {
private Long invoiceId;
private String additionalInfo;
}
Then in the controller if you check that if violates the related business rules, create an instance of this exception and throw it :
public class InvoiceController {
#PostMapping("/invoice")
public Long processInvoice(InvoiceRequest request){
if(fail) {
throw new InvoiceException(invoiceId, "foobar");
} ​
​}
}
In the #ContorllerAdvice , you can then access these data from the exception instance :
#ControllerAdvice
public class MyExceptionHandler {
​#ExceptionHandler(InvoiceException.class)
​public ResponseEntity<ErrorMessage> handle(InvoiceException ex) {
​
​}
}

Related

Exceptionhandler for Enum in request parameter

I have a Get request: \allTopic
It inputs a filterCriteria custom object which contains multiple fields and one of those is an Enum called Role, which is either student or teacher
And there are many more different API calls with different Enums. So I want to create #controllerAdvice that can handle all these.
I need help with
Annotations to put in the Get API controller function header
Annotations to put in the filterCriteria class
What particular exception to handle in #exceptionHandler in #controlleradvice
I have some similar code as per your need, please have a look
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(value = PageNotFoundException.class)
public String pageNotFoundException(PageNotFoundException exception){
return "error/404";
}
#ExceptionHandler(value = AuthFailedException.class)
public String authFailedException(AuthFailedException exception){
return "error/401";
}
#ExceptionHandler(value = ServerException.class)
public String serverException(ServerException exception){
return "error/500";
}
}
Afterwards, you can throw any of the given type of exception.
please note, you have to create such your exception.
Example:
public class PageNotFoundException extends RuntimeException{
}
I hope, it helps!

Spring - return my onw exception in my own annotation used for validation

I have my onw annotation:
#Constraint(validatedBy = {MaxDateValidator.class})
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface MaxDate {
and my validator:
#RequiredArgsConstructor
public class MaxDateValidator implements ConstraintValidator<MaxDate, LocalDate> {
#Override
public void initialize(MaxDate constraintAnnotation) {
...
}
#Override
public boolean isValid(LocalDate date, ConstraintValidatorContext constraintValidatorContext) {
//I want to throw my onw exception here with some hint to be read by
frontend
if(condition){
throw new MyException("message", HINTS.WRONG_DATE);
}
return someCondition();
}
}
My question is if it's possible to throw my own exception in isValid method? I have my own annotation #MaxDate set on some field in my Dto coming from frontend and in some cases I'd like to throw here my own exception with some hint to be read by frontend and displaying some validation message.
Or maybe I should completely remove this annotation and do some validation in my service method?
It's not a good idea to throw your own exception from the isValid method because by the contract this method shouldn't throw any exceptions (and should be threadsafe by the way). To customize the exception thrown by this validator you can use standard mechanisms like:
Add String message() default "your message"; field inside MaxDate annotation.
Use ConstraintValidatorContext like this:
if(condition){
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("Your message").addConstraintViolation();
return false;
}

#ExceptionHandler not working in a Service class

The below is a service class
#Service
class Test {
public Object findEmployees1(String id, String dbId) {
return employeeRepo.findByDatabaseIdAndIdentifier(dbId, id);
}
public Object findEmployees2(String name, String dbId) {
Object records = employeeRepo.findByNameAndDatabaseId(name, dbId);
}
#ExceptionHandler(Exception.class)
public void internalErrorExceptionHandler(Exception ex) {
LOGGER.error("Log the exception here");
throw new InternalErrorException(ex.getMessage());
}
}
I want if any exception(eg some SQLException) comes in any of the method in the class test , it gets caught by the #ExceptionHandler and is logged there and re thrown
I cannot use #ExceptionHandler with #ControllerAdvice as I don't have any class with #Controller annotation on it . I am writing just a common module to get data from the database.
When I execute the code , the log under #ExceptionHandler is not printed as it never gets called.
The requirement is to log and rethrow a common exception if any exception comes in any of the service class methods without having individual try catch statements in each method.
As suggested, you can use spring aop to handle such exceptions. Instead of duplicating I will link to the existing question I have tried to answer here.
The other way is, if you are using ByteBuddy, you can use following annotation on the method which is expected to throw exception.
#Advice.OnMethodExit(onThrowable = RuntimeException.class)

Using MVC type conversion for path variable and returning 404 on null parameter

My controller. Note the custom #Exists annotation:
#RestController
public class ClientApiController {
#RequestMapping(path = "/{client}/someaction", method = RequestMethod.GET)
String handleRequest(#Exists Client client) {
// ...
}
}
The Exists annotation:
/**
* Indicates that a controller request mapping method parametet should not be
* null. This is meant to be used on model types to indicate a required entity.
*/
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Exists {}
The converter which converts the String from the path variable into a Client instance:
#Component
public class StringToClient implements Converter<String, Client> {
#Autowired
private ClientDAO clientDAO;
#Override
public Client convert(String source) {
return clientDAO.getClientById(source);
}
}
The ResourceNotFoundException exception used to trigger a 404
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
}
My controller method receives the converted Client as desired. If the client id used in the URL matches a client, everything works fine. If the id doesn't match, the client parameter is null empty (uses default constructor) in the handle() controller method.
What I can't get to work now is declarative checking that the Client is not null (i.e. that the id refers to an existing client). If it's null, a ResourceNotFoundException should be thrown. Checking whether the argument is null in the method body and throwing my custom ResourceNotFoundException is easy to do, but repetitive (like this one does). Also, this declarative approach should work for all model classes implementing the interface ModelWithId so it can be used for multiple model types.
I've searched the Spring documentation and I haven't found how to achieve this. I need to insert some processing somewhere after type conversion and before the controller's handleRequest method.
I'm using Spring Boot 1.3.3
After type conversion and before the controller's method there is a validation. You can implement custom validator and raise exception in it. Add new validator to DataBinder, and mark method's parameter as #Validated:
#RestController
public class ClientApiController {
#InitBinder
public void initBinder(DataBinder binder){
binder.addValidators(new Validator() {
#Override
public boolean supports(Class<?> aClass) {
return aClass==Client.class;
}
#Override
public void validate(Object o, Errors errors) {
Client client = (Client)o;
if(client.getId()==null) throw new ResourceNotFoundException();
}
});
}
#RequestMapping(path = "/{client}/someaction", method = RequestMethod.GET)
String handleRequest(#Validated #Exists Client client) {
// ...
}
#RequestMapping(path = "/{client}/anotheraction", method = RequestMethod.GET)
String handleAnotherRequest(#Validated #Exists Client client) {
// ...
}
}
Of course, you can declare validator as separate class, and use it repeatedly in other controllers. Actually, you can raise exception right in your converter, but there is possibility, that you'll need the conversion without exception in other places of your application.

Generalize methods for the application using JDBC template

I am developing a demo application using Spring MVC v3.0 and the Jdbc template.In my application for different -2 module we need some same methods as save,update,delete etc.. .So instead of writing again and again same method for different modules.Do we have any way to implement this kind of functionality in a common class(abstract class).
Hope some buddy will give me the good way to learn and implement this functionality.
You can do that by having a super class with a save method that takes Object type parameter and then you have to check instanceOf and implement.But i suggest you to have different methods for different type.
create an Abstract class
public abstract class AbstractDaoImpl<E,F> extends HibernateDaoSupport{
public abstract Class<E> getEntityType();
public void update(Object updateObject) throws DAOException {
try {
getHibernateTemplate().saveOrUpdate(updateObject);
getHibernateTemplate().flush();
}catch(Exception ex){
logger.error("Error updating attachment: " + ex.getMessage());
throw new DAOException(ex.getMessage(),Code.DAO_EXCEPTION);
}finally {}
//To find by ID
#SuppressWarnings("unchecked")
#Override
public E retrieveSingleMatch(F id) {
return (E) getHibernateTemplate().get(getEntityType(), (Serializable) id);
}
}
and the Dao Implementations
public class StudentDaoImpl<Student,String> extends AbstractDaoImpli implements MyDao {
#SuppressWarnings("unchecked")
public Class getEntityType() {
return Student.class;
}
}
Your service code will be
studentDao.update(anyDomainObject);
Student student = studentDao.retrieveSingleMatch(studentId);
depending on your object ,

Resources