Converting List to Enumeration in Kotlin

August 15th, 2018

There’s a bunch of helper extension methods that the Kotlin standard library provides for working with collections. However, it would seem that at the present moment <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/java.util.-enumeration/index.html">java.util.Enumeration</a> has been left a bit behind. Here is a simple extension method to convert any List to a matching Enumeration:


/**
 * Extension function for converting a {@link List} to an {@link Enumeration}
 */
fun <T> List<T>.toEnumeration(): Enumeration<T> {
    return object : Enumeration<T> {
        var count = 0

        override fun hasMoreElements(): Boolean {
            return this.count < size
        }

        override fun nextElement(): T {
            if (this.count < size) {
                return get(this.count++)
            }
            throw NoSuchElementException("List enumeration asked for more elements than present")
        }
    }
}

And here is how you can use it to expose the local file system to the JTree component. First, we create a custom implementation of the TreeNode interface:


data class FileTreeNode(val file: File?, val children: Array<File>, val nodeParent: TreeNode?) : TreeNode {
    constructor(file: File, parent: TreeNode) : this(file, file.listFiles() ?: arrayOf(), parent)
    constructor(children: Array<File>) : this(null, children, null)

    init {
        children.sortWith(compareBy { it.name.toLowerCase() })
    }

    override fun children(): Enumeration<FileTreeNode> {
        return children.map { FileTreeNode(it, this) }.toEnumeration()
    }

    override fun getAllowsChildren(): Boolean {
        return true
    }

    override fun getChildAt(childIndex: Int): TreeNode {
        return FileTreeNode(children[childIndex], this)
    }

    override fun getChildCount(): Int {
        return children.size
    }

    override fun getIndex(node: TreeNode): Int {
        val ftn = node as FileTreeNode
        return children.indexOfFirst { it == ftn.file }
    }

    override fun getParent(): TreeNode? {
        return this.nodeParent
    }

    override fun isLeaf(): Boolean {
        val isNotFolder = (this.file != null) && (this.file.isFile)
        return this.childCount == 0 && isNotFolder
    }
}

Note a few language shortcuts that make the code more concise than its Java counterparts:

  • Since File.listFiles() can return null, we wrap that call with a simple Elvis operator: file.listFiles() ?: arrayOf().
  • The initializer block sorts the File children in place by name.
  • To return tree node enumeration in children(), we first map each File child to the corresponding FileTreeNode and then use our extension function to convert the resulting List to Enumeration.
  • Looking up the index of the specific node is done with the existing extension indexOfFirst function from the standard library.

Now all is left to do is to create our JTree:


val tree = JTree(FileTreeNode(File.listRoots()))
tree.rootVisible = false