diff --git a/src/net/JNet/Specific/JNetEventResult.cs b/src/net/JNet/Specific/JNetEventResult.cs index 3c16df534a..1b3e65a773 100644 --- a/src/net/JNet/Specific/JNetEventResult.cs +++ b/src/net/JNet/Specific/JNetEventResult.cs @@ -55,7 +55,7 @@ public JNetEventResult(IJVMBridgeBaseInitializer initializer) : base(initializer /// /// The to be returned to the JVM side /// - public object ReturnData { get => IExecute("getReturnData"); set => IExecute("setReturnData", value); } + public object ReturnData { get => IExecute("getReturnData"); } // disabled since JVM side raise an exception in any case set => IExecute("setReturnData", value); } /// /// Helper function to set both and /// diff --git a/src/net/JNetReflector/InternalMethods.cs b/src/net/JNetReflector/InternalMethods.cs index 4fd1c1b370..4d086d58d4 100644 --- a/src/net/JNetReflector/InternalMethods.cs +++ b/src/net/JNetReflector/InternalMethods.cs @@ -2020,6 +2020,7 @@ static string AnalyzeMethods(this Class classDefinition, IEnumerable clas template = Template.GetTemplate(Template.SingleMethodTemplate); singleMethod = template.Replace(AllPackageClasses.ClassStub.MethodStub.DECORATION, jDecoration.ToString()) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_EXECUTION, listenerHandlerType) + .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER, returnType == "void" ? string.Empty : AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER_FORMAT) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_NAME, baseHandlerName) .Replace(AllPackageClasses.ClassStub.MethodStub.MODIFIER, modifier) .Replace(AllPackageClasses.ClassStub.MethodStub.RETURNTYPE, returnType) @@ -2049,6 +2050,7 @@ static string AnalyzeMethods(this Class classDefinition, IEnumerable clas template = Template.GetTemplate(Template.SingleMethodTemplate); singleMethod = template.Replace(AllPackageClasses.ClassStub.MethodStub.DECORATION, jDecoration.ToString()) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_EXECUTION, listenerHandlerType) + .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER, returnType == "void" ? string.Empty : AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER_FORMAT) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_NAME, baseHandlerName) .Replace(AllPackageClasses.ClassStub.MethodStub.MODIFIER, modifier) .Replace(AllPackageClasses.ClassStub.MethodStub.RETURNTYPE, returnType) @@ -2078,6 +2080,7 @@ static string AnalyzeMethods(this Class classDefinition, IEnumerable clas template = Template.GetTemplate(Template.SingleMethodTemplate); singleMethod = template.Replace(AllPackageClasses.ClassStub.MethodStub.DECORATION, jDecoration.ToString()) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_EXECUTION, listenerHandlerType) + .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER, returnType == "void" ? string.Empty : AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER_FORMAT) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_NAME, baseHandlerName) .Replace(AllPackageClasses.ClassStub.MethodStub.MODIFIER, modifier) .Replace(AllPackageClasses.ClassStub.MethodStub.RETURNTYPE, returnType) @@ -2149,6 +2152,7 @@ static string AnalyzeMethods(this Class classDefinition, IEnumerable clas { singleMethod = template.Replace(AllPackageClasses.ClassStub.MethodStub.DECORATION, jDecoration.ToString()) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_EXECUTION, listenerHandlerType) + .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER, returnType == "void" ? string.Empty : AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER_FORMAT) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_NAME, baseHandlerName) .Replace(AllPackageClasses.ClassStub.MethodStub.MODIFIER, modifier) .Replace(AllPackageClasses.ClassStub.MethodStub.RETURNTYPE, returnType) @@ -2178,6 +2182,7 @@ static string AnalyzeMethods(this Class classDefinition, IEnumerable clas singleMethod = template.Replace(AllPackageClasses.ClassStub.MethodStub.DECORATION, jDecoration.ToString()) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_EXECUTION, listenerHandlerType) + .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER, returnType == "void" ? string.Empty : AllPackageClasses.ClassStub.MethodStub.LISTENER_DISPOSE_HANDLER_FORMAT) .Replace(AllPackageClasses.ClassStub.MethodStub.LISTENER_HANDLER_NAME, baseHandlerName) .Replace(AllPackageClasses.ClassStub.MethodStub.MODIFIER, modifier) .Replace(AllPackageClasses.ClassStub.MethodStub.RETURNTYPE, returnType) diff --git a/src/net/JNetReflector/Templates/AllPackageClassesStubClass.template b/src/net/JNetReflector/Templates/AllPackageClassesStubClass.template index d3bf117fee..2aeccbe894 100644 --- a/src/net/JNetReflector/Templates/AllPackageClassesStubClass.template +++ b/src/net/JNetReflector/Templates/AllPackageClassesStubClass.template @@ -3,13 +3,15 @@ ALLPACKAGE_CLASSES_STUB_CLASS_DECORATION_PLACEHOLDER public partial class ALLPACKAGE_CLASSES_STUB_CLASS_PLACEHOLDER : ALLPACKAGE_CLASSES_STUB_BASECLASS_PLACEHOLDERALLPACKAGE_CLASSES_STUB_WHERECLAUSES_PLACEHOLDER { const string _bridgeClassName = "ALLPACKAGE_CLASSES_STUB_JAVACLASS_PLACEHOLDER"; + /// - /// Internal constructor: used internally from JCOBridge + /// Initializer used internally by JCOBridge. Do not use directly. /// [global::System.Obsolete("This public initializer is needed for JCOBridge internal use, other uses can produce unidentible behaviors.")] public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(IJVMBridgeBaseInitializer initializer) : base(initializer) { } + /// - /// Generic constructor: it is useful for JCOBridge when there is a derived class which needs to pass arguments to the highest JVMBridgeBase class + /// Generic constructor used by JCOBridge when a derived class needs to forward arguments to the base JVMBridgeBase class. /// public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(params object[] args) : base(args) { } diff --git a/src/net/JNetReflector/Templates/AllPackageClassesStubClassInterfaceOrAbstract.template b/src/net/JNetReflector/Templates/AllPackageClassesStubClassInterfaceOrAbstract.template index f54c8b3c5c..edef42659f 100644 --- a/src/net/JNetReflector/Templates/AllPackageClassesStubClassInterfaceOrAbstract.template +++ b/src/net/JNetReflector/Templates/AllPackageClassesStubClassInterfaceOrAbstract.template @@ -3,14 +3,20 @@ ALLPACKAGE_CLASSES_STUB_CLASS_DECORATION_PLACEHOLDER public partial class ALLPACKAGE_CLASSES_STUB_CLASS_PLACEHOLDER : ALLPACKAGE_CLASSES_STUB_BASECLASS_PLACEHOLDERALLPACKAGE_CLASSES_STUB_WHERECLAUSES_PLACEHOLDER { const string _bridgeClassName = "ALLPACKAGE_CLASSES_STUB_JAVACLASS_PLACEHOLDER"; + /// - /// Internal constructor: used internally from JCOBridge + /// Initializer used internally by JCOBridge. Do not use directly. /// [global::System.Obsolete("This public initializer is needed for JCOBridge internal use, other uses can produce unidentible behaviors.")] public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(IJVMBridgeBaseInitializer initializer) : base(initializer) { } + /// - /// Generic constructor: it is useful for JCOBridge when there is a derived class which needs to pass arguments to the highest JVMBridgeBase class + /// Generic constructor used by JCOBridge when a derived class needs to forward arguments to the base JVMBridgeBase class. /// + /// + /// represents a JVM interface or abstract class in .NET. + /// Instantiating it directly outside of JCOBridge infrastructure is not supported and may produce undefined behavior. + /// [global::System.Obsolete("ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER class represents, in .NET, an instance of a JVM interface or abstract class. This public initializer is needed for JCOBridge internal use, other uses can produce unidentible behaviors.")] public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(params object[] args) : base(args) { } diff --git a/src/net/JNetReflector/Templates/AllPackageClassesStubClassListener.template b/src/net/JNetReflector/Templates/AllPackageClassesStubClassListener.template index bdd1843a46..80e7e61e87 100644 --- a/src/net/JNetReflector/Templates/AllPackageClassesStubClassListener.template +++ b/src/net/JNetReflector/Templates/AllPackageClassesStubClassListener.template @@ -3,16 +3,17 @@ ALLPACKAGE_CLASSES_STUB_CLASS_DECORATION_PLACEHOLDER public partial class ALLPACKAGE_CLASSES_STUB_CLASS_PLACEHOLDER : ALLPACKAGE_CLASSES_STUB_BASECLASS_PLACEHOLDER { /// - /// Internal constructor: used internally from JCOBridge + /// Initializer used internally by JCOBridge. Do not use directly. /// [global::System.Obsolete("This public initializer is needed for JCOBridge internal use, other uses can produce unidentible behaviors.")] - public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(IJVMBridgeBaseInitializer initializer) : base(initializer) + public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(IJVMBridgeBaseInitializer initializer) : base(initializer) { - var listenerRuntimeType = GetType(); + var listenerRuntimeType = GetType(); _hasALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDERSecondGate = MASES.JNet.Specific.JNetEventResult.GetMethodIsOverridden(listenerRuntimeType, nameof(ListenerShallManageEvent), typeof(int), typeof(object)); } + /// - /// Generic constructor: it is useful for JCOBridge when there is a derived class which needs to pass arguments to the highest JVMBridgeBase class + /// Generic constructor used by JCOBridge when a derived class needs to forward arguments to the base JVMBridgeBase class. /// public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(params object[] args) : base(args) { @@ -21,12 +22,27 @@ public partial class ALLPACKAGE_CLASSES_STUB_CLASS_PLACEHOLDER : ALLPACKAGE_CLAS InitializeHandlers(listenerRuntimeType); } + /// + /// if the user has overridden in a subclass. + /// Cached at construction to avoid per-event reflection cost. When , the first gate always + /// returns so that the second gate is reached regardless of whether individual event handlers are registered. + /// readonly bool _hasALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDERSecondGate; + /// + /// + /// Evaluated in order: + /// + /// delegate — index-based, no string conversion, lowest overhead. + /// delegate — name-based, resolves via . + /// — returns if the specific event has a registered delegate or a virtual method override. + /// — returns if the second gate is overridden, ensuring all events reach it. + /// + /// protected override bool ListenerShallManageEvent(int eventIndex) { - if (ListenerShallManageEventIndex != null) return ListenerShallManageEventIndex(eventIndex); // test first gate base handler with index - if (ListenerShallManageEventName != null) return ListenerShallManageEventName(ConvertListenerEventIndexToEventName(eventIndex)); // or test first gate base handler with name + if (ListenerShallManageEventIndex != null) return ListenerShallManageEventIndex(eventIndex); + if (ListenerShallManageEventName != null) return ListenerShallManageEventName(ConvertListenerEventIndexToEventName(eventIndex)); if (ListenerShallManageEventHandlers(eventIndex)) return true; return _hasALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDERSecondGate; } @@ -40,28 +56,40 @@ ALLPACKAGE_CLASSES_STUB_LISTENER_CLASS_PLACEHOLDER #region ALLPACKAGE_CLASSES_STUB_CLASS_DIRECT_PLACEHOLDER declaration /// -/// Direct override of or its generic type if there is one +/// Concrete CLR representation of returned by the JVM. /// +/// +/// When the JVM returns an instance of this listener type, JCOBridge needs a concrete CLR class to wrap it. +/// A full listener implementation cannot be used in this scenario because it would require user-provided handler code +/// that is not available at the point of construction. This class provides a minimal, handler-free wrapper: +/// is a no-op, unconditionally +/// returns discarding all events immediately, and is +/// to prevent automatic JVM-side registration. +/// Do not use this class directly to register event handlers — use instead. +/// public partial class ALLPACKAGE_CLASSES_STUB_CLASS_DIRECT_PLACEHOLDER : ALLPACKAGE_CLASSES_STUB_CLASS_PLACEHOLDER { /// - /// Internal constructor: used internally from JCOBridge + /// Initializer used internally by JCOBridge. Do not use directly. /// [global::System.Obsolete("This public initializer is needed for JCOBridge internal use, other uses can produce unidentible behaviors.")] public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDERDirect(IJVMBridgeBaseInitializer initializer) : base(initializer) { } + /// - /// Generic constructor: it is useful for JCOBridge when there is a derived class which needs to pass arguments to the highest JVMBridgeBase class + /// Generic constructor used by JCOBridge when a derived class needs to forward arguments to the base JVMBridgeBase class. /// public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDERDirect(params object[] args) : base(args) { } /// public override bool AutoInit => false; - /// + /// + /// No handlers are registered in this direct override — initialization is intentionally skipped. protected override void InitializeHandlers(global::System.Type _) { } /// - protected override bool ListenerShallManageEvent(int _) { return false; } // early discard since no handlers are registered + /// Always returns — all events are discarded at the first gate without reading any JVM argument data. + protected override bool ListenerShallManageEvent(int _) => false; const string _bridgeClassName = "ALLPACKAGE_CLASSES_STUB_JAVACLASS_DIRECT_PLACEHOLDER"; private static readonly global::System.Exception _LocalBridgeClazzException = null; diff --git a/src/net/JNetReflector/Templates/SingleListenerJavaFile.template b/src/net/JNetReflector/Templates/SingleListenerJavaFile.template index 97086a90c8..fdda4f7ac6 100644 --- a/src/net/JNetReflector/Templates/SingleListenerJavaFile.template +++ b/src/net/JNetReflector/Templates/SingleListenerJavaFile.template @@ -9,63 +9,134 @@ package ALLPACKAGE_PACKAGE_PLACEHOLDER; public final class ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER ALLPACKAGE_CLASSES_STUB_EXTEND_JAVACLASS_PLACEHOLDERimplements org.mases.jcobridge.IJCListenerALLPACKAGE_CLASSES_STUB_JAVACLASS_PLACEHOLDER { final org.mases.jcobridge.JCListener _internalListener; + /** + * Constructs the listener and registers it with the JCOBridge runtime using the provided key. + * @param key the registration key used by JCOBridge to identify this listener instance on the CLR side. + * @throws org.mases.jcobridge.JCNativeException if the native bridge initialization fails. + */ public ALLPACKAGE_CLASSES_STUB_SIMPLECLASS_PLACEHOLDER(String key) throws org.mases.jcobridge.JCNativeExceptionCONSTRUCTOR_STUB_CONSTRUCTOR_EXTEND_EXCEPTIONS_PLACEHOLDER { super(); _internalListener = new org.mases.jcobridge.JCListener(key); } + /** + * Releases the resources held by this listener and unregisters it from the JCOBridge runtime. + */ public synchronized void release() { _internalListener.release(); } + /** + * Returns the numeric index associated with the given event name. + * The index is used by the CLR side for zero-cost index-based event filtering. + * @param eventName the name of the event as registered on the CLR side. + * @return the numeric index of the event. + */ public synchronized int getEventIndex(String eventName) { return _internalListener.getEventIndex(eventName); } - + + /** + * Raises the named event on the CLR side with no associated data. + * @param eventName the name of the event to raise. + */ public synchronized void raiseEvent(String eventName) { _internalListener.raiseEvent(eventName); } + /** + * Raises the event identified by index on the CLR side with no associated data. + * @param eventIndex the numeric index of the event to raise. + */ public synchronized void raiseEvent(int eventIndex) { _internalListener.raiseEvent(eventIndex); } - + + /** + * Raises the named event on the CLR side, passing a single data object. + * @param eventName the name of the event to raise. + * @param e the data object associated with the event. + */ public synchronized void raiseEvent(String eventName, Object e) { _internalListener.raiseEvent(eventName, e); } + /** + * Raises the event identified by index on the CLR side, passing a single data object. + * @param eventIndex the numeric index of the event to raise. + * @param e the data object associated with the event. + */ public synchronized void raiseEvent(int eventIndex, Object e) { _internalListener.raiseEvent(eventIndex, e); } - + + /** + * Raises the named event on the CLR side, passing a primary data object and additional arguments. + * @param eventName the name of the event to raise. + * @param e the primary data object associated with the event. + * @param objects additional arguments forwarded to the CLR handler. + */ public synchronized void raiseEvent(String eventName, Object e, Object... objects) { _internalListener.raiseEvent(eventName, e, objects); } + /** + * Raises the event identified by index on the CLR side, passing a primary data object and additional arguments. + * @param eventIndex the numeric index of the event to raise. + * @param e the primary data object associated with the event. + * @param objects additional arguments forwarded to the CLR handler. + */ public synchronized void raiseEvent(int eventIndex, Object e, Object... objects) { _internalListener.raiseEvent(eventIndex, e, objects); } - + + /** + * Returns the data object sent by the CLR side for the current event, if any. + * @return the event data object, or {@code null} if none was provided. + */ public Object getEventData() { return _internalListener.getEventData(); } - + + /** + * Returns {@code true} if the current event has additional arguments beyond the primary data object. + * @return {@code true} if extra data is available. + */ public boolean hasExtraData() { return _internalListener.hasExtraData(); } - + + /** + * Returns the number of additional arguments associated with the current event. + * @return the length of the extra data array. + */ public int extraDataLength() { return _internalListener.extraDataLength(); } - + + /** + * Returns the additional arguments associated with the current event. + * @return an array of extra data objects, or an empty array if none are present. + */ public Object[] extraData() { return _internalListener.extraData(); } - + + /** + * Returns the return value set by the CLR handler for the current event. + * Used when the JVM interface method has a non-void return type and the CLR side + * must supply the value via {@link #setReturnData(Object)}. + * @return the return value, or {@code null} if not set. + */ public Object getReturnData() { return _internalListener.getReturnData(); } - + + /** + * Sets the return value that the JVM interface method will return to its caller. + * Must be called by the CLR handler before control returns to the JVM for non-void interface methods. + * @param retData the value to return to the JVM caller. + */ public void setReturnData(Object retData) { _internalListener.setReturnData(retData); } diff --git a/src/net/JNetReflector/Templates/SingleListenerMethod.template b/src/net/JNetReflector/Templates/SingleListenerMethod.template index d2ae932850..835eaaa425 100644 --- a/src/net/JNetReflector/Templates/SingleListenerMethod.template +++ b/src/net/JNetReflector/Templates/SingleListenerMethod.template @@ -2,18 +2,29 @@ /// /// Handler for METHOD_STUB_METHOD_HELP_PLACEHOLDER /// -/// If has a value it takes precedence over corresponding class method +/// +/// Assign a delegate to handle the event without subclassing. If both this handler and a virtual method override are present, +/// the delegate takes precedence. Set to to delegate to the virtual method. +/// public METHOD_STUB_LISTENER_EXECUTION_TYPE_PLACEHOLDER OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER { get; set; } = null; +METHOD_STUB_LISTENER_DISPOSE_HANDLER_PLACEHOLDER +/// Index assigned by for the event. Used for zero-cost index-based filtering in . +int _METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandlerIndex = 0; -int METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandlerIndex = 0; +/// if the user has overridden in a subclass. Cached at construction to avoid per-event reflection. bool _hasOverrideMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER; + +/// Returns if this event has an active handler — either a delegate assignment or a virtual method override. Used by to discard events with no registered handler without reading JVM argument data. [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] bool METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden() => _hasOverrideMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER || OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER != null; + void METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandler(object sender, CLRListenerEventArgs> data) { - if (!METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden()) // can be omitted however it is a protection against an user override of ListenerShallManageEvent + if (!METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden()) // guard: no handler registered — return without reading data. + // Normally unreachable if ListenerShallManageEvent filtered correctly, + // but protects against user overrides of ListenerShallManageEvent that bypass the check. { - // returns immediately without analyze anything, data.EventData.TypedEventData.HasOverride is false by default + // data.EventData.TypedEventData.HasOverride is false by default — JVM receives no return value. return; } METHOD_STUB_LISTENER_HANDLER_EXECUTION_PLACEHOLDER diff --git a/src/net/JNetReflector/Templates/Templates.cs b/src/net/JNetReflector/Templates/Templates.cs index 07848edb62..b915d87f02 100644 --- a/src/net/JNetReflector/Templates/Templates.cs +++ b/src/net/JNetReflector/Templates/Templates.cs @@ -212,9 +212,10 @@ public class MethodStub public const string LISTENER_PARAMETERS_TYPES = "METHOD_STUB_LISTENER_PARAMETERS_TYPES_PLACEHOLDER"; public const string LISTENER_HANDLER_EXECUTION = "METHOD_STUB_LISTENER_HANDLER_EXECUTION_PLACEHOLDER"; public const string LISTENER_HANDLER_NAME = "METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER"; - public static string SINGLE_LISTENER_HANDLER_FORMAT = " METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandlerIndex = AddEventHandler(\"{0}\", new global::System.EventHandler>>(METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandler));" + Environment.NewLine // removed OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER = METHOD_STUB_METHOD_NAME_PLACEHOLDER;"; + public const string LISTENER_DISPOSE_HANDLER = "METHOD_STUB_LISTENER_DISPOSE_HANDLER_PLACEHOLDER"; + public static string SINGLE_LISTENER_HANDLER_FORMAT = " _METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandlerIndex = AddEventHandler(\"{0}\", new global::System.EventHandler>>(METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandler));" + Environment.NewLine // removed OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER = METHOD_STUB_METHOD_NAME_PLACEHOLDER;"; + " _hasOverrideMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER = MASES.JNet.Specific.JNetEventResult.GetMethodIsOverridden(listenerRuntimeType, nameof(METHOD_STUB_METHOD_NAME_PLACEHOLDER)METHOD_STUB_LISTENER_PARAMETERS_TYPES_PLACEHOLDER);"; - public const string SINGLE_LISTENER_FIRST_GATE_FORMAT = " if (eventIndex == METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandlerIndex) return METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden();"; + public const string SINGLE_LISTENER_FIRST_GATE_FORMAT = " if (eventIndex == _METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventHandlerIndex) return METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden();"; public const string EXECUTION_FORMAT = "{0}{1}{2}(\"{3}\"{4}{5});"; public const string SINGLE_ARRAY_EXECUTION_FORMAT = "new object[] {{ {0} }}"; public const string STATIC_EXECUTION_FORMAT = "{0}{1}{2}(LocalBridgeClazz, \"{3}\"{4}{5});"; @@ -238,12 +239,25 @@ public class MethodStub public const string INSTANCE_EXECUTE = "IExecute"; public const string SIGNATURE_EXECUTE_TRAILER = "WithSignature"; + public static readonly string LISTENER_DISPOSE_HANDLER_FORMAT = "" + Environment.NewLine + + "/// " + Environment.NewLine + + "/// Optional handler invoked after the event handler returns, to dispose the JVM object returned by this event." + Environment.NewLine + + "/// " + Environment.NewLine + + "/// Set when the event handler returns a JVM-backed object" + Environment.NewLine + + "/// that is no longer needed after the call. The handler receives the return value and is responsible for calling" + Environment.NewLine + + "/// on it, releasing the underlying JVM global reference immediately" + Environment.NewLine + + "/// instead of waiting for the .NET garbage collector to finalize it." + Environment.NewLine + + "/// If not set, the return value is not disposed automatically." + Environment.NewLine + + "public global::System.Action OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDERDispose { get; set; } = null;" + Environment.NewLine + + ""; + public static readonly string ACTION_LISTENER_EXECUTION_HANDLER_FORMAT = " var methodToExecute = (OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER != null) ? OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER : METHOD_STUB_METHOD_NAME_PLACEHOLDER;" + Environment.NewLine + " methodToExecute.Invoke(METHOD_STUB_LISTENER_EXECUTION_PLACEHOLDER);" + Environment.NewLine + " data.EventData.TypedEventData.HasOverride = METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden();"; public static readonly string FUNC_LISTENER_EXECUTION_HANDLER_FORMAT = " var methodToExecute = (OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER != null) ? OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDER : METHOD_STUB_METHOD_NAME_PLACEHOLDER;" + Environment.NewLine + " var executionResult = methodToExecute.Invoke(METHOD_STUB_LISTENER_EXECUTION_PLACEHOLDER);" + Environment.NewLine - + " data.EventData.TypedEventData.SetReturnData(METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden(), executionResult);"; + + " data.EventData.TypedEventData.SetReturnData(METHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDEREventOverridden(), executionResult);" + Environment.NewLine + + " OnMETHOD_STUB_LISTENER_HANDLER_NAME_PLACEHOLDERDispose?.Invoke(executionResult);"; public static readonly string BLOCK_LISTENER_HANDLER_FORMAT = "/// " + Environment.NewLine + "/// Handlers initializer for " + Environment.NewLine