Question
I defined an extension function in a Kotlin file and want to call it from Java code.
Here is the Kotlin code:
package com.test.extensions
import com.test.model.MyModel
fun MyModel.bar(): Int {
return this.name.length
}
MyModel is a generated Java class. I then tried to call the extension function from Java like this:
MyModel model = new MyModel();
model.bar();
However, this does not work. The IDE does not recognize bar() as a method on MyModel, and compilation fails.
A normal top-level Kotlin function does work from Java. For example:
fun bar(): Int {
return 2 * 2;
}
and I can access it from Java through the generated class for the Kotlin file.
So what am I doing wrong? Is it possible to access Kotlin extension functions from Java, and if so, how should they be called?
Short Answer
By the end of this page, you will understand why Kotlin extension functions do not appear as real instance methods in Java, how Kotlin compiles them, and the correct way to call them from Java using the generated class and a static method call.
Concept
Kotlin extension functions let you write code that looks like you are adding a new method to an existing class:
fun MyModel.bar(): Int = this.name.length
In Kotlin, this can be called like:
val result = model.bar()
That syntax is convenient, but it is important to understand what extension functions really are.
Extension functions do not modify the class
An extension function does not actually add a method to MyModel. It is only a Kotlin language feature. Under the hood, Kotlin compiles that function into a static function.
So this Kotlin code:
fun MyModel.bar(): Int = this.name.length
is compiled to something conceptually like this for Java:
public static int bar(MyModel receiver) {
return receiver.getName().length();
}
That is why Java cannot do this:
model.bar();
Java only sees the real methods that belong to MyModel. Since bar() was never added to the MyModel class, Java has no such instance method to call.
Why this matters
This matters because Kotlin and Java interoperate closely, but not every Kotlin feature maps to Java syntax in the same way. Extension functions are a good example:
- In Kotlin, they look like instance methods.
- In Java, they are just static utility methods.
Understanding this helps you:
- call Kotlin code correctly from Java
- avoid confusing IDE and compiler errors
- design mixed Kotlin/Java projects more clearly
How Java should call them
If your Kotlin file is named Extensions.kt, Java will usually access the generated static method through a generated class named after the file:
import com.test.extensions.ExtensionsKt;
MyModel model = new MyModel();
int result = ExtensionsKt.bar(model);
In older Kotlin examples or tooling, you may see names like ExtensionsPackage, but in modern Kotlin the default generated class name is usually based on the file name plus Kt.
You can also customize that generated class name with @file:JvmName(...) if needed.
Mental Model
Think of an extension function like a helper tool placed next to an object, not a new part installed inside the object.
model.bar()in Kotlin is like saying, "use the helper tool as if it belongs tomodel"- In reality, the tool lives outside the object
- Java only sees the actual object and its real methods, not Kotlin's syntactic shortcut
So Kotlin gives you a friendly shortcut:
model.bar()
But Java sees the real form:
ExtensionsKt.bar(model)
A useful analogy:
- Real method: a button built into a machine
- Extension function: a remote control that works with the machine
Kotlin lets the remote feel like a built-in button. Java does not.
Syntax and Examples
Core syntax in Kotlin
An extension function is declared by writing the target type before the function name:
fun TypeName.functionName(): ReturnType {
// use this to refer to the receiver object
}
Example:
fun String.firstChar(): Char {
return this[0]
}
Used in Kotlin:
val letter = "Hello".firstChar()
println(letter) // H
Your example
Kotlin:
package com.test.extensions
import com.test.model.MyModel
fun MyModel.bar(): Int {
return this.name.length
}
If the file is named Extensions.kt, Java calls it like this:
import com.test.extensions.ExtensionsKt;
import com.test.model.MyModel;
public class Main {
public static void main(String[] args) {
MyModel model = new MyModel();
int result = ExtensionsKt.bar(model);
System.out.println(result);
}
}
Cleaner Java name with @file:JvmName
You can choose a nicer generated class name for Java:
@file:JvmName("MyModelExtensions")
package com.test.extensions
import com.test.model.MyModel
fun MyModel.bar(): Int = this.name.length
Then Java can call:
import com.test.extensions.MyModelExtensions;
MyModel model = new MyModel();
int result = MyModelExtensions.bar(model);
Another example with nullable safety
Kotlin:
fun String?.safeLength(): Int {
return this?.length ?: 0
}
Kotlin usage:
val a: String? = null
println(a.safeLength()) // 0
Java usage:
int len = StringsKt.safeLength(null);
This again shows that Java calls the extension as a static function.
Step by Step Execution
Consider this Kotlin file Extensions.kt:
package com.test.extensions
import com.test.model.MyModel
fun MyModel.bar(): Int {
return this.name.length
}
And this Java code:
import com.test.extensions.ExtensionsKt;
import com.test.model.MyModel;
MyModel model = new MyModel();
int result = ExtensionsKt.bar(model);
What happens step by step
1. Kotlin compiles the extension function
Kotlin does not insert bar() into the MyModel class.
Instead, it generates something equivalent to a static method in a helper class:
public final class ExtensionsKt {
public static int bar(MyModel receiver) {
return receiver.getName().length();
}
}
2. Java creates the object
MyModel model = new MyModel();
At this point, model is just a normal Java object. It only has the methods defined in MyModel itself.
3. Java calls the generated static method
int result = ExtensionsKt.bar(model);
Here, model is passed as the first argument. That argument is the Kotlin extension receiver.
4. Inside the function
In Kotlin, this refers to the receiver object:
return this.name.length
So if model.name is "Alice", then:
this.nameis"Alice"this.name.lengthis5- the function returns
5
Why model.bar() fails in Java
Because Java checks the real methods on the MyModel class. Since bar() is not actually defined there, Java reports an error.
Real World Use Cases
Extension functions are commonly used in Kotlin-heavy codebases, even when Java is also present.
Practical uses
Formatting domain objects
fun MyModel.displayName(): String = "User: ${this.name}"
Useful for UI code, logging, and debugging.
Validation helpers
fun MyModel.hasValidName(): Boolean = this.name.isNotBlank()
Useful before saving data or sending API requests.
Conversion helpers
fun MyModel.toDto(): MyDto = MyDto(this.name)
Useful when converting between database objects, API models, and UI models.
Collection convenience
fun List<MyModel>.names(): List<String> = this.map { it.name }
Useful in business logic and reporting.
Framework helper functions
Extensions are often used to make libraries feel easier to use in Kotlin, for example with:
- Android views
- database query helpers
- HTTP request helpers
- testing utilities
In mixed Java/Kotlin projects
If Java also needs the functionality, teams often decide whether:
- the extension should remain Kotlin-only for convenience, or
- a regular utility/static method should be exposed clearly for both languages
Real Codebase Usage
In real projects, developers often use extension functions as readable helper APIs around existing classes.
Common patterns
Validation helpers
fun MyModel.requireName() {
require(this.name.isNotBlank()) { "Name must not be blank" }
}
This keeps validation logic close to the type it works with.
Mapping and transformation
fun MyModel.toApiModel(): ApiModel {
return ApiModel(name = this.name)
}
This is very common in layered applications.
Guard-style helpers
fun MyModel.isReady(): Boolean = this.name.isNotBlank()
Used before running business logic.
Null-safe utility extensions
fun MyModel?.orDefaultName(): String = this?.name ?: "Unknown"
Useful when working with optional data.
In Java-facing code
When a project contains both Kotlin and Java, teams usually follow one of these approaches:
- Use extension functions mainly in Kotlin code for readability.
- Call them from Java as static methods when needed.
- Add
@file:JvmName("...")to make Java calls clearer. - Prefer regular utility classes if the code is mostly Java.
Design tip
If a helper must feel natural in Java too, an ordinary static utility method may be easier to discover than a Kotlin extension. If the project is mostly Kotlin, extension functions are often the better ergonomic choice.
Common Mistakes
1. Expecting the extension to become a real Java method
Broken expectation:
MyModel model = new MyModel();
model.bar(); // Error
Why it fails:
bar()is not actually added toMyModel- Java only sees real members of the class
Correct usage:
int result = ExtensionsKt.bar(model);
2. Forgetting the generated class name
Beginners often try to import the package instead of the generated class.
Correct form usually depends on the Kotlin file name.
If the file is Extensions.kt, use:
import com.test.extensions.ExtensionsKt;
Then call:
ExtensionsKt.bar(model);
3. Confusing top-level functions and extension functions
These are both compiled as static methods, but extension functions take the receiver as a parameter.
Kotlin:
fun bar(): Int = 4
fun MyModel.bar(): Int = this.name.length
Java sees something like:
ExtensionsKt.bar();
ExtensionsKt.bar(model);
4. Using Kotlin syntax that does not match Java accessors
For Java classes, Kotlin properties often map to getters and setters.
Kotlin:
fun MyModel.bar(): Int = this.name.length
This usually means Kotlin is calling getName() under the hood.
Be careful if the Java class does not expose the property the way you expect.
5. Not handling null values
Broken code:
fun MyModel.bar(): Int = this.name.length
If name can be null in the Java class, this may fail at runtime.
Safer version:
fun MyModel.bar(): Int = this.name?.length ?: 0
Only use this if name is actually nullable from Kotlin's point of view.
6. Assuming extension dispatch is polymorphic
Extension functions are resolved statically, not like overridden member methods.
That means the chosen extension depends on the compile-time type, not the runtime subtype. This surprises many learners.
Comparisons
| Concept | Kotlin Call Style | Java Call Style | Is it a real member of the class? |
|---|---|---|---|
| Member function | model.realMethod() | model.realMethod() | Yes |
| Extension function | model.bar() | ExtensionsKt.bar(model) | No |
| Top-level function | bar() | ExtensionsKt.bar() | No |
| Static Java utility method | Utils.bar(model) | Utils.bar(model) | No |
Extension function vs member function
| Feature | Extension Function | Member Function |
|---|---|---|
| Defined inside the class | No | Yes |
| Can access private members | No | Yes |
| Callable as instance method in Kotlin | Yes | Yes |
| Callable as instance method in Java | No | Yes |
| Actually changes the class API | No | Yes |
Extension function vs utility method
They are very similar under the hood.
- An extension function gives nicer syntax in Kotlin.
- A utility method is more obvious in Java.
If Kotlin is the main language, extension functions improve readability. If Java is the main language, utility methods may be simpler.
Cheat Sheet
Quick reference
Declare an extension function
fun MyModel.bar(): Int = this.name.length
Call it in Kotlin
val result = model.bar()
Call it in Java
If the file is Extensions.kt:
int result = ExtensionsKt.bar(model);
Important rule
Extension functions are not real class methods. They are compiled as static functions.
Generated class name
Usually:
Extensions.kt->ExtensionsKtStrings.kt->StringsKt
Customize Java class name
@file:JvmName("MyExtensions")
Then Java calls:
MyExtensions.bar(model);
Receiver becomes a parameter
Kotlin:
fun MyModel.bar(): Int
Java view:
static int bar(MyModel model)
Common error
model.bar(); // Does not work in Java
Good use cases
- formatting
- validation
- mapping
- convenience helpers
Watch out for
- nullability from Java classes
- generated class naming
- assuming extensions modify the original class
FAQ
Can Java call Kotlin extension functions?
Yes. Java can call them as static methods on the generated class for the Kotlin file.
Why does model.bar() not work in Java?
Because bar() is not actually added to the MyModel class. It is compiled as a static helper function.
What class name should Java import?
Usually the Kotlin file name plus Kt, such as ExtensionsKt for Extensions.kt.
Can I make the generated Java class name nicer?
Yes. Use @file:JvmName("DesiredName") at the top of the Kotlin file.
Are extension functions the same as Java static utility methods?
Under the hood, they are very similar. The main difference is that Kotlin lets you call them with instance-like syntax.
Do extension functions override class methods?
No. Real member methods always take priority over extensions.
Can extension functions access private fields of the class?
No. They only have access to public or otherwise visible members.
Should I use extensions in a Java-heavy project?
You can, but if Java is the main consumer, regular utility methods may be easier for the team to read and discover.
Mini Project
Description
Create a small Kotlin utility file with extension functions for a Java model class, then call those functions correctly from Java. This project demonstrates the key idea that extension functions improve Kotlin syntax but are still static methods from Java's point of view.
Goal
Build and use Kotlin extension functions on a Java class, then call them from Java with the correct generated helper class.
Requirements
- Create a Java class named
MyModelwith anamefield and getter/setter. - Create a Kotlin file containing at least two extension functions for
MyModel. - Call both extension functions from Java using the generated class name or a custom
@file:JvmName. - Print the results from Java to verify everything works.
Keep learning
Related questions
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.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.