From fe8370bae3cc1666eabb4dd1d946440d42889021 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Wed, 15 Jan 2025 02:34:15 -0800 Subject: [PATCH] Convert com.facebook.react.uimanager.ViewManagerPropertyUpdater to Kotlin (#48658) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/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 --- .../ReactAndroid/api/ReactAndroid.api | 14 +- .../uimanager/ViewManagerPropertyUpdater.java | 172 ------------------ .../uimanager/ViewManagerPropertyUpdater.kt | 171 +++++++++++++++++ 3 files changed, 178 insertions(+), 179 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 0e7b6d3363c112..a62c25e8c2b546 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -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 ()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 { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java deleted file mode 100644 index 42e9d8b2992dbe..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -public class ViewManagerPropertyUpdater { - public interface Settable { - void getProperties(Map props); - } - - public interface ViewManagerSetter extends Settable { - void setProperty(T manager, V view, String name, Object value); - } - - public interface ShadowNodeSetter extends Settable { - void setProperty(T node, String name, Object value); - } - - private static final String TAG = "ViewManagerPropertyUpdater"; - - private static final Map, ViewManagerSetter> VIEW_MANAGER_SETTER_MAP = - new HashMap<>(); - private static final Map, ShadowNodeSetter> SHADOW_NODE_SETTER_MAP = new HashMap<>(); - - public static void clear() { - ViewManagersPropertyCache.clear(); - VIEW_MANAGER_SETTER_MAP.clear(); - SHADOW_NODE_SETTER_MAP.clear(); - } - - public static , V extends View> void updateProps( - T delegate, V v, ReactStylesDiffMap props) { - Iterator> iterator = props.mBackingMap.getEntryIterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - delegate.setProperty(v, entry.getKey(), entry.getValue()); - } - } - - public static void updateProps( - T manager, V v, ReactStylesDiffMap props) { - ViewManagerSetter setter = findManagerSetter(manager.getClass()); - Iterator> iterator = props.mBackingMap.getEntryIterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - setter.setProperty(manager, v, entry.getKey(), entry.getValue()); - } - } - - public static void updateProps(T node, ReactStylesDiffMap props) { - ShadowNodeSetter setter = findNodeSetter(node.getClass()); - Iterator> iterator = props.mBackingMap.getEntryIterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - setter.setProperty(node, entry.getKey(), entry.getValue()); - } - } - - public static Map getNativeProps( - Class viewManagerTopClass, - Class shadowNodeTopClass) { - Map props = new HashMap<>(); - findManagerSetter(viewManagerTopClass).getProperties(props); - findNodeSetter(shadowNodeTopClass).getProperties(props); - return props; - } - - private static ViewManagerSetter findManagerSetter( - Class managerClass) { - @SuppressWarnings("unchecked") - ViewManagerSetter setter = - (ViewManagerSetter) VIEW_MANAGER_SETTER_MAP.get(managerClass); - if (setter == null) { - setter = findGeneratedSetter(managerClass); - if (setter == null) { - setter = new FallbackViewManagerSetter<>(managerClass); - } - VIEW_MANAGER_SETTER_MAP.put(managerClass, setter); - } - - return setter; - } - - private static ShadowNodeSetter findNodeSetter( - Class nodeClass) { - @SuppressWarnings("unchecked") - ShadowNodeSetter setter = (ShadowNodeSetter) SHADOW_NODE_SETTER_MAP.get(nodeClass); - if (setter == null) { - setter = findGeneratedSetter(nodeClass); - if (setter == null) { - setter = new FallbackShadowNodeSetter<>(nodeClass); - } - SHADOW_NODE_SETTER_MAP.put(nodeClass, setter); - } - - return setter; - } - - private static T findGeneratedSetter(Class cls) { - String clsName = cls.getName(); - try { - Class setterClass = Class.forName(clsName + "$$PropsSetter"); - //noinspection unchecked - return (T) setterClass.newInstance(); - } catch (ClassNotFoundException e) { - FLog.w(TAG, "Could not find generated setter for " + cls); - return null; - } catch (InstantiationException | IllegalAccessException e) { - throw new RuntimeException("Unable to instantiate methods getter for " + clsName, e); - } - } - - private static class FallbackViewManagerSetter - implements ViewManagerSetter { - private final Map mPropSetters; - - private FallbackViewManagerSetter(Class viewManagerClass) { - mPropSetters = - ViewManagersPropertyCache.getNativePropSettersForViewManagerClass(viewManagerClass); - } - - @Override - public void setProperty(T manager, V v, String name, Object value) { - ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name); - if (setter != null) { - setter.updateViewProp(manager, v, value); - } - } - - @Override - public void getProperties(Map props) { - for (ViewManagersPropertyCache.PropSetter setter : mPropSetters.values()) { - props.put(setter.getPropName(), setter.getPropType()); - } - } - } - - private static class FallbackShadowNodeSetter - implements ShadowNodeSetter { - private final Map mPropSetters; - - private FallbackShadowNodeSetter(Class shadowNodeClass) { - mPropSetters = - ViewManagersPropertyCache.getNativePropSettersForShadowNodeClass(shadowNodeClass); - } - - @Override - public void setProperty(ReactShadowNode node, String name, Object value) { - ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name); - if (setter != null) { - setter.updateShadowNodeProp(node, value); - } - } - - @Override - public void getProperties(Map props) { - for (ViewManagersPropertyCache.PropSetter setter : mPropSetters.values()) { - props.put(setter.getPropName(), setter.getPropType()); - } - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.kt new file mode 100644 index 00000000000000..de7e27d588a43e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.kt @@ -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) + } + + @Suppress("FINITE_BOUNDS_VIOLATION_IN_JAVA") + public interface ViewManagerSetter, V : View> : Settable { + public fun setProperty(manager: T, view: V, name: String, value: Any?) + } + + @Suppress("FINITE_BOUNDS_VIOLATION_IN_JAVA") + public interface ShadowNodeSetter> : Settable { + public fun setProperty(node: T, name: String, value: Any?) + } + + private const val TAG = "ViewManagerPropertyUpdater" + + private val VIEW_MANAGER_SETTER_MAP: MutableMap, ViewManagerSetter<*, *>> = HashMap() + private val SHADOW_NODE_SETTER_MAP: MutableMap, ShadowNodeSetter<*>> = HashMap() + + @JvmStatic + public fun clear(): Unit { + ViewManagersPropertyCache.clear() + VIEW_MANAGER_SETTER_MAP.clear() + SHADOW_NODE_SETTER_MAP.clear() + } + + @JvmStatic + public fun , 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 updateProps( + manager: ViewManager, + 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 > 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>, + shadowNodeTopClass: Class + ): Map { + val props: MutableMap = HashMap() + findManagerSetter(viewManagerTopClass).getProperties(props) + findNodeSetter(shadowNodeTopClass).getProperties(props) + return props + } + + private fun findManagerSetter( + managerClass: Class> + ): ViewManagerSetter, 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, V> + } + + private fun > findNodeSetter( + nodeClass: Class + ): ShadowNodeSetter { + var setter = SHADOW_NODE_SETTER_MAP[nodeClass] + if (setter == null) { + setter = findGeneratedSetter(nodeClass) + if (setter == null) { + @Suppress("UNCHECKED_CAST") + setter = FallbackShadowNodeSetter(nodeClass as Class) + } + SHADOW_NODE_SETTER_MAP[nodeClass] = setter + } + @Suppress("UNCHECKED_CAST") + return setter as ShadowNodeSetter + } + + private fun 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( + viewManagerClass: Class> + ) : ViewManagerSetter, V> { + private val mPropSetters: Map = + ViewManagersPropertyCache.getNativePropSettersForViewManagerClass(viewManagerClass) + + override fun setProperty(manager: ViewManager, view: V, name: String, value: Any?) { + val setter = mPropSetters[name] + setter?.updateViewProp(manager, view, value) + } + + override fun getProperties(props: MutableMap) { + for (setter in mPropSetters.values) { + props[setter.propName] = setter.propType + } + } + } + + private class FallbackShadowNodeSetter(shadowNodeClass: Class) : + ShadowNodeSetter> { + private val propSetters: Map = + 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) { + for (setter in propSetters.values) { + props[setter.propName] = setter.propType + } + } + } +}