j.sinjaradze
j.sinjaradze

Reputation: 165

How can i reduce repetitive code in spring boot controllers

I've just started to use spring boot for my services. I have few controllers that use same code in their bodies. for example in every controller I have to check if request object obtained from request is null or not:

if (request == null){
    throw new InvalidRequestException("the request object is null");
}

I know that repeating code in several controllers is not a good approach, so I was wondering if there is a way to prevent code repetition, or if spring boot has a solution for the mentioned problem.

Upvotes: 3

Views: 1489

Answers (8)

darshakat
darshakat

Reputation: 689

Better to use @Valid to check the payload, without checking it manually. Please follow the below explanation.

You can use "import org.springframework.validation.Errors;" and @Valid as below.

@PostMapping("/test")
public ResponseEntity<String> editStatus(@Valid @RequestBody Person person, Errors errors) {
    String responseMessage;
    if(errors.hasErrors()) {
        responseMessage = "'" + errors.getFieldError().getField() + "' " + errors.getFieldError().getDefaultMessage();
    } else {
        // You can do ur logic here
        responseMessage = "result";
    }
    return ResponseEntity.accepted().body(responseMessage);
}

Person payload you can validate as below.

public class Person {
    @NotNull
    private String firstName;
    @NotNull
    private String lastName;
    private String city;

    //Getter
    //Setter
}

In this explanation, I used Person payload. @Valid check the payload content. Once you receive payload without mandatory fields, you can handle the situation using errors.

Upvotes: 0

Raj
Raj

Reputation: 976

I agree to @Niraj Sonawane to use the @Validated annotation to deal with the specific case given in the post.

To add to that, using filters may be another option to deal with the cases that fall into "pre-requisite-to-perform-controller-actions". We were using a complex logic to resolve access permissions which were required by all the controllers we had in the design. And, we used a filter to handle that.

Upvotes: 0

Z fp
Z fp

Reputation: 574

Spring AOP?

create a Aspect class like this:

@Aspect
class AopDemo{

    @Around("execution(* com.demo.controller.*(..))")
    public Object release(JoinPoint jp){
        try{
            Object[] args = jp.getArgs();
            for(Object arg: args){
                if(arg == null){
                    throw new InvalidRequestException("the request object is null"); 
                }
            }
            return jp.proceed(args);
        }catch(InvalidRequestException ire){
            // handle InvalidRequestException
        }catch(Exception ex){
            // handle Exception
        }
    }

}

Upvotes: 0

BSeitkazin
BSeitkazin

Reputation: 3059

You are using SpringBoot, so in your application, where you define @SpringBootApplication annotation, you can specify the next @Bean:

@Bean
public HttpRequestHandler httpRequestHandler () {
    return new MyHttpRequestHandler();
}

Also create MyHttpRequestHandler class, where you can make any your logic with that:

public class MyHttpRequestHandler implements HttpRequestHandler {

@Override
public void handleRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request == null) {
            throw new InvalidRequestException("the request object is null");
        }
   }
}

Upvotes: 4

Niraj Sonawane
Niraj Sonawane

Reputation: 11115

Basically what you are doing is parameter validation. This is is kind of cross cutting concerns and perfect use case for using AOP approach.

Spring provide very nice way of doing this

you can simply use @validate like this

@PostMapping
    public ResponseEntity<Void> someMEthod(@Validated(CustomChecks.class) @RequestBody request yourRequest)

Then you can put all your validation logic inside CustomChecks class. (You can find number of examples)

if you have very small and general purpose validations then you can also use annotations.

in your case simply put @NotNull annotation on your request class. Check this example

hope this helps

Upvotes: 1

Fima Taf
Fima Taf

Reputation: 977

One approach is to create an abstract class that will contain a wrapping method that will be called by the extending controller.

public abstract class CoreController {
  protected void validateRequest(MyRequest request) {
    if (request == null) throw new InvalidRequestException("the request object is null");
  }
}

Extend your controllers with this class and call the validateRequest method

public class MyController extends CoreController {
  @PostMapping("/some_endpoint")
  public MyResponse endpointMethod (@RequestBody MyRequest request) {
    validateRequest(request);
    ...
    return new MyResponse();
  }
}

Upvotes: 0

Paris Karagiannopoulos
Paris Karagiannopoulos

Reputation: 591

Make your service layer throw custom exceptions according to your conditions and use a @ControllerAdvice in your Controller to handle the output when exceptions are thrown.

Upvotes: 0

Lorelorelore
Lorelorelore

Reputation: 3393

Just wrap that code in a method:

protected void checkRequest(Object request){
    if (request == null){
        throw new InvalidRequestException("the request object is null");
    }
}

and declare it in an AbstractController class. Let your controllers extend this class.

Upvotes: 0

Related Questions