Springer book downloader in Kotlin
It's not exact translation of your code, but still :) I've just tried!

Unfortunately, it's not a github project, so I don't have an access to the excel sheet, so I can't really run and test it. But, anyways, ideas are:


Utilization of toString() java method 
Using of lazy properties allows to 'cache' the URL easily. It's also possible because all of the Books properties are immutable.
Extension method download() doesn't really belong to a book, but, instead,
can easily download any URL
I used require(), though, it's not really correct, since it throws an exception, instead of gracefully exiting the app. I used it, just to demonstrate it, nothing more.


And, probably, something else. Please, tell me what you're thinking!

data class Book(
    val title: String,
    val author: String,
    val edition: String,
    val year: String,
    val category: String,
    val url: String
) {
    constructor(row: Row) : this(
        row.getCell(0).stringCellValue, row.getCell(1).stringCellValue,
        row.getCell(2).stringCellValue, row.getCell(4).numericCellValue.toString(),
        row.getCell(11).stringCellValue, row.getCell(18).stringCellValue
    )

    override fun toString() = "$title, $edition - $author"

    val downloadURL by lazy {
        val canonicalURL = Jsoup.connect(url).get().select("link[rel=canonical]").attr("href")
        val pdfRelativeURL =
            Jsoup.connect(canonicalURL).get().select("""a[href^="/content/pdf/"]""").attr("href")
        URL("https://link.springer.com${pdfRelativeURL}")
    }
}

fun URL.download(to: Path): Path {
    Files.createDirectories(to.parent)

    Channels.newChannel(openStream()).use { inChannel -&gt;
        FileOutputStream(to.toFile()).channel.use { outChannel -&gt;
            print("Saving $this to $to... ")
            outChannel.transferFrom(inChannel, 0, Long.MAX_VALUE)
            println("DONE.")
        }
    }

    return to
}

fun main(args: Array&lt;String&gt;) {
    require(args.size == 2) { "Please pass &lt;full_path_to_springer_excel_file&gt; and &lt;full_path_to_download_folder" }

    val (excelPath, downloadFolder) = args
    val excelFile = WorkbookFactory.create(File(excelPath))

    // drop(1): skip the first row because it contains the headers
    val books = excelFile.getSheetAt(0).drop(1).map { Book(it) }

    books.map { book -&gt;
        val path = Paths.get(downloadFolder, book.category, "$book.pdf")
        book.downloadURL.download(to = path)
    }
}
```