92

I am in the processing of learning Kotlin and ran into a problem I couldn't figure out. I would like to extend the Java class RuntimeException in Kotlin and be able to use any one of three of its constructors, in different circumstances (based on what info I have at the time I want to throw an exception). In java my class would look like this:

public class PhotoLibException extends RuntimeException {

    public PhotoLibException(String message, RuntimeException ex) {
        super(message, ex);
    }

    public PhotoLibException(String message) {
        super(message);
    }

    public PhotoLibException(RuntimeException ex) {
        super(ex);
    }
}

When I try to do this in Kotlin, I used this answer as a guide: Kotlin secondary constructor however, I had a problem trying to figure out how to invoke the appropriate super constructor correctly. For example, using functions seemed to be a good approach, like this:

fun PhotoLibException(message: String): PhotoLibException {
    val ex = null
    return PhotoLibException(message, ex)
}

fun PhotoLibException(ex: Exception): PhotoLibException {
    val message = ""
    return PhotoLibException(message, ex)
}

class PhotoLibException(message: String, ex: Exception?): RuntimeException(message, ex) {
}

However, in this Kotlin example above, I am always invoking the super constructor with two args, and not invoking the constructor most appropriate to the situation. So what I have above works, but doesn't do exactly what it would do in Java where a different constructor is invoked in each situation. I also tried instantiating a new RuntimeException inside each fun above and casting it to PhotoLibException, but I wasn't allowed to do that.

Can anyone suggest how I would do this correctly in Kotlin?

iknow
  • 8,358
  • 12
  • 41
  • 68
Steve Moseley
  • 5,797
  • 2
  • 19
  • 22

2 Answers2

177

Update: Since M11 (0.11.*), you can use secondary constructors to solve this problem:

class PhotoLibException : RuntimeException {
    constructor(message: String, ex: Exception?): super(message, ex) {}
    constructor(message: String): super(message) {}
    constructor(ex: Exception): super(ex) {}
}

Currently, there's no way to call different super-constructors in different context from the same class. It will be supported in the upcoming months, though.

Andrey Breslav
  • 24,795
  • 10
  • 66
  • 61
  • 1
    Hi, does this solution hold good even today (as of kotlin 1.2.41)? I know it works but are there even simpler alternatives? – Rakesh N May 24 '18 at 13:40
  • 1
    @Andrey Breslav How would I add a property to this? I.e. Say some boolean which is only PhotoLibException field passed in via constructor – urSus Jun 13 '18 at 20:48
  • Make sure your not initialising the any of the parent constructor on the same line as declaring the child class. Eg "class Child : Parent (- don't do this initialisation here-) " – Niroshan Jun 26 '18 at 09:22
  • Note that this only works if the class doesn't have a primary constructor - all constructors have to be "secondary". That's probably what @Niroshan meant. – Jorn Jun 16 '22 at 15:34
5

Use the @JvmOverloads annotation.

class PhotoLibException: RuntimeException {
   @JvmOverloads constructor(message: String, ex: Exception?)
}
Brill Pappin
  • 4,692
  • 1
  • 36
  • 36