Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Java.Interop] Value Marshaling with Expressions
Fixes: #8 Extend the JniValueMarshaler abstraction from commit 77a6bf8 so that JniValueMarshaler can *also* marshal from/to Java via System.Linq.Expressions expression trees: partial class JniValueMarshaler { public virtual Type MarshalType {get;} public virtual Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type targetType); public virtual Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize); public virtual Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue); } The members: * MarshalType: The JNI type that this marshaler marshals from/to. The default value is typeof(IntPtr), making it suitable for marshaling reference types. * CreateParameterToManagedExpression(): Java > Managed marshaler. Convert the Java parameter `sourceValue`, of type `MarshalType`, to the managed type `targetType`. * CreateParameterFromManagedExpression(): Managed > Java marshaler. Convert the managed parameter `sourceValue` to `MarshalType`. * CreateReturnValueFromManagedExpression(): Managed > Java marshaler, for return values (not parameters). Convert the managed parameter `sourceValue` to `MarshalType`, suitable for use when returning to Java. The default implementation of these methods uses the marshaling behavior provided by the abstract JniValueMarshaler.CreateValue(), JniValueMarshaler.CreateArgumentState(), and JniValueMarshaler.DestroyArgumentState() methods. CreateParameterToManagedExpression() uses CreateValue(), while CreateParameterFromManagedExpression() and CreateReturnValueFromManagedExpression() uses both CreateArgumentState() and DestroyArgumentState() to marshal values. The purpose of using expression trees is to permit optimizations: Java.Interop.ExportedMemberBuilder uses expression trees in order to generate the Java > Managed marshaling code, so by extending JniValueMarshaler to use expression trees it's possible to use a smarter marshaling algorithm for specific types. For example, the builtin types don't need to do *anything*, as they're binary compatible with the JNI types. Conseequently, they only need to return the source parameter, instead of actually using JniValueManager.CreateValue()/etc. Similarly, the IJavaPeerable value marshaler can directly use JniRuntime.JniValueManager.GetValue<T>() for Java > managed marshaling and IJavaPeerable.PeerReference for Managed > Java marshaling. Finally, this doesn't *fully* fix Issue #8, but it fixes "enough" to close the issue. What's missing, but can be done later, is: > Do in conjunction w/ Java.Interop.Dynamic While Java.Interop.Dynamic can (should!) use JniValueManager.CreateParameterFromManagedExpression(), it doesn't currently because it doesn't even perform the JNI invocation via expression trees; it uses expression trees to invoke the intermediate helper method JavaClassInfo.TryInvokeMember(). This can be fixed, but doesn't need to be done yet. > Need to permit use of custom attributes on return types, parameter > types, "inline" into marshal methods. This will be done in a separate commit for a JniValueManagerAttribute custom attribute. (Let's try to keep commits single purpose, right?) > Use Expression<TDelegate> to make it easier to write marshalers. This isn't needed for the currently supported marshalers.
- Loading branch information