工厂模式动态创建例外

时间:2014-08-05 03:04:49

标签: java exception-handling factory-pattern

我创建了Exception xml并动态创建并抛出异常。

<exception-mappings>
<exception-mapping key="exceptionkey1">
    <class-name>com.package.CheckedException</class-name>
    <message>Checked Exception Message</message>
</exception-mapping>
<exception-mapping key="exceptionkey2">
    <class-name>com.package.UnCheckedException</class-name>
    <message>UnChecked Exception Message</message>
</exception-mapping>

我根据异常键使用反射动态创建异常对象。

public static void throwException(final String key) throws CheckedException, UncheckedException {
    ExceptionMapping exceptionMapping = exceptionMappings.getExceptionMappings().get(key);
    if (exceptionMapping != null) {
        try {
            Class exceptionClass = Class.forName(exceptionMapping.getClassName());
            try {
                throw ()exceptionClass.newInstance(); // line X
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

我想知道哪一个类在X行进行类型转换,这样我就不需要使用If / else了。背后的原因我不想使用if else,有可能在将来可能会添加新类,并且我不希望每次添加新异常时都更改此代码。

我的基本逻辑是我的服务层将抛出CheckedException或UncheckedException。如果抛出CheckedException,它将由我的Web层处理。此外,我不能抛出超级父类Exception或Throwable,因为我的web层只捕获CheckedException。如果抛出UncheckedException,它将显示异常页面。

请帮助我,因为我无法继续前进。

编辑:也接受任何其他解决方案。

6 个答案:

答案 0 :(得分:10)

嗯,以科学的名义,你可以做到这一点。我会建议这样做吗?绝不是。我自己会做这样的远程事吗?可能不是。

public class ExceptionFactory {
    public static void throwException(String className)
            throws CheckedException, UncheckedException {

        Class<?> exceptionClass;

        try {
            exceptionClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException(e);
        }

        try {
            if (CheckedException.class.isAssignableFrom(exceptionClass)) {
                throw exceptionClass.asSubclass(CheckedException.class)
                        .newInstance();
            } else if (UncheckedException.class
                    .isAssignableFrom(exceptionClass)) {
                throw exceptionClass.asSubclass(UncheckedException.class)
                        .newInstance();

            } else {
                throw new IllegalArgumentException(
                        "Not a valid exception type: "
                                + exceptionClass.getName());
            }
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

    public static void main(String... args) {
        try {
            throwException("CheckedException");
        } catch (CheckedException e) {
            System.out.println(e);
        } catch (UncheckedException e) {
            System.out.println(e);
        }
    }
}

class CheckedException extends Exception {
}

class UncheckedException extends Exception {
}

答案 1 :(得分:2)

我不明白这家工厂的意义。即使你让它工作(你可以通过将它抛出的所有异常作为单个祖先类的子类),它的用法将是这样的:

....
if (somethingInWrong) {
    ExceptionFactory.throwException("SomeKey");
}
....

对于每个键,您仍然需要创建要映射到它的异常类。让我们说SomeKeyException是映射到&#34; SomeKey&#34;。

的异常

在这种情况下,简单地写一下它的类型更安全:

....
if (somethingInWrong) {
    throw new SomeKeyException();
}
....

这样编译器会检查您是否正在创建它实际知道的异常类。如果您使用Factory,则可能会使用一些非有效键的String,并且编译器无法对其执行任何操作。只有在运行时,Factory才能找到映射到无效密钥的异常。

答案 2 :(得分:2)

一些调整:

public static void throwException(final String key) throws Throwable {
    ExceptionMapping exceptionMapping =
        exceptionMappings.getExceptionMappings().get(key);
    if (exceptionMapping != null) {
        try {
            Class<Throwable> exceptionClass = 
                (Class<Throwable>)Class.forName(exceptionMapping.getClassName());
            try {
               throw exceptionClass.cast( exceptionClass.newInstance() ); // line X
            } catch (InstantiationException e) {
               e.printStackTrace();
            } catch (IllegalAccessException e) {
               e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 }

答案 3 :(得分:1)

没有必要使用反射(正如我上面评论you shouldn't use reflection unless you really have to...)。

您可以将例外类实现为:

class MyExceptions {

    static void myExceptionsThrower(String key) throws Exception {
        if("illegalstate".equals(key)) {
            throw new IllegalStateException("that's my IllegalStateException bro!");
        }
        else if("illegalaccess".equals(key)) {
            throw new IllegalAccessException("that's my IllegalAccessException bro!");
        }
        // etc...
    }
}

并将其用于:

MyExceptions.myExceptionsThrower(key);

答案 4 :(得分:1)

这是我进入这场德比赛的进军。 : - )

其他答案评论这是否是一个合理的设计。为了这个答案的目的,我将这些问题放在一边。

我的几个小小的烦恼是不必要的警告(即使被压制),以及不报告实际出错的例外情况。特别是仅仅打印出堆栈迹线通常是不够的。是的,这只是测试代码,但在处理这样的代码时 - 即使是设计用于抛出异常的代码 - 实际上应该考虑如何处理错误。在这种情况下,我选择将这类错误表示为InternalError的实例,因为配置或任何可能以各种方式出错的情况。具体来说:如果找不到类,如果找到它但不是CheckedExceptionUncheckedException(或者甚至是普通类)的子类型,或者如果没有 - arg构造函数或者它是否无法访问。

一些建议的解决方案的另一个问题是,如果异常类名称是"java.lang.InstantiationException"(或其他内部捕获的异常之一),则可以构造,抛出此异常类型的实例,然后捕获在内部,导致堆栈跟踪但实际上没有抛出请求的异常。我通过线性化逻辑而不是嵌套try-catch块来避免这种情况。

最后,我将创建异常的代码解压缩到一个单独的方法中,以便它可以用于已检查和未检查的情况。如果重新排列异常层次结构以仅允许单个根异常(我建议取消选中)并且具有在Web层处理或被抛出给调用者的异常子类型,则可以大大简化这一过程。

static void throwException(final String exClassName) throws CheckedException, UncheckedException {
    Class<?> clazz;
    try {
        clazz = Class.forName(exClassName);
    } catch (ClassNotFoundException cnfe) {
        throw new InternalError(exClassName, cnfe);
    }

    if (CheckedException.class.isAssignableFrom(clazz)) {
        throw newException(clazz.asSubclass(CheckedException.class));
    } else if (UncheckedException.class.isAssignableFrom(clazz)) {
        throw newException(clazz.asSubclass(UncheckedException.class));
    } else {
        throw new InternalError(exClassName + " is not a valid exception");
    }
}

static <X extends Throwable> X newException(Class<X> clazz) {
    X x;
    try {
        x = clazz.newInstance();
    } catch (InstantiationException|IllegalAccessException e) {
        throw new InternalError("creating instance of " + clazz, e);
    }
    return x;
}

答案 5 :(得分:0)

这对于创建自定义前提条件例外以避免多个条件很有帮助。 在检查 null 指针时创建前提条件异常。

class Preconditions {
    /**
     * <p>
     *  Checks the value to be null and if null throws a new Exception with the message given.
     *  Used to reduce checking if conditions for complexity.
     * </p>
     * @param val - val to check null
     * @param exceptionClass - exception class to be thrown
     * @param args - message to be called for throwing exception
     * @throws Throwable - Common Throwable Exception.
     */
    public static void checkNotNull(final Object val, final Class<?>  exceptionClass, final Object ...args) throws Throwable {
        Class<?>[] argTypes = new Class<?>[args.length];
        Arrays.stream(args).map(WithIndex.indexed()).forEach(arg ->argTypes[arg.index()] = arg.value().getClass());
        if (null == val) throw (Throwable) exceptionClass.getConstructor(argTypes).newInstance(args);
    }

}

然后,您可以在以下代码中使用它:

    PreConditionUtil.checkNotNull(objectToCheck, CustomException.class, ErrorCode, "your error message", ...);
相关问题