springboot return 200 when close Closeable even throw exception

1k Views Asked by At

How to return error in springboot and close a Closeable class? When I got some error in springboot and close a closable class is returning 200 OK

don't I need close the Closeable? Is there some way to handle this on springboot?


   CSVPrinter csvPrinter;

    try{

        csvPrinter = new CSVPrinter(httpServletResponse.getWriter() , CSVFormat.DEFAULT);

        System.out.println(1/0); // force exception to jump into catch

    }catch (Exception e) {

        e.printStackTrace();

        try { csvPrinter.close(true); } catch (IOException e1) { e1.printStackTrace(); } // has returned 200 OK when closing CSVPrinter
         
        throw new RuntimeException("Error"); // this are been called but was already returned 200
    }


I've tried on try-with-resources but no success too

    try( final CSVPrinter csvPrinter = new CSVPrinter( httpServletResponse.getWriter() , CSVFormat.DEFAULT) ){

        System.out.println(1/0); // // force exception to jump into catch

    }catch (Exception e) {  // has returned 200 OK 
        throw new RuntimeException("Error"); // this are been called but was already returned 200
    }

I'm inject httpResponse in controller

  @GetMapping("/export")
   public void exportInCsv(
                ExportRequest exportRequest,
                HttpServletResponse httpServletResponse // inject httpreponse
             ){

        exportService.writeResponse(exportRequest,httpServletResponse);
    }

I have no controller exception handler

1

There are 1 best solutions below

3
Blair Nangle On

Your controller method (exportInCsv()) doesn't actually return a ResponseEntity object, so GET requests made to this endpoint will always result in 200 responses.

You should either throw a checked exception as a result of a failure to do something (construct or close an instance of CSVPrinter), or implement ResponseEntityExceptionHandler more generally in your code to catch unchecked exceptions and respond with a generic error message (and 400).

Personally, I prefer the former way of doing things, as the code will end up more explicit and allow you more customisation of your endpoint (but it is not a bad idea to do both).

Pseudocode

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


import java.util.UUID;


@RestController
@RequestMapping("/widgets")
public class WidgetController {

    @GetMapping(value = "/{widgetId}", produces = "application/json")
    public ResponseEntity<?> fetchWidget(@PathVariable UUID widgetId) {
        try {
            Widget widget = findWidgetById(widgetId);

            return ResponseEntity.ok().body(widget);
        } catch (CheckedException e) {
            return ResponseEntity.badRequest().build();
        }
    }

    private Widget findWidgetById(UUID widgetId) throws CheckedException {
        Widget widget = findMethodThatMightThrowCheckedException(widgetId);

        return widget;
    }

}

With a checked exception, you also have the option of dealing with it a lower level (closer to where it was initially thrown), but it sounds like you want to bubble it up (and map it to an HTTP response) to the client of your GET /export API.