Java에서 오류 코드 / 문자열을 정의하는 가장 좋은 방법은 무엇입니까? SQLException이 발생하면 다음을 수행

Java로 웹 서비스를 작성 중이며 오류 코드 및 관련 오류 문자열을 정의하는 가장 좋은 방법을 찾으려고합니다 . 숫자 오류 코드와 함께 그룹화 된 오류 문자열이 필요합니다. 오류 코드와 오류 문자열은 모두 웹 서비스에 액세스하는 클라이언트로 전송됩니다. 예를 들어, SQLException이 발생하면 다음을 수행 할 수 있습니다.

// Example: errorCode = 1, 
//          errorString = "There was a problem accessing the database."
throw new SomeWebServiceException(errorCode, errorString);

클라이언트 프로그램에 다음 메시지가 표시 될 수 있습니다.

“오류 # 1이 발생했습니다. 데이터베이스에 액세스하는 데 문제가 있습니다.”

내 첫 번째 생각은 Enum오류 코드 중 하나를 사용 toString하고 오류 문자열을 반환하는 메서드를 재정의하는 것이 었습니다. 내가 생각해 낸 것은 다음과 같습니다.

public enum Errors {
  DATABASE {
    @Override
    public String toString() {
      return "A database error has occured.";
    }
  },

  DUPLICATE_USER {
    @Override
    public String toString() {
      return "This user already exists.";
    }
  },

  // more errors follow
}

내 질문은 : 이 작업을 수행하는 더 좋은 방법이 있습니까? 외부 파일에서 읽는 것보다 코드 솔루션을 선호합니다. 이 프로젝트에 Javadoc을 사용하고 있으며 오류 코드를 인라인으로 문서화하고 문서에서 자동으로 업데이트하도록하는 것이 도움이 될 것입니다.



답변

분명히 enum 솔루션의 더 나은 구현이 있습니다 (일반적으로 꽤 좋습니다).

public enum Error {
  DATABASE(0, "A database error has occured."),
  DUPLICATE_USER(1, "This user already exists.");

  private final int code;
  private final String description;

  private Error(int code, String description) {
    this.code = code;
    this.description = description;
  }

  public String getDescription() {
     return description;
  }

  public int getCode() {
     return code;
  }

  @Override
  public String toString() {
    return code + ": " + description;
  }
}

대신 설명을 반환하기 위해 toString ()을 재정의 할 수 있습니다. 확실하지 않습니다. 어쨌든 요점은 각 오류 코드에 대해 별도로 재정의 할 필요가 없다는 것입니다. 또한 서수 값을 사용하는 대신 코드를 명시 적으로 지정했습니다. 이렇게하면 순서를 변경하고 나중에 오류를 추가 / 제거하기가 더 쉽습니다.

이것은 전혀 국제화되어 있지 않다는 것을 잊지 마십시오. 그러나 웹 서비스 클라이언트가 로케일 설명을 보내지 않는 한, 어쨌든 쉽게 국제화 할 수 없습니다. 적어도 클라이언트 측에서 i18n에 사용할 오류 코드가있을 것입니다.


답변

내가 아는 한, 속성 파일에서 오류 메시지를 외부화하는 것을 선호합니다. 이것은 응용 프로그램의 국제화 (언어 당 하나의 속성 파일)의 경우에 매우 유용합니다. 오류 메시지를 수정하는 것도 더 쉬우 며 Java 소스를 다시 컴파일 할 필요가 없습니다.

내 프로젝트에는 일반적으로이 오류에 대한 속성 파일의 키를 포함하는 오류 코드 (문자열 또는 정수,별로 신경 쓰지 않음)가 포함 된 인터페이스가 있습니다.

public interface ErrorCodes {
    String DATABASE_ERROR = "DATABASE_ERROR";
    String DUPLICATE_USER = "DUPLICATE_USER";
    ...
}

속성 파일에서 :

DATABASE_ERROR=An error occurred in the database.
DUPLICATE_USER=The user already exists.
...

솔루션의 또 다른 문제는 유지 보수 가능성입니다. 오류가 2 개 뿐이고 이미 12 줄의 코드가 있습니다. 따라서 관리해야 할 수백 개의 오류가있을 때 열거 파일을 상상해보십시오!


답변

toString () 오버로딩은 약간 이상해 보입니다. toString ()의 정상적인 사용이 약간 늘어난 것 같습니다.

