Exception Handling
1
에러메시지 및 예외 처리
에러 메시지 처리
package com.x2bee.common.base.exception;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Optional;
import com.x2bee.common.base.rest.HttpException;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.boot.json.JsonParseException;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.x2bee.common.base.context.ConfigProperties;
import com.x2bee.common.base.filter.RequestLoggingFilter;
import com.x2bee.common.base.rest.Response;
import com.x2bee.common.base.rest.ValidationError;
import com.x2bee.common.base.util.RequestUtils;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class GlobalControllerAdvice {
private String attributeError = "error";
@ExceptionHandler(HttpInterfaceResponseException.class)
protected ResponseEntity<Object> handleHttpInterfaceException(HttpInterfaceResponseException e, WebRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
String code = Optional.ofNullable(e.getErrorCode()).orElse(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
String message = e.getErrorMessage();
HttpStatus httpStatus = HttpStatus.resolve(Integer.valueOf(code));
if (httpStatus == null) {
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
// HttpInterfaceResponseException의 경우 message값에 json 데이터가 넘어오기 때문에
// ErrorCode로 반환하지 않고 Object형태로 그대로 반환함.
return new ResponseEntity<>(message, httpStatus);
}
@ExceptionHandler(HttpException.class)
protected ResponseEntity<Object> handleHttpException(HttpException e, WebRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
String code = Optional.ofNullable(e.getErrorCode()).orElse(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
String message = e.getErrorMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(WebClientResponseException.class)
protected ResponseEntity<Object> handleWebClientResponseException(WebClientResponseException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("", e);
String code = Optional.ofNullable(String.valueOf(e.getStatusCode().value())).orElse(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
String message = e.getMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(WebClientRequestException.class)
protected ResponseEntity<Object> handleWebClientRequestException(WebClientRequestException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("", e);
String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
String message = e.getMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(AsyncRequestTimeoutException.class)
protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("", e);
String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
String message = e.getMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(Exception.class)
protected ResponseEntity<Object> handleException(Exception e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("", e);
String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
String message = e.getMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(value = { NullPointerException.class, IOException.class, ArrayIndexOutOfBoundsException.class, EntityNotFoundException.class, StringIndexOutOfBoundsException.class, IndexOutOfBoundsException.class, UnsupportedEncodingException.class })
protected ResponseEntity<Object> handleErrorException(Exception e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("handleErrorException {}", e);
String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
String message = e.getMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(value = { IllegalArgumentException.class, IllegalStateException.class, ConstraintViolationException.class, JsonParseException.class, com.fasterxml.jackson.core.JsonParseException.class, HttpMessageNotReadableException.class, MethodArgumentTypeMismatchException.class, MissingServletRequestParameterException.class, MultipartException.class })
protected ResponseEntity<Object> handleIllegalException(Exception e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("handleIllegalException {}", e);
String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
String message = e.getMessage();
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(value = { DataAccessException.class, BadSqlGrammarException.class })
protected ResponseEntity<Object> handleSqlException(Exception e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.error("", e);
String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
String message = MessageResolver.getMessage(CommonAppError.SYSTEM_FAIL);
int httpStatus = Integer.parseInt(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(ValidationException.class)
protected ResponseEntity<Object> handleValidationException(ValidationException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn(e.getMessage(), e);
String code = CommonAppError.VALIDATION_EXCEPTION.getCode();
String message = e.getMessage();
String httpStatusCode = String.valueOf(HttpStatus.BAD_REQUEST.value());
int httpStatus = getBadRequestHttpStatusCode(httpStatusCode);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(BindException.class)
protected ResponseEntity<Object> handleBindException(BindException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("", e);
String code = CommonAppError.BINDING_ERROR.getCode();
String message = getBindingErrorMessage(e.getBindingResult());
String httpStatusCode = String.valueOf(HttpStatus.BAD_REQUEST.value());
int httpStatus = getBadRequestHttpStatusCode(httpStatusCode);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(e, errorCode);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
protected ResponseEntity<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("", e);
String code = CommonAppError.BINDING_ERROR.getCode();
String message = getBindingErrorMessage(e.getBindingResult());
String httpStatusCode = String.valueOf(HttpStatus.BAD_REQUEST.value());
int httpStatus = getBadRequestHttpStatusCode(httpStatusCode);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(e, errorCode);
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
protected ResponseEntity<Object> handleNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("", e);
String code = String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value());
String message = e.getMessage();
int httpStatus = getBadRequestHttpStatusCode(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(NoHandlerFoundException.class)
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("", e);
String code = String.valueOf(HttpStatus.NOT_FOUND.value());
String message = e.getMessage();
int httpStatus = getBadRequestHttpStatusCode(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(MaxUploadSizeExceededException.class)
protected ResponseEntity<Object> handleMaxSizeException(MaxUploadSizeExceededException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("", e);
String code = CommonAppError.INVALID_FILE.getCode();
String message = e.getMessage();
String httpStatusCode = String.valueOf(HttpStatus.PAYLOAD_TOO_LARGE.value());
int httpStatus = getBadRequestHttpStatusCode(httpStatusCode);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(AuthenticationException.class)
protected ResponseEntity<Object> handleAuthenticationException(AuthenticationException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("AuthenticationException: {}", e.getMessage());
log.warn("", e);
String code = String.valueOf(HttpStatus.UNAUTHORIZED.value());
String message = e.getMessage();
int httpStatus = getBadRequestHttpStatusCode(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(JwtException.class)
protected ResponseEntity<Object> handleJwtException(JwtException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("JwtException: {}", e.getMessage());
log.warn("", e);
String code = String.valueOf(HttpStatus.UNAUTHORIZED.value());
String message = e.getMessage();
int httpStatus = getBadRequestHttpStatusCode(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(AccessDeniedException.class)
protected ResponseEntity<Object> handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("AccessDeniedException: {}", e.getMessage());
log.warn("", e);
String code = String.valueOf(HttpStatus.FORBIDDEN.value());
String message = e.getMessage();
int httpStatus = getBadRequestHttpStatusCode(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
@ExceptionHandler(ExpiredJwtException.class)
protected ResponseEntity<Object> handleExpiredJwtException(ExpiredJwtException e, HttpServletRequest request) {
RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
log.warn("ExpiredJwtException: {}", e.getMessage());
log.warn("", e);
String code = String.valueOf(HttpStatus.FORBIDDEN.value());
String message = e.getMessage();
int httpStatus = getBadRequestHttpStatusCode(code);
ErrorCode errorCode = ErrorCode.builder()
.code(code)
.message(message)
.httpStatus(httpStatus)
.build();
return handleExceptionInternal(errorCode);
}
private String getBindingErrorMessage(BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<FieldError> errors = bindingResult.getFieldErrors();
if (CollectionUtils.isNotEmpty(errors)) {
FieldError error = errors.get(0);
return error.getDefaultMessage();
} else {
return MessageResolver.getMessage(CommonAppError.BINDING_ERROR);
}
} else {
return MessageResolver.getMessage(CommonAppError.BINDING_ERROR);
}
}
private ResponseEntity<Object> handleExceptionInternal(ErrorCode errorCode) {
ResponseEntity<Object> body = ResponseEntity.status(errorCode.getHttpStatus())
.body(makeErrorResponse(errorCode));
return body;
}
private Response<Object> makeErrorResponse(ErrorCode errorCode) {
return Response.builder()
.code(errorCode.getCode())
.message(errorCode.getMessage())
.error(true)
.build();
}
private ResponseEntity<Object> handleExceptionInternal(BindException e, ErrorCode errorCode) {
return ResponseEntity.status(errorCode.getHttpStatus())
.body(makeErrorResponse(e, errorCode));
}
private Response<Object> makeErrorResponse(BindException e, ErrorCode errorCode) {
List<ValidationError> validationErrorList = e.getBindingResult()
.getFieldErrors()
.stream()
.map(ValidationError::of)
.toList();
return Response.builder()
.code(errorCode.getCode())
.message(errorCode.getMessage())
.error(true)
.errors(validationErrorList)
.build();
}
private int getBadRequestStartPrefix() {
Integer badRequestStartPrefix = null;
try {
badRequestStartPrefix = ConfigProperties.getInstance().getIntValue("http-status-bad-request-start-prefix");
} catch (Exception ex) {
badRequestStartPrefix = null;
}
if (badRequestStartPrefix == null) {
badRequestStartPrefix = 400;
}
return badRequestStartPrefix;
}
private int getBadRequestHttpStatusCode(String httpStatusCode) {
int badRequestStartPrefix = getBadRequestStartPrefix();
String lastCode = httpStatusCode.substring(httpStatusCode.length() - 2);
int httpStatus = badRequestStartPrefix + Integer.valueOf(lastCode);
return httpStatus;
}
}package com.x2bee.common.base.rest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
@Getter
@Setter
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class Response<T> {
@Schema(description = "result time")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime timestamp = LocalDateTime.now();
@Schema(description = "result code")
private String code = "0000";
@Schema(description = "result message")
private String message = "";
@Schema(description = "process check")
private Boolean isProcess;
@Schema(description = "payload")
@JsonInclude(JsonInclude.Include.NON_NULL)
private T payload;
@Schema(description = "is error")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean error = null;
@Schema(description = "validation error list")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<ValidationError> errors = new ArrayList<>();
@Builder
public Response(String code, String message, T payload, Boolean error, List<ValidationError> errors, Boolean isProcess) {
if (code != null) {
this.code = code;
}
this.message = message;
this.payload = payload;
this.error = error;
this.isProcess = isProcess;
if (errors != null && !errors.isEmpty()) {
this.errors = errors;
}
}
public Response<Object> setErrorResponse(String code, String message, Boolean isProcess) {
return Response.builder()
.code(code)
.message(message)
.isProcess(isProcess)
.error(true)
.build();
}
}package com.x2bee.api.common.base.advice;
import com.x2bee.common.base.exception.AppError;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ApiError implements AppError {
// success
SUCCESS("0000", "common.message.success", "common.message.success", false),
// app error
EMPTY_PARAMETER("1001", "common.error.emptyParameter", "common.error.emptyParameter", false),
INVALID_PARAMETER("1002", "common.error.invalidParameter", "common.error.invalidParameter", false),
DATA_NOT_FOUND("1003", "common.error.dataNotFound", "common.error.dataNotFound", false),
DATA_INVALID_PARAMETER("1004", "common.error.dataInvalidParameter", "common.error.dataInvalidParameter", false),
INVALID_FILE("1005", "common.error.invalidFile", "common.error.invalidFile", false),
DUPLICATE_DATA("1007", "common.error.duplicateData", "common.error.duplicateData", false),
TROUBLE_NETWORK("1008", "common.error.trouble.network", "common.error.trouble.network", false),
TROUBLE_EXCEPTION("1009", "common.error.trouble.exception", "common.error.trouble.exception", false),
UPLOAD_FAIL("1100", "common.error.uploadFail", "common.error.uploadFail", false),
// ERP
ERP_ERROR_MESSAGE("2000", "common.erp.errorMessage", "common.erp.errorMessage", false),
// 결제관련
PAYMENT_TOSS_NOT_INCLUDE("4001" , "paymentCommon.toss.not.include", "paymentCommon.toss.not.include", false),
PAYMENT_CUSTOMERKEY_NOT_SAME("4002" , "paymentCommon.customerkey.not.same", "paymentCommon.customerkey.not.same", false),
PAYMENT_REQUIED_NOT_FIND("4003" , "paymentCommon.requied.not.find", "paymentCommon.requied.not.find", false),
PAYMENT_COMMON_IN_APRL_ERROR("4004" , "paymentCommon.in.aprl.error", "paymentCommon.in.aprl.error", false),
PAYMENT_COMMON_CNCL_IN_APRL_SUC("4005" , "paymentCommon.cncl.in.aprl.suc", "paymentCommon.cncl.in.aprl.suc", false),
PAYMENT_COMMON_CNCL_IN_APRL_ERROR("4006" , "paymentCommon.cncl.in.aprl.error", "paymentCommon.cncl.in.aprl.error", false),
PAYMENT_COMMON_IN_CNCL_ERROR("4010" , "paymentCommon.in.cncl.error", "paymentCommon.in.cncl.error", false),
PAYMENT_COMMON_IN_CNCL_SUC("4011" , "paymentCommon.in.cncl.suc", "paymentCommon.in.cncl.suc", false),
PAYMENT_RESPONSE_EMPTY("4012" , "paymentCommon.response.empty", "paymentCommon.response.empty", false),
// 권한 없음.
NOT_AUTHORIZED("7000", "common.error.notAuthorized", "common.error.notAuthorized", false),
// binding error
BINDING_ERROR("8000", "common.error.bindingError", "common.error.bindingError", false),
BINDING_ERROR_NOT_NULL("8001", "common.error.bindingErrorNotNull", "common.error.bindingErrorNotNull", false),
// unknow error
UNKNOWN("9000", getMessageUnknown(), getMessageUnknown(), false),
// ValidatioException error
VALIDATION_EXCEPTION("9100", getMessageUnknown(), getMessageUnknown(), false);
private final String code;
private final String messageKey;
private final String boMessageKey;
private final Boolean isProcess;
@Override
public boolean getIsProcess() {
return isProcess;
}
private static String messageUnknown = "common.error.unknown";
public static String getMessageUnknown() {
return messageUnknown;
}
}2
예외 처리 기능 (x2bee-common 패키지 하위 Exception 클래스 구현)
package com.x2bee.common.base.exception;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CommonException extends UserDefinedException {
private static final long serialVersionUID = 1L;
private final String errorCode;
private final String errorMessage;
public CommonException(String message, Throwable cause) {
super(message, cause);
this.errorCode = "500";
this.errorMessage = message;
}
public CommonException(String message) {
super(message);
this.errorCode = "500";
this.errorMessage = message;
}
public CommonException(Throwable cause) {
super(cause);
this.errorCode = "500";
this.errorMessage = cause.getMessage();
}
public CommonException(String errorCode, String errorMessage) {
super(errorMessage);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
}package com.x2bee.common.base.exception;
@SuppressWarnings("serial")
public class ValidationException extends UserDefinedException {
public ValidationException() {
super();
}
public ValidationException(String message) {
super(message);
}
public ValidationException(Throwable t) {
super(t);
}
public ValidationException(String message, Throwable t) {
super(message, t);
}
}마지막 업데이트