Reputation: 1
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
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
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