AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / user-18070589

Vijay Mohan Rangaraju's questions

Martin Hope
Vijay Mohan Rangaraju
Asked: 2025-04-06 13:58:44 +0800 CST

Spring Boot Swagger lança "Falha ao carregar definição de API. O status da resposta é 500 /v3/api-docs" após adicionar manipuladores de exceção

  • 6

esta é a primeira vez que faço uma pergunta aqui, então, por favor, tenham paciência se eu esquecer de alguma coisa.

Criei um projeto bancário simples no Spring Boot com as seguintes APIs REST:

/criar

/obterConta

/depósito

/retirar

/deleteConta

Tudo funciona perfeitamente:

  1. As APIs funcionam corretamente e atualizam o banco de dados conforme o esperado
  2. A interface do usuário do Swagger mostra todos os endpoints conforme pretendido
  3. Os testes do Postman também funcionam sem problemas

Entretanto, quando adicionei tratamento de exceção personalizado usando @ControllerAdvice, o Swagger começou a gerar este erro:

Falha ao carregar a definição da API. O status da resposta é 500 /v3/api-docs

Aqui está a parte estranha: quando eu removo as classes de exceção, o Swagger começa a funcionar novamente! Então, claramente, há algo na configuração de tratamento de exceção que está causando esse problema.

Alguém pode me ajudar a descobrir o que está errado?

Classe ErrorResponse:

package com.bank.bankingApplication.exceptions;

import java.time.LocalDateTime;

public class ErrorResponse {
    private String message;
    private String timestamp;
    private String path;

    public ErrorResponse(String message, String path) {
        this.message = message;
        this.timestamp = LocalDateTime.now().toString();
        this.path = path;
    }

    // Getters and Setters

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}

Classe GlobalExceptionHandler:

package com.bank.bankingApplication.exceptions;


import com.bank.bankingApplication.controller.BankController;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;


@ControllerAdvice
@RestControllerAdvice(assignableTypes = {BankController.class})
public class GlobalExceptionHandler {

//    @ExceptionHandler(Exception.class)
//    public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, HttpServletRequest request) {
//        ErrorResponse error = new ErrorResponse(ex.getMessage(), request.getRequestURI());
//        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
//    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ErrorResponse> handleTypeMismatch(MethodArgumentTypeMismatchException ex, HttpServletRequest request) {
        String msg = "Invalid type for parameter: " + ex.getName();
        ErrorResponse error = new ErrorResponse(msg, request.getRequestURI());
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgs(IllegalArgumentException ex, HttpServletRequest request) {
        ErrorResponse error = new ErrorResponse(ex.getMessage(), request.getRequestURI());
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

    // You can add more specific ones like @ExceptionHandler(AccountNotFoundException.class) here.
}

Controlador:

package com.bank.bankingApplication.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.bank.bankingApplication.model.Account;
import com.bank.bankingApplication.repository.AccountRepository;
import com.bank.bankingApplication.service.AccountService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/bank")
@Tag(name = "Bank Controller", description = "Handles operations related to bank accounts")
public class BankController {
    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountRepository accountRepository;

    @Operation(
            summary = "Create a new bank account",
            description = "This endpoint is used to create a new bank account for a user."
    )
    @PostMapping("/create")
    public Account createAccount(@RequestBody Account account){
        return accountService.createAccount(account);
    }

    @Operation(
            summary = "Fetches the existing bank account",
            description = "This endpoint is used to fetch an existing bank account for a user."
    )
    @PostMapping("/getAccount")
    public ResponseEntity<?> getAccountDetails(@RequestBody Account account) {
        Long id = account.getId();
        Optional<Account> accountOpt = accountRepository.findById(id);
        if (accountOpt.isPresent()) {
            return ResponseEntity.ok(accountOpt.get());
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Account not found");
        }
    }

    @Operation(
            summary = "Deposits the amount",
            description = "This endpoint is used to deposit amount for a user."
    )
    @PostMapping("/deposit")
    public ResponseEntity<DepositAndWithdrawResponse> deposit(@RequestBody DepositAndWithdrawRequest request) {
        Optional<Account> optionalAccount = accountRepository.findById(request.getId());
        if (optionalAccount.isPresent()) {
            Account account = optionalAccount.get();
            account.setBalance(account.getBalance() + request.getAmount());
            accountRepository.save(account);
            DepositAndWithdrawResponse response = new DepositAndWithdrawResponse();
            response.setId(account.getId());
            response.setAccountHolder(account.getAccountHolder());
            response.setBalance(account.getBalance());
            response.setRemarks("Deposit successful. New balance: " + account.getBalance());
            return ResponseEntity.ok(response);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    @Operation(
            summary = "withdraws the amount",
            description = "This endpoint is used to withdraw amount for a user."
    )
    @PostMapping("/withdraw")
    public ResponseEntity<DepositAndWithdrawResponse> withdraw(@RequestBody DepositAndWithdrawRequest request) {
        Optional<Account> optionalAccount = accountRepository.findById(request.getId());
        if (optionalAccount.isPresent()) {
            Account account = optionalAccount.get();
            if(account.getBalance() >= request.getAmount()){
                account.setBalance(account.getBalance() - request.getAmount());
                accountRepository.save(account);
                DepositAndWithdrawResponse response = new DepositAndWithdrawResponse();
                response.setId(account.getId());
                response.setAccountHolder(account.getAccountHolder());
                response.setBalance(account.getBalance());
                response.setRemarks("Withdraw successful. New balance: " + account.getBalance());
                return ResponseEntity.ok(response);
            }
            else{
                account.setBalance(account.getBalance());
                accountRepository.save(account);
                DepositAndWithdrawResponse response = new DepositAndWithdrawResponse();
                response.setId(account.getId());
                response.setAccountHolder(account.getAccountHolder());
                response.setBalance(account.getBalance());
                response.setRemarks("Withdraw unsuccessful because entered amount was greater than the current balance: " + account.getBalance());
                return ResponseEntity.ok(response);
            }

        } else {
            return ResponseEntity.notFound().build();
        }
    }

    @DeleteMapping("/deleteAccount")
    @Operation(
            summary = "Deletes an existing bank account",
            description = "This endpoint is used to delete an existing bank account for a user."
    )
    public ResponseEntity<String> deleteAccountById(@RequestBody Map<String, Long> request) {
        Long id = request.get("id");
        Optional<Account> account = accountRepository.findById(id);
        if (account.isPresent()) {
            accountRepository.deleteById(id);
            return ResponseEntity.ok("Account with ID " + id + " has been deleted successfully.");
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Account with ID " + id + " not found.");
        }
    }

}

propriedades do aplicativo:

spring.datasource.url=jdbc:mysql://localhost:3306/bank
spring.datasource.username=root
spring.datasource.password=MyPassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.bank</groupId>
    <artifactId>bankingApplication</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bankingApplication</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>21</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Adicionei @ControllerAdvice com classes de exceção personalizadas para retornar respostas de erro estruturadas. Eu esperava que o Swagger continuasse funcionando como antes, mas, em vez disso, recebi um erro 500 em /v3/api-docs. Remover o manipulador de exceção corrige o Swagger, então acredito que algo está errado dentro da camada de tratamento de exceção. Para solucionar o problema, comentei o @ExceptionHandler(Exception.class) generalizado e mantive apenas os específicos, como MethodArgumentTypeMismatchException e IllegalArgumentException, supondo que o Swagger possa depender de algum tratamento de exceção integrado. Mas o resultado ainda foi o mesmo — o Swagger falha ao carregar com um erro 500, enquanto o Postman funciona bem.

java
  • 1 respostas
  • 43 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve