Skip to content

[kotlinify] Kotlinify BaseJavaModule #51207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

l2hyunwoo
Copy link
Contributor

@l2hyunwoo l2hyunwoo commented May 9, 2025

Summary:

Issues from #50513

Migrate BaseJavaModule.java from Java to Kotlin

Discussion

I think it's also possible to call getReactApplicationContext as a property getter of reactApplicationContext rather than as a function call, and I believe that writing it this way preserves the unique syntax of Kotlin. What do you think?
If it sounds, I'll make other PR to use property getter of non-nullable ReactApplicationContext

AS-IS

@Nullsafe(Nullsafe.Mode.LOCAL)
@StableReactNativeAPI
public abstract class BaseJavaModule(
  private val reactApplicationContext: ReactApplicationContext? = null
) : NativeModule {
  // ....
  protected fun getReactApplicationContext(): ReactApplicationContext =
    requireNotNull(reactApplicationContext) {
      "Tried to get ReactApplicationContext even though NativeModule wasn't instantiated with one"
    }
}

TO-BE

@Nullsafe(Nullsafe.Mode.LOCAL)
@StableReactNativeAPI
public abstract class BaseJavaModule(
  private val _reactApplicationContext: ReactApplicationContext? = null
) : NativeModule {
  protected val reactApplicationContext: ReactApplicationContext
    get() = requireNotNull(reactApplicationContext) {
      "Tried to get ReactApplicationContext even though NativeModule wasn't instantiated with one"
    }
}

Changelog:

[ANDROID] [CHANGED] Migrate BaseJavaModule from Java to Kotlin

Test Plan:

yarn android
yarn test-android

yarn android

스크린샷 2025-05-10 오전 12 22 39

yarn test-android

스크린샷 2025-05-10 오전 12 24 42

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels May 9, 2025
@l2hyunwoo l2hyunwoo force-pushed the feature/kotlinfy-basejavamodule branch 2 times, most recently from eeb882e to bac454f Compare May 9, 2025 03:24
@l2hyunwoo l2hyunwoo marked this pull request as draft May 9, 2025 03:33
@l2hyunwoo l2hyunwoo force-pushed the feature/kotlinfy-basejavamodule branch from bac454f to 50b5f1e Compare May 9, 2025 05:38
@l2hyunwoo l2hyunwoo marked this pull request as ready for review May 9, 2025 05:39
@l2hyunwoo l2hyunwoo force-pushed the feature/kotlinfy-basejavamodule branch 2 times, most recently from fea09af to 3193c7b Compare May 9, 2025 10:30
@l2hyunwoo
Copy link
Contributor Author

w: file:///__w/react-native/react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt:242:35 This synthetic property is based on the getter function 'fun getReactApplicationContextIfActiveOrWarn(): ReactApplicationContext?' from Kotlin. In the future, synthetic properties will be available only if the base getter function came from Java. Consider replacing this property access with a 'getReactApplicationContextIfActiveOrWarn()' function call.
w: file:///__w/react-native/react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt:249:5 This synthetic property is based on the getter function 'fun getReactApplicationContext(): ReactApplicationContext' from Kotlin. In the future, synthetic properties will be available only if the base getter function came from Java. Consider replacing this property access with a 'getReactApplicationContext()' function call.
w: file:///__w/react-native/react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt:362:39 This synthetic property is based on the getter function 'fun getReactApplicationContextIfActiveOrWarn(): ReactApplicationContext?' from Kotlin. In the future, synthetic properties will be available only if the base getter function came from Java. Consider replacing this property access with a 'getReactApplicationContextIfActiveOrWarn()' function call.
w: file:///__w/react-native/react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt:445:35 This synthetic property is based on the getter function 'fun getReactApplicationContextIfActiveOrWarn(): ReactApplicationContext?' from Kotlin. In the future, synthetic properties will be available only if the base getter function came from Java. Consider replacing this property access with a 'getReactApplicationContextIfActiveOrWarn()' function call.

It should be fixed on other commit

@l2hyunwoo l2hyunwoo force-pushed the feature/kotlinfy-basejavamodule branch 3 times, most recently from 9f59aee to 1df590a Compare May 9, 2025 15:37
Copy link
Collaborator

@mateoguzmana mateoguzmana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for migrating this file!

Could you please remove any change that is not related to the migration of the file itself? It will make it easier for us to review and analyse whether the migration has potential breaking changes in the ecosystem.

@@ -32,15 +32,15 @@ internal class ToastModule(reactContext: ReactApplicationContext) :
override fun show(message: String?, durationDouble: Double) {
val duration = durationDouble.toInt()
UiThreadUtil.runOnUiThread {
Toast.makeText(getReactApplicationContext(), message, duration).show()
Toast.makeText(reactApplicationContext, message, duration).show()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes related to the migration? If not, let's please take them out – preferably you could send them over in a separate PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apply your code review! Thanks for review it.

@l2hyunwoo l2hyunwoo force-pushed the feature/kotlinfy-basejavamodule branch 5 times, most recently from 4a40e10 to 86ac511 Compare May 11, 2025 04:29
Copy link
Collaborator

@mateoguzmana mateoguzmana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the other comments! I have some concerns about the breaking changes this might introduce.

I have an example of a file that maintains backwards compatibility, perhaps we can try something like that in this case: InteropEvent.kt

@@ -17,6 +17,7 @@ import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.module.annotations.ReactModule

/** Module that exposes the user's preferred color scheme. */
@Suppress("SYNTHETIC_PROPERTY_WITHOUT_JAVA_ORIGIN")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need these suppressions?

@@ -41,19 +41,19 @@ public NativeSampleTurboModuleSpec(ReactApplicationContext reactContext) {
}

protected final void emitOnPress() {
mEventEmitterCallback.invoke("onPress");
getEventEmitterCallback().invoke("onPress");
Copy link
Collaborator

@mateoguzmana mateoguzmana May 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally when we have to do these changes after a migration, it indicates it is a breaking change. I've checked and this specific property is used in other open source packages: See

Could you try to find a way to maintain backwards compatibility? we might have to expose a getter separately, but leaving the property with the same name so it can also be accessed like the change you did here

@@ -109,7 +109,7 @@ internal class JavaModuleWrapper(
val baseJavaModule = module

Systrace.beginSection(TRACE_TAG_REACT, "module.getConstants")
val map = baseJavaModule.constants
val map = baseJavaModule.getConstants()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar here, we would need to find a way to maintain the access to the constants backwards compatible

@DoNotStrip
protected void setEventEmitterCallback(CxxCallbackImpl eventEmitterCallback) {
mEventEmitterCallback = eventEmitterCallback;
public companion object {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: let's try to leave the original reference from where the strings where taken from

Suggested change
public companion object {
public companion object {
// taken from Libraries/Utilities/MessageQueue.js

@l2hyunwoo l2hyunwoo force-pushed the feature/kotlinfy-basejavamodule branch from 86ac511 to e390cdc Compare May 15, 2025 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants