Question
Convert a Kotlin Array to Java varargs: Passing Arrays to Java Methods from Kotlin
Question
I have a Kotlin array of strings and I want to pass it to a Java method that accepts varargs (which appears as String... in Java and String[] in interop). For example:
val angularRoutings = arrayOf("/language", "/home")
// This does not work
web.ignoring().antMatchers(angularRoutings)
How do I correctly pass a Kotlin Array<String> to a Java varargs parameter?
Also, if I have an ArrayList<String>, how can I pass that to a varargs method parameter in Kotlin?
Short Answer
By the end of this page, you will understand how Kotlin handles Java varargs, why passing an array directly often fails, and how to use the spread operator (*) to expand a Kotlin array into individual arguments. You will also learn how to convert lists such as ArrayList<String> into arrays before passing them to Java varargs methods.
Concept
In Java, a method with varargs looks like this:
void antMatchers(String... patterns)
Java treats String... as a special syntax for “zero or more String values.” Internally, it is handled as a String[].
When Kotlin calls a Java varargs method, Kotlin does not automatically unpack an Array<String> into separate arguments. Instead, you usually need to explicitly tell Kotlin to spread the array into individual values.
That is what the * spread operator does.
web.ignoring().antMatchers(*angularRoutings)
This matters because Kotlin and Java interoperate closely, but their function call rules are not identical. If you regularly work with Java libraries from Kotlin, especially frameworks like Spring, Android APIs, or older utility libraries, you will often need to pass arrays or collections into Java varargs methods correctly.
For collections like ArrayList<String>, you cannot spread the list directly. A varargs parameter expects individual values, so you must first convert the list to an array:
val routes = arrayListOf("/language", "/home")
web.ignoring().antMatchers(*routes.toTypedArray())
So the key idea is:
Array<String>-> use*arrayList<String>orArrayList<String>-> use*list.toTypedArray()
Mental Model
Think of a varargs method like a function that wants several separate items placed on a table:
- Java varargs: “Put each string on the table one by one.”
- Kotlin array: “Here is a box containing strings.”
If you hand over the box directly, the method may not treat it as separate items.
The spread operator * means:
“Open the box and place each item on the table individually.”
If you have a list instead of an array, you first need to pack it into the right kind of box (Array<String>) and then open it with *.
Syntax and Examples
Core syntax
Passing individual values
web.ignoring().antMatchers("/language", "/home")
Passing a Kotlin array to Java varargs
val angularRoutings = arrayOf("/language", "/home")
web.ignoring().antMatchers(*angularRoutings)
Passing an ArrayList<String> or List<String>
val routes = arrayListOf("/language", "/home")
web.ignoring().antMatchers(*routes.toTypedArray())
Why * is needed
Without the spread operator:
val angularRoutings = arrayOf("/language", "/home")
web.ignoring().antMatchers(angularRoutings) // usually does not match the varargs call you expect
With the spread operator:
val angularRoutings = arrayOf("/language", "/home")
web.ignoring().antMatchers(*angularRoutings)
Kotlin now expands the array so the Java method receives it as if you had written:
web.ignoring().antMatchers("/language", "/home")
Example with your case
val angularRoutings = arrayOf("/language", "/home")
web.ignoring().antMatchers(*angularRoutings)
This is the correct way to pass the array.
Step by Step Execution
Consider this example:
val routes = arrayOf("/language", "/home")
web.ignoring().antMatchers(*routes)
Step by step:
arrayOf("/language", "/home")creates a KotlinArray<String>.routesnow holds two strings.antMatchers(...)is a Java method that expects varargs, meaning multipleStringarguments.*routestells Kotlin to spread the array.- Kotlin effectively turns the call into:
web.ignoring().antMatchers("/language", "/home")
- The Java method receives the values as its varargs parameter.
Now compare with a list:
val routes = arrayListOf("/language", "/home")
web.ignoring().antMatchers(*routes.toTypedArray())
Step by step:
arrayListOf(...)creates anArrayList<String>.- A list is not the same as
Array<String>. toTypedArray()converts the list into anArray<String>.*spreads that array into separate arguments.- The Java varargs method receives the strings correctly.
Real World Use Cases
This pattern appears often when Kotlin code calls Java libraries.
Common scenarios
- Spring Security: passing URL patterns into methods like
antMatchers(...) - Logging frameworks: passing multiple formatting arguments
- Android APIs: calling Java methods that accept variable numbers of values
- Testing libraries: passing multiple expected values or parameters
- Utility libraries: methods like
of(...),addAll(...), or matcher-style APIs
Example: route configuration
val publicRoutes = arrayOf("/login", "/register", "/about")
web.ignoring().antMatchers(*publicRoutes)
Example: dynamic values from configuration
val configuredRoutes = listOf("/health", "/metrics")
web.ignoring().antMatchers(*configuredRoutes.toTypedArray())
This is useful when the values are not hardcoded and come from files, databases, or application settings.
Real Codebase Usage
In real projects, developers often combine varargs calls with collection building, validation, and configuration.
Common patterns
1. Build a list, then convert once
If your values are dynamic, it is common to collect them in a list and convert at the call site.
val routes = mutableListOf("/home")
if (enableLanguagePage) {
routes.add("/language")
}
web.ignoring().antMatchers(*routes.toTypedArray())
2. Guard against empty collections
val routes = getRoutesFromConfig()
if (routes.isNotEmpty()) {
web.ignoring().antMatchers(*routes.toTypedArray())
}
3. Keep interop code local
A common style is to keep Java interop details near the boundary of the library call.
fun ignoreRoutes(web: WebSecurity, routes: List<String>) {
web.ignoring().antMatchers(*routes.toTypedArray())
}
This keeps the rest of your Kotlin code clean and collection-friendly.
4. Prefer readable data preparation
val publicEndpoints = listOf(
"/login",
"/signup",
"/status"
)
web.ignoring().antMatchers(*publicEndpoints.toTypedArray())
This is often clearer than manually repeating many string arguments.
Common Mistakes
1. Forgetting the spread operator
Broken:
val routes = arrayOf("/language", "/home")
web.ignoring().antMatchers(routes)
Fix:
web.ignoring().antMatchers(*routes)
2. Trying to spread a list directly
Broken:
val routes = listOf("/language", "/home")
web.ignoring().antMatchers(*routes)
A List<String> is not an Array<String>.
Fix:
web.ignoring().antMatchers(*routes.toTypedArray())
3. Confusing Java arrays and Kotlin collections
A Kotlin Array<String> and a List<String> are different types with different behaviors.
- Use
Array<String>when you need array-based interop. - Use
List<String>for most regular Kotlin collection work.
4. Assuming varargs always accept collections
Varargs methods accept a variable number of arguments, not arbitrary collection types. Collections often need conversion first.
5. Using primitive arrays incorrectly
For non-String cases, remember that primitive arrays like IntArray are different from Array<Int>. Some APIs require one form specifically.
Example:
val numbers = intArrayOf(1, 2, 3)
This is not the same as:
val numbers = arrayOf(1, 2, 3)
This matters when working with Java interop.
Comparisons
Array vs List when calling Java varargs
| Kotlin type | Can be passed directly to Java varargs? | What to do |
|---|---|---|
Array<String> | No, not usually as expanded args | Use *array |
List<String> | No | Convert with toTypedArray() then use * |
ArrayList<String> | No | Convert with toTypedArray() then use * |
| Individual strings | Yes | Pass normally |
Direct arguments vs spread array
| Style | Example | When to use |
|---|---|---|
| Direct arguments | antMatchers("/a", "/b") | When values are known at the call site |
| Spread array | antMatchers(*routes) | When values are already in an array |
| List converted to array | antMatchers(*routes.toTypedArray()) | When values come from a list or ArrayList |
Array<String> vs ArrayList<String>
| Type | Best use |
|---|---|
Array<String> | Fixed-size grouped values, Java interop |
ArrayList<String> | Dynamic add/remove operations |
In Kotlin, lists are generally more common in application code, but arrays are often needed when interfacing with Java APIs.
Cheat Sheet
// Java method
// void antMatchers(String... patterns)
// Pass direct values
antMatchers("/language", "/home")
// Pass Kotlin array
val routes = arrayOf("/language", "/home")
antMatchers(*routes)
// Pass List or ArrayList
val routes = listOf("/language", "/home")
antMatchers(*routes.toTypedArray())
Rules
- Java
String...becomes a varargs call from Kotlin. - Use
*to spread a Kotlin array into varargs. - You cannot spread a
Listdirectly. - Convert a list with
toTypedArray()first. Array<String>andList<String>are not interchangeable.
Quick fixes
- Have
Array<String>? ->*array - Have
List<String>? ->*list.toTypedArray() - Have
ArrayList<String>? ->*arrayList.toTypedArray()
FAQ
Why does antMatchers(array) fail in Kotlin?
Because Kotlin does not automatically expand the array into separate varargs arguments. Use *array.
How do I pass a Kotlin list to a Java varargs method?
Convert it first: *myList.toTypedArray().
What does the * operator mean in Kotlin?
It is the spread operator. It expands an array into individual arguments for a varargs parameter.
Can I use ArrayList<String> directly with varargs?
No. Convert it to an array first with toTypedArray().
Is Java String... the same as String[]?
Internally, yes. varargs is compiled as an array, but the call syntax is more flexible.
Should I use arrays or lists in Kotlin?
Use lists for most Kotlin code. Use arrays mainly when an API specifically requires them, such as Java varargs interop.
Mini Project
Description
Create a small Kotlin utility that configures public URL routes for a Java-style API that accepts varargs. This demonstrates the exact skill of converting Kotlin arrays and lists into arguments that a Java library can consume.
Goal
Build a function that accepts route values from both an array and a list, then passes them correctly to a varargs-style method.
Requirements
- Create a Kotlin function that simulates a Java varargs method.
- Store route paths in both an
Array<String>and aList<String>. - Pass the array using the spread operator.
- Convert the list to an array before spreading it.
- Print the received routes to confirm the values were passed correctly.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.