2

I have tried to write a method that takes an error and returns it the same but with an exclamation mark added to the end of the message but there was a problem with the fact that the errors in java are immutable and because of limitations of generics its impossible to create new instance of error by using new T(e, message) :

public static <T extends Throwable> T withExclamationMark(T error) {
    return new T(error.getMessage() + "!", error);
}

Is there any simple solution which doesnt require reflection etc?

nick sigevsky
  • 37
  • 1
  • 5
  • 1
    `return`[`new Exception(cause.getMessage() + "!", cause)`](https://docs.oracle.com/javase/9/docs/api/java/lang/Exception.html#Exception-java.lang.String-java.lang.Throwable-). Although this will always return an `Exception`. Is an exclamation mark at the ent really that important/useful? Sounds like an [XY-problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Turing85 Jan 04 '18 at 14:50
  • what's wrong with reflection? – Maurice Perry Jan 04 '18 at 14:55
  • @MauricePerry Because [reflection is generally regarded as bad practice](https://stackoverflow.com/questions/36644349/is-using-java-reflection-bad-practice). I agree with the chosen answer: it is always good to look for a better solution before deploying reflection. – Turing85 Jan 04 '18 at 14:57
  • Do you know the specific type of the exception when you invoke this method? – fps Jan 04 '18 at 15:03
  • 1
    @Turing85 I also agree with that, but I see no other solution in this case. – Maurice Perry Jan 04 '18 at 15:04
  • Is there any way you can solve this in the proper place instead of altering a Throwable object ? Rather write out the exclamation point at the place where you log/display the error/exception. – nos Jan 04 '18 at 15:18

3 Answers3

1

You can do it with a BiFunction:

public static <T extends Throwable> T withExclamationMark(
        T error, 
        BiFunction<String, T, T> factory) {

    return factory.apply(error.getMessage() + "!", error);
}

Then, you can use this method as follows:

RuntimeException original = new RuntimeException("Message");

RuntimeException decorated = withExclamationMark(original, RuntimeException::new);

System.out.println(decorated.getMessage()); // Message!
fps
  • 33,623
  • 8
  • 55
  • 110
0
public static void main(String[] args) throws Exception {
    Throwable t = new Throwable("my message");
    Throwable t2 = withExclamationMark(t);
    t2.printStackTrace();
}

public static <T extends Throwable> T withExclamationMark(T error) 
             throws Exception {
    Constructor c = error.getClass().getConstructor(String.class, 
                                        Throwable.class);
    return (T) c.newInstance(error.getMessage() + "!", error);
}
sanit
  • 1,646
  • 1
  • 18
  • 21
0

If you want to aviod reflection at all costs, you will have to pay for this. The presented solution will sacrifice precision w.r.t. the type of the Throwable. To append something to the message, we will wrap the given Throwable in an Exception by deploying the constructor Exception(String, Throwable)

public static <T extends Throwable> Exception withExclamationMark(T t) {
    return new Excpetion(t.getMessage() + "!", t);
}

As I already mentioned, this method only returns instances of the class Exception, thus when you try to catch those Exceptions, you would have to check the cause:

try {
    ...
} catch (Exception e) { // let's assume you would normally catch an IOException here
    Exception cause = e.getCause();
    if ((cause != null) && (cause instanceof IOException) {
        IOException ioEx = ((IOExcpetion) cause);
        // handle excpetion
    } else {
        throw e; // or System.exit(42) or halt and catch fire or ...
    }
}

For a solution deploying reflection, please see @sanit's answer. Maybe a combination of both answers could lead to a satisfying solution.

Turing85
  • 18,217
  • 7
  • 33
  • 58