IT박스

Java에서 오류 코드 / 문자열을 정의하는 가장 좋은 방법은 무엇입니까?

itboxs 2020. 7. 23. 19:40
반응형

Java에서 오류 코드 / 문자열을 정의하는 가장 좋은 방법은 무엇입니까?


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 ()을 재정의하고 싶을 수도 있습니다. 어쨌든 요점은 각 오류 코드마다 별도로 재정의 할 필요가 없다는 것입니다. 또한 서수 값을 사용하는 대신 코드를 명시 적으로 지정 했으므로 순서를 변경하고 나중에 오류를 추가 / 제거하기가 더 쉬워집니다.

Don't forget that this isn't internationalised at all - but unless your web service client sends you a locale description, you can't easily internationalise it yourself anyway. At least they'll have the error code to use for i18n at the client side...


As far as I am concerned, I prefer to externalize the error messages in a properties files. This will be really helpful in case of internationalization of your application (one properties file per language). It is also easier to modify an error message, and it won't need any re-compilation of the Java sources.

On my projects, generally I have an interface that contains errors codes (String or integer, it doesn't care much), which contains the key in the properties files for this error:

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

in the properties file:

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

Another problem with your solution is the maintenability: you have only 2 errors, and already 12 lines of code. So imagine your Enumeration file when you will have hundreds of errors to manage!


Overloading toString() seems a bit icky -- that seems a bit of a stretch of toString()'s normal use.

What about:

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; }
}

seems a lot cleaner to me... and less verbose.


At my last job I went a little deeper in the enum version:

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

@Error, @Info, @Warning are retained in the class file and are available at runtime. (We had a couple of other annotations to help describe message delivery as well)

@Text is a compile-time annotation.

I wrote an annotation processor for this that did the following:

  • Verify that there are no duplicate message numbers (the part before the first underscore)
  • Syntax-check the message text
  • Generate a messages.properties file that contains the text, keyed by the enum value.

I wrote a few utility routines that helped log errors, wrap them as exceptions (if desired) and so forth.

I'm trying to get them to let me open-source it... -- Scott


I'd recommend that you take a look at java.util.ResourceBundle. You should care about I18N, but it's worth it even if you don't. Externalizing the messages is a very good idea. I've found that it was useful to be able to give a spreadsheet to business folks that allowed them to put in the exact language they wanted to see. We wrote an Ant task to generate the .properties files at compile time. It makes I18N trivial.

If you're also using Spring, so much the better. Their MessageSource class is useful for these sorts of things.


Just to keep flogging this particular dead horse- we've had good use of numeric error codes when errors are shown to end-customers, since they frequently forget or misread the actual error message but may sometimes retain and report a numeric value that can give you a clue to what actually happened.


There are many ways to solve this. My preferred approach is to have interfaces:

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

public interface IMessage {
    ICode code();
}

Now you can define any number of enums which provide messages:

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

Now you have several options to turn those into Strings. You can compile the strings into your code (using annotations or enum constructor parameters) or you can read them from a config/property file or from a database table or a mixture. The latter is my preferred approach because you will always need some messages that you can turn into text very early (ie. while you connect to the database or read the config).

I'm using unit tests and reflection frameworks to find all types that implement my interfaces to make sure each code is used somewhere and that the config files contain all expected messages, etc.

Using frameworks that can parse Java like https://github.com/javaparser/javaparser or the one from Eclipse, you can even check where the enums are used and find unused ones.


I (and the rest of our team in my company) prefer to raise exceptions instead of returning error codes. Error codes have to be checked everywhere, passed around, and tend to make the code unreadable when the amount of code becomes bigger.

The error class would then define the message.

PS: and actually also care for internationalization !
PPS: you could also redefine the raise-method and add logging, filtering etc. if required (at leastin environments, where the Exception classes and friends are extendable/changeable)


A little late but, I was just looking for a pretty solution for myself. If you have different kind of message error you can add simple, custom message factory so that you can specify more details and format that you'd like later.

public enum Error {
    DATABASE(0, "A database error has occured. "), 
    DUPLICATE_USER(1, "User already exists. ");
    ....
    private String description = "";
    public Error changeDescription(String description) {
        this.description = description;
        return this;
    }
    ....
}

Error genericError = Error.DATABASE;
Error specific = Error.DUPLICATE_USER.changeDescription("(Call Admin)");

EDIT: ok, using enum here is a little dangerous since you alter particular enum permanently. I guess better would be to change to class and use static fields, but than you cannot use '==' anymore. So I guess it's a good example what not to do, (or do it only during initialization) :)


enum for error code/message definition is still a nice solution though it has a i18n concerns. Actually we may have two situations: the code/message is displayed to the end user or to the system integrator. For the later case, I18N is not necessary. I think the web services is most likely the later case.


Using interface as message constant is generally a bad idea. It will leak into client program permanently as part of exported API. Who knows, that later client programmers might parse that error messages(public) as part of their program.

You will be locked forever to support this, as changes in string format will/may break client program.


Please follow the below example:

public enum ErrorCodes {
NO_File("No file found. "),
private ErrorCodes(String value) { 
    this.errordesc = value; 
    }
private String errordesc = ""; 
public String errordesc() {
    return errordesc;
}
public void setValue(String errordesc) {
    this.errordesc = errordesc;
}

};

In your code call it like:

fileResponse.setErrorCode(ErrorCodes.NO_FILE.errordesc());

참고URL : https://stackoverflow.com/questions/446663/best-way-to-define-error-codes-strings-in-java

반응형