1

I am working on a project which contains a couple of modules. I want to provide the ability in every module to have a custom exception that statically populates internal structure, e.g. HashMap, from property file with custom error_code-error_message pairs. I have a base abstract custom exception what contains a static property:

public abstract class AbstractException extends RuntimeException{
   public static Map<String, String> ERRORS = new HashMap<String, String>();
   public String code;
   // getters and setter for code ommited

   public static init(String fileName, Class<?> clazz){
    // read properties file
    // populate map
   }

   public static String getMessageByCode(String code){
    //
   String mess = ERRORS.get(code);
   // in case of null message provide default message about unknown error
   }

   public AbstractException(String code){
      super(getMessageByCode(code));
      this.setCode(code);
   }

   public AbstractException(Throwable thr){
      super(getMessageByCode("ERROR_999"), thr);
      this.setCode(code);
   }

   public AbstractException(Throwable thr, String msg){
      super(getMessageByCode("ERROR_999") + " " + msg, thr);
      this.setCode(code);
   }

}

Simple custom exception

public class MyException extends AbstractException{
 static{
   // populate internal map with module-specific errors
   init("module1.errors.properties", MyException.class);
 }     

public MyException(String code){
 super(getMessageByCode());
}
// rest code omited

}

Simple usage of custom exception in code:

throw new MyException("ERROR_404");

Propblems what I can see in this code:

  1. ERRORS map exists for all child classes of abstract exception
  2. Concurrent access to static ERRORS field.

Question is, how to avoid these problems, may be someone have a better solution of my problem?

DJClayworth
  • 26,349
  • 9
  • 53
  • 79
Vik Gamov
  • 5,446
  • 1
  • 26
  • 46
  • 1
    Are you wanting to share error messages between modules? –  Jul 15 '11 at 14:38
  • What sort of problem when concurrent access to static ERRORS? there is no dirty read/write for those static members, isn't it? – TheOneTeam Jul 15 '11 at 14:48
  • Maybe you should use `java.util.logging` instead. Do you really need to keep those errors in memory? – toto2 Jul 15 '11 at 15:13
  • 2Brian No, I don't want. With common parent class I just want to have incapsulate same logic populating and using errors map. – Vik Gamov Jul 15 '11 at 16:18
  • [Hashtable](http://stackoverflow.com/questions/40471/java-hashmap-vs-hashtable) is synchronized while HashMap is not. – Jeffrey Jul 15 '11 at 17:30

1 Answers1

1

This design won't work because there will be only one copy of ERRORS, shared among all subclasses. One possible solution is an ExceptionFactory that manages the various ERRORS maps and can create and exceptions of the required subclasses for you. For example

public static class AbstractException extends RuntimeException 
{ 
    String code;
    String message;
    public void setCode(String code) { this.code = code; }
    public void setMessage(String message) { this.message = message; }
}

public static class MyException1 extends AbstractException{ }

public static class MyException2 extends AbstractException{ }

public static class ExceptionFactory
{
    private Map<Class<?>,Map<String,String>> errorMaps = new HashMap<Class<?>, Map<String,String>>();
    public void register(Class<? extends AbstractException> exType, String fileName)
    {
        Map<String,String> errors = new HashMap<String,String>();
        // load errors from fileName
        errorMaps.put(exType, errors);
    }

    public <T extends AbstractException> T newException(Class<T> exType, String code)
    {
        Map<String,String> map = errorMaps.get(exType);
        String message = map.get(code);
        T ex;
        try
        {
            ex = exType.newInstance();
            ex.setCode(code);
            ex.setMessage(message);
            return ex;
        }
        catch(InstantiationException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch(IllegalAccessException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190