How can I create generic class, which inherits itself?


#1

How can I call newBuilder() method with the following logic (see RollingFileAppender for more details) ?

class RollingFileAppender {

    class Builder<B : Builder<B>> : AbstractOutputStreamAppender.Builder<B>(){
        fun build(): RollingFileAppender{ }
    }

    fun <B : Builder<B>> newBuilder(): B {
        return Builder<B>().asBuilder()
    }
}

In Java code I can just do this:

RollingFileAppender appender = RollingFileAppender.newBuilder()./*execute configuration here*/build();

Question: how can I do the same call in Kotlin? Compiler asks me to pass type into the newBuilder() method, however there are not any non-generic valid types here.


#2

Probably you doing something wrong… Class cannot inherits itself anyway even in Java. :slight_smile: And link you gave really doesn’t clarify more details.


#3

I full agree with you. There is popular library - log4j2. I’d like to configure logs programmatically.

However: what I missed? How can I create bulder of the appender?


#4

Unfortunately, this class has a very inconvenient constructor (static method, actually). Roughly, you can do the following:

class RollingFileAppenderBuilder : Builder<RollingFileAppender>
{
    var fileName: String? = null
    var filePattern: String? = null
    var append: String? = null
    var name: String? = null
    var bufferedIO: String? = null
    var bufferSizeStr: String? = null
    var immediateFlush: String? = null
    var policy: TriggeringPolicy? = null
    var strategy: RolloverStrategy? = null
    var layout: Layout<out Serializable>? = null
    var filter: Filter? = null
    var ignore: String? = null
    var advertise: String? = null
    var advertiseURI: String? = null
    var config: Configuration? = null

    override fun build(): RollingFileAppender {
        return RollingFileAppender.createAppender(
            fileName, filePattern, append, name, bufferedIO, bufferSizeStr, immediateFlush, policy, strategy, layout,
            filter, ignore, advertise, advertiseURI, config)
    }
}

val appender: RollingFileAppender = RollingFileAppenderBuilder().apply {
    fileName = "ffff"
    filePattern = "ppppp"
}.build()

And in fact, you don’t have to inherit from Builder here.


#5

This issue was already discussed here.