Home > Software engineering >  How to set values inside the enum directly from the properties file key?
How to set values inside the enum directly from the properties file key?

Time:01-23

I have been trying to load string values by inserting the keys from properties file inside the enum constructor. But instead of setting the values, it's setting the keys only.

My errorcodes.properties have this content

error.id.required.message=Id is required to get the details. error.id.required.code=110

and enum file is like this:

`public enum ErrorCodes {
  ID_REQUIRED("error.id.required.message",
      "error.id.required.code"),
  ID_INVALID("error.id.invalid.message",
      "error.id.invalid.code");

  private final String msg;
  private final String code;

  private ErrorCodes(String msg, String code) {
    this.msg = msg;
    this.code = code;
  }

  public String getMsg() {
    return msg;
  }

  public String getCode() {
    return code;
  }
}`

So I created an exception which would take one of the above defined enum as an argument and throw a custom exception with message as "Id is required to get the details." and the code as "110".

e.g., throw new CustomException(ErrorCodes.ID_REQUIRED)

Instead the response came as

"errorCode": "error.id.required.code"
"errorMessage": "error.id.required.message"

Please help! Thanks.

CodePudding user response:

To fix this, you must load the properties file and retrieve the values using the keys passed to the enum constructor.

You can use the java.util.Properties class to load the properties file and retrieve the values. Here is an example of how you can modify your code to load the values from the properties file:

public enum ErrorCodes {
  ID_REQUIRED("error.id.required"),
  ID_INVALID("error.id.invalid");

  private final String msg;
  private final String code;

  static {
    properties = new Properties();
    RuntimeException initError;
    try {
      InputStream input = getClass().getResourceAsStream("errorcodes.properties")
      properties.load(input);
    } catch (IOException e) {
     initError = RuntimeException initError = new RuntimeException("Unhandled Error: ", e)
    }
  }

  private ErrorCodes(String key) {
    this.msg = key   ".message";
    this.code = key   ".code";
  }

  public String getMsg() {
    return getProperty(msg);
  }

  public String getCode() {
    return getProperty(code);
  }

  private static String getProperty(String key) {
    if (initError != null) {
      throw initError;
    }
    return properties.getProperty(key);
  }
}

This way, the enum constructor takes the property's key and uses it to look up the values from the properties file.

As a side note, you should also ensure that the errorcodes.properties is in the classpath of your application.

CodePudding user response:

In general there's no good idea to use Enum like this. Remember, that enum's constant is singleton, therefore you can't use this like this.

I think it's better to have separate class, where you can encapsulate this logic:

  • Read property file
  • Get an Enum and retrieve only related data from the file
  • Declare two Map to save message and code by ErrorCode
  • Getters to retreive message and code by ErrorCode
  • ErrorCode and ErrorCodeStore should be in the same package

This is an enum ErrorCode:

@lombok.RequiredArgsConstructor(access = AccessLevel.PACKAGE)
public enum ErrorCode {

    ID_REQUIRED("error.id.required.message", "error.id.required.code"),
    ID_INVALID("error.id.invalid.message", "error.id.invalid.code");

    final String message;
    final String code;

    public final String getMessage() {
        return ErrorCodeStore.getInstance().getValue(message);
    }

    public final String getCode() {
        return ErrorCodeStore.getInstance().getValue(code);
    }

}

This is ErrorCodeStore:

@lombok.RequiredArgsConstructor(access = AccessLevel.PRIVATE)
final class ErrorCodeStore {

    private static ErrorCodeStore instance;

    public static ErrorCodeStore getInstance() {
        if (instance == null)
            throw new RuntimeException("ErrorCodeStore instance should be"
                                                 " initialized");
        return instance;
    }

    private final Properties properties;

    // InputStream should be explicitly closed
    public static ErrorCodeStore initFrom(InputStream in) throws IOException {
        Properties properties = new Properties();
        properties.load(in);

        return instance = new ErrorCodeStore(properties);
    }

    String getValue(String key) {
        return properties.getProperty(key, key);
    }

}

Demo

public static void main(String[] args) throws IOException {
    ErrorCodeStore.initFrom(Main.class.getResourceAsStream("/errorcodes.properties"));
    System.out.println(ErrorCode.ID_REQUIRED.getMessage()); // Id is required to get the details.
    System.out.println(ErrorCode.ID_REQUIRED.getCode());    // 110
    System.out.println(ErrorCode.ID_INVALID.getMessage());  // error.id.invalid.message
    System.out.println(ErrorCode.ID_INVALID.getCode());     // error.id.invalid.code
}
  • Related