0

Suppose I have several classes:

Class ExceptionA{
    public ExceptionA(ExceptionA.ErrorCode errorCode){}
    setters...
    getters...
    public static enum ErrorCode{
        EC_ABC,EC_XYZ,EC_123
}

Class ExceptionB{
    public ExceptionB(ExceptionB.ErrorCode errorCode){}
    setters...
    getters...
    public static enum ErrorCode{
        EC_DEF,EC_LOL,EC_456
}

In a loop somewhere that works with an array containing ExceptionA, ExceptionB, ExceptionC objects: I want to generically construct an Exception object using its constructor without ever explicitly stating ExceptionX.ErrorCode.

Class<? extends Exception> expectedException = exception.getClass().getConstructor(Enum.class).newInstance(someErrorCodeEnum);

The issue occurs at getConstructor(). Constructors do exist for each Exception class, but they take SpecificException.ErrorCode type. Not just a generic Enum.class. Is there some method that might work like this?:

ExceptionA exceptionAobject = new ExceptionA(EC_ABC);
exceptionAobject.getEnumClassFromString("ErrorCode"); // Should be of type ExceptionA.ErrorCode
3
  • There might be some bean introspection API that might work. Otherwise, you'll need to get the constructors with getConstructors(), looping through them to find one where the parameter type is a subtype of Enum, and use that one. Commented Jan 9, 2017 at 18:50
  • Is the use of different error code enums the only difference between your exception classes, or may there be other differences too? Commented Jan 9, 2017 at 19:19
  • I haven't noticed any yet, but there may be other differences. I just want to account for the possibility of those as well. Commented Jan 9, 2017 at 19:21

2 Answers 2

1

It depends on the circumstances. If you know for sure that there will be only a single constructor, you could simply call, e.g. ExceptionA.class.getConstructors()[0] to get the sole constructor. You could even call getParameterTypes()[0] on the constructor object to get the actual ErrorCode type.

Otherwise, if you know that there should be an inner class named ErrorCode, you have to use the Binary name of the inner class, i.e.

Class<? extends Exception> exceptionType = exception.getClass();
Class<?> errorCodeType = exceptionType.getClassLoader()
                        .loadClass(exceptionType.getName()+"$ErrorCode");
assert errorCodeType.getDeclaringClass() == exceptionType;

Then, you can lookup the constructor using

Constructor<? extends Exception> con = exceptionType.getConstructor(errorCodeType);

But maybe you are thinking too complicated. If you already have your someErrorCodeEnum object that you intend to pass to the constructor, you can simply use this object to determine the parameter type:

Constructor<? extends Exception> con = exception.getClass()
    .getConstructor(((Enum<?>)someErrorCodeEnum).getDeclaringClass());

Note the importance of using Enum.getDeclaringClass() rather than Object.getClass() here, as a particular enum constant may be of an anonymous inner class extending the formal enum type. getDeclaringClass() will return the right type.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you! I'm almost there. Constructor ctor = exception.getClass().getConstructor(((Enum<?>) errorCode).getDeclaringClass()); WhatClassType expectedException = ctor.newInstance(errorCode); The type that this constructor may return might be an ExceptionA or ExceptionB, etc. How do I generically specific the return type?
Isn’t this where a common superclass of your exception classes comes in? As mentioned at the bottom of my (otherwise not to the point) answer.
Well, if there’s no other common base class than Exception, using Constructor<? extends Exception> like shown in my answer will be sufficient to assign the result of newInstance to variables of type Exception or the same type as the exception variable, as long as it isn’t a type parameter. If the type of exception is a type parameter, there is no type safe way to denote that the result of the Reflection operation will be of the same type. It will be the erasure of the type variable instead. That’s a known limitation of Java Generics.
0

I am not quite sure I got your requirements. I am thinking this ought to be doable without reflection, so here’s my idea:

public class ExceptionA extends Exception {

    public ExceptionA(ExceptionA.ErrorCode errorCode) {
    }

    public static enum ErrorCode implements ExceptionErrorCode {
        EC_ABC, EC_XYZ, EC_123;

        @Override
        public Exception toException() {
            return new ExceptionA(this);
        }
    }
}

I am using this little interface:

public interface ExceptionErrorCode {
    Exception toException();
}

This will allow something like:

    ExceptionErrorCode someErrorCodeEnum = ExceptionA.ErrorCode.EC_XYZ;
    Exception expectedException = someErrorCodeEnum.toException();

Would this fulfil your requirements?

I am thinking for the sake of the model you may want to introduce a common superclass for your exception classes so you need not declare toException() and expectedException just Exception — it’s a vague type for my taste. And even though you don’t see the need immediately, the supertype could come in handy some time.

2 Comments

There are several exception classes though. MyRuntimeException, MyCheckedException, etc. that all extend the base Exception class.
I expected that. And yes, you would have to duplicate the override of toException() in the enum of each class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.