이건 어떤가요:

public enum Errors {
  DATABASE(1, "A database error has occured."),
  DUPLICATE_USER(5007, "This user already exists.");
  //... add more cases here ...

  private final int id;
  private final String message;

  Errors(int id, String message) {
     this.id = id;
     this.message = message;
  }

  public int getId() { return id; }
  public String getMessage() { return message; }
}

나에게 훨씬 더 깨끗하고 … 덜 장황 해 보인다.


답변

마지막 작업에서 나는 enum 버전에서 조금 더 깊이 들어갔다.

public enum Messages {
    @Error
    @Text("You can''t put a {0} in a {1}")
    XYZ00001_CONTAINMENT_NOT_ALLOWED,
    ...
}

@Error, @Info, @Warning은 클래스 파일에 유지되며 런타임에 사용할 수 있습니다. (메시지 전달을 설명하는 데 도움이되는 몇 가지 다른 주석도 있습니다.)

@Text는 컴파일 타임 주석입니다.

다음을 수행하는 주석 프로세서를 작성했습니다.

  • 중복 된 메시지 번호 (첫 번째 밑줄 앞 부분)가 없는지 확인하십시오.
  • 구문-메시지 텍스트 확인
  • 열거 형 값으로 키가 지정된 텍스트를 포함하는 messages.properties 파일을 생성하십시오.

오류를 기록하고 예외로 래핑하는 데 도움이되는 몇 가지 유틸리티 루틴을 작성했습니다 (원하는 경우).

나는 그들이 그것을 오픈 소스로 만들려고 노력하고 있습니다 …-Scott


답변

java.util.ResourceBundle을 살펴 보는 것이 좋습니다. I18N에 관심을 가져야하지만 그렇지 않더라도 그만한 가치가 있습니다. 메시지를 외부화하는 것은 아주 좋은 생각입니다. 비즈니스 직원이보고자하는 정확한 언어를 입력 할 수있는 스프레드 시트를 제공하는 것이 유용하다는 것을 알게되었습니다. 컴파일 타임에 .properties 파일을 생성하는 Ant 태스크를 작성했습니다. 그것은 I18N을 사소하게 만듭니다.

Spring도 사용하고 있다면 훨씬 좋습니다. 그들의 MessageSource 클래스는 이러한 종류의 일에 유용합니다.


답변

이 특정 죽은 말을 계속해서 채찍질하기 위해 최종 고객에게 오류가 표시 될 때 숫자 오류 코드를 잘 사용 했습니다. 최종 고객이 실제 오류 메시지를 자주 잊어 버리거나 잘못 읽었지만 때때로 제공 할 수있는 숫자 값을 유지하고보고 할 수 있기 때문입니다. 실제로 일어난 일에 대한 단서입니다.


답변

이를 해결하는 방법에는 여러 가지가 있습니다. 내가 선호하는 접근 방식은 인터페이스를 사용하는 것입니다.

public interface ICode {
     /*your preferred code type here, can be int or string or whatever*/ id();
}

public interface IMessage {
    ICode code();
}

이제 메시지를 제공하는 열거 형을 얼마든지 정의 할 수 있습니다.

public enum DatabaseMessage implements IMessage {
     CONNECTION_FAILURE(DatabaseCode.CONNECTION_FAILURE, ...);
}

이제이를 문자열로 변환 할 수있는 몇 가지 옵션이 있습니다. 문자열을 코드로 컴파일하거나 (주석 또는 열거 형 생성자 매개 변수 사용) 구성 / 속성 파일 또는 데이터베이스 테이블 또는 혼합에서 읽을 수 있습니다. 당신은 항상 당신이 초기 텍스트로 전환 할 수있는 일부 메시지해야하므로 후자는 나의 선호하는 접근 방법이다 (즉. 동안 데이터베이스에 연결하거나 설정을 읽기).

단위 테스트와 리플렉션 프레임 워크를 사용하여 인터페이스를 구현하는 모든 유형을 찾아서 각 코드가 어딘가에서 사용되고 구성 파일에 모든 예상 메시지가 포함되어 있는지 확인하고 있습니다.

https://github.com/javaparser/javaparser 또는 Eclipse 와 같은 Java를 구문 분석 할 수있는 프레임 워크를 사용 하면 열거 형이 사용되는 위치를 확인하고 사용하지 않는 것을 찾을 수도 있습니다.