Toni T
Toni T

Reputation: 1

Getting Enum class from generic type?

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

Upvotes: 0

Views: 507

Answers (2)

Anonymous
Anonymous

Reputation: 86262

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.

Upvotes: 0

Holger
Holger

Reputation: 298143

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.

Upvotes: 1

Related Questions