Skip to content

Commit

Permalink
Convert com.facebook.react.uimanager.ViewManagerPropertyUpdater to Ko…
Browse files Browse the repository at this point in the history
…tlin (#48658)

Summary:
Pull Request resolved: #48658

Migrate to Kotlin before I make further changes to this. Generics are really tricky due to our previous usage of raw generics on the Java side, but were worked around by some combination of unchecked cast and `Nothing`

Changelog: [Internal]

Reviewed By: mdvacca, rshest

Differential Revision: D68102210
  • Loading branch information
javache authored and facebook-github-bot committed Jan 15, 2025
1 parent 559d070 commit fe8370b
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 179 deletions.
14 changes: 7 additions & 7 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -5240,13 +5240,13 @@ public abstract interface class com/facebook/react/uimanager/ViewManagerDelegate
public fun setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
}

public class com/facebook/react/uimanager/ViewManagerPropertyUpdater {
public fun <init> ()V
public static fun clear ()V
public static fun getNativeProps (Ljava/lang/Class;Ljava/lang/Class;)Ljava/util/Map;
public static fun updateProps (Lcom/facebook/react/uimanager/ReactShadowNode;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public static fun updateProps (Lcom/facebook/react/uimanager/ViewManager;Landroid/view/View;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public static fun updateProps (Lcom/facebook/react/uimanager/ViewManagerDelegate;Landroid/view/View;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public final class com/facebook/react/uimanager/ViewManagerPropertyUpdater {
public static final field INSTANCE Lcom/facebook/react/uimanager/ViewManagerPropertyUpdater;
public static final fun clear ()V
public static final fun getNativeProps (Ljava/lang/Class;Ljava/lang/Class;)Ljava/util/Map;
public static final fun updateProps (Lcom/facebook/react/uimanager/ReactShadowNode;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public static final fun updateProps (Lcom/facebook/react/uimanager/ViewManager;Landroid/view/View;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public static final fun updateProps (Lcom/facebook/react/uimanager/ViewManagerDelegate;Landroid/view/View;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
}

public abstract interface class com/facebook/react/uimanager/ViewManagerPropertyUpdater$Settable {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.uimanager

import android.view.View
import com.facebook.common.logging.FLog
import com.facebook.react.uimanager.ViewManagersPropertyCache.PropSetter
import java.util.HashMap

public object ViewManagerPropertyUpdater {
public fun interface Settable {
public fun getProperties(props: MutableMap<String, String>)
}

@Suppress("FINITE_BOUNDS_VIOLATION_IN_JAVA")
public interface ViewManagerSetter<T : ViewManager<V, *>, V : View> : Settable {
public fun setProperty(manager: T, view: V, name: String, value: Any?)
}

@Suppress("FINITE_BOUNDS_VIOLATION_IN_JAVA")
public interface ShadowNodeSetter<in T : ReactShadowNode<*>> : Settable {
public fun setProperty(node: T, name: String, value: Any?)
}

private const val TAG = "ViewManagerPropertyUpdater"

private val VIEW_MANAGER_SETTER_MAP: MutableMap<Class<*>, ViewManagerSetter<*, *>> = HashMap()
private val SHADOW_NODE_SETTER_MAP: MutableMap<Class<*>, ShadowNodeSetter<*>> = HashMap()

@JvmStatic
public fun clear(): Unit {
ViewManagersPropertyCache.clear()
VIEW_MANAGER_SETTER_MAP.clear()
SHADOW_NODE_SETTER_MAP.clear()
}

@JvmStatic
public fun <T : ViewManagerDelegate<V>, V : View> updateProps(
delegate: T,
view: V,
props: ReactStylesDiffMap
) {
val iterator = props.mBackingMap.entryIterator
while (iterator.hasNext()) {
val entry = iterator.next()
delegate.setProperty(view, entry.key, entry.value)
}
}

@JvmStatic
public fun <V : View> updateProps(
manager: ViewManager<V, *>,
view: V,
props: ReactStylesDiffMap
) {
val setter = findManagerSetter(manager.javaClass)
val iterator = props.mBackingMap.entryIterator
while (iterator.hasNext()) {
val entry = iterator.next()
setter.setProperty(manager, view, entry.key, entry.value)
}
}

@JvmStatic
public fun <T : ReactShadowNode<T>> updateProps(node: T, props: ReactStylesDiffMap) {
val setter = findNodeSetter(node.javaClass)
val iterator = props.mBackingMap.entryIterator
while (iterator.hasNext()) {
val entry = iterator.next()
setter.setProperty(node, entry.key, entry.value)
}
}

@JvmStatic
public fun getNativeProps(
viewManagerTopClass: Class<out ViewManager<Nothing, *>>,
shadowNodeTopClass: Class<out Nothing>
): Map<String, String> {
val props: MutableMap<String, String> = HashMap()
findManagerSetter(viewManagerTopClass).getProperties(props)
findNodeSetter(shadowNodeTopClass).getProperties(props)
return props
}

private fun <V : View> findManagerSetter(
managerClass: Class<out ViewManager<V, *>>
): ViewManagerSetter<ViewManager<V, *>, V> {
var setter = VIEW_MANAGER_SETTER_MAP[managerClass]
if (setter == null) {
setter = findGeneratedSetter(managerClass)
if (setter == null) {
setter = FallbackViewManagerSetter(managerClass)
}
VIEW_MANAGER_SETTER_MAP[managerClass] = setter
}
@Suppress("UNCHECKED_CAST")
return setter as ViewManagerSetter<ViewManager<V, *>, V>
}

private fun <T : ReactShadowNode<T>> findNodeSetter(
nodeClass: Class<out T>
): ShadowNodeSetter<T> {
var setter = SHADOW_NODE_SETTER_MAP[nodeClass]
if (setter == null) {
setter = findGeneratedSetter(nodeClass)
if (setter == null) {
@Suppress("UNCHECKED_CAST")
setter = FallbackShadowNodeSetter(nodeClass as Class<Nothing>)
}
SHADOW_NODE_SETTER_MAP[nodeClass] = setter
}
@Suppress("UNCHECKED_CAST")
return setter as ShadowNodeSetter<T>
}

private fun <T> findGeneratedSetter(cls: Class<*>): T? {
val clsName = cls.name
try {
val setterClass = Class.forName("$clsName$\$PropsSetter")
@Suppress("DEPRECATION", "UNCHECKED_CAST")
return setterClass.newInstance() as T
} catch (e: ClassNotFoundException) {
FLog.w(TAG, "Could not find generated setter for $cls")
return null
} catch (e: InstantiationException) {
throw RuntimeException("Unable to instantiate methods getter for $clsName", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Unable to instantiate methods getter for $clsName", e)
}
}

private class FallbackViewManagerSetter<V : View>(
viewManagerClass: Class<out ViewManager<V, *>>
) : ViewManagerSetter<ViewManager<V, *>, V> {
private val mPropSetters: Map<String, PropSetter> =
ViewManagersPropertyCache.getNativePropSettersForViewManagerClass(viewManagerClass)

override fun setProperty(manager: ViewManager<V, *>, view: V, name: String, value: Any?) {
val setter = mPropSetters[name]
setter?.updateViewProp(manager, view, value)
}

override fun getProperties(props: MutableMap<String, String>) {
for (setter in mPropSetters.values) {
props[setter.propName] = setter.propType
}
}
}

private class FallbackShadowNodeSetter(shadowNodeClass: Class<out Nothing>) :
ShadowNodeSetter<ReactShadowNode<*>> {
private val propSetters: Map<String, PropSetter> =
ViewManagersPropertyCache.getNativePropSettersForShadowNodeClass(shadowNodeClass)

override fun setProperty(node: ReactShadowNode<*>, name: String, value: Any?) {
val setter = propSetters[name]
setter?.updateShadowNodeProp(node, value)
}

override fun getProperties(props: MutableMap<String, String>) {
for (setter in propSetters.values) {
props[setter.propName] = setter.propType
}
}
}
}

0 comments on commit fe8370b

Please sign in to comment.