jni 0.3.1 → 0.4.0
raw patch · 7 files changed
+219/−82 lines, 7 filesdep +constraintsdep +deepseqdep ~inline-c
Dependencies added: constraints, deepseq
Dependency ranges changed: inline-c
Files
- jni.cabal +12/−5
- src/Foreign/JNI.c +2/−0
- src/Foreign/JNI.cpphs +107/−60
- src/Foreign/JNI/Internal.hs +25/−0
- src/Foreign/JNI/NativeMethod.hsc +5/−3
- src/Foreign/JNI/String.hs +9/−3
- src/Foreign/JNI/Types.hs +59/−11
jni.cabal view
@@ -1,5 +1,5 @@ name: jni-version: 0.3.1+version: 0.4.0 synopsis: Complete JNI raw bindings. description: Please see README.md. homepage: https://github.com/tweag/inline-java/tree/master/jni#readme@@ -12,8 +12,6 @@ build-type: Simple cabal-version: >=1.10 extra-source-files: README.md-extra-tmp-files:- src/Foreign/JNI.c source-repository head type: git@@ -22,13 +20,15 @@ library hs-source-dirs: src- c-sources: src/Foreign/JNI.c+ if impl(ghc < 8.2.1)+ c-sources: src/Foreign/JNI.c cc-options: -std=c11 extra-libraries: jvm exposed-modules: Foreign.JNI Foreign.JNI.Types Foreign.JNI.String+ Foreign.JNI.Internal other-modules: Foreign.JNI.NativeMethod build-depends:@@ -36,8 +36,15 @@ bytestring >=0.10, choice >= 0.2.0, containers >=0.5,- inline-c >=0.5.6.1,+ constraints >=0.8,+ deepseq >= 1.4.2, singletons >= 2.0, thread-local-storage >=0.1+ if impl(ghc < 8.2.1)+ build-depends:+ inline-c >=0.5.6.1+ else+ build-depends:+ inline-c >=0.6 build-tools: cpphs default-language: Haskell2010
src/Foreign/JNI.c view
@@ -1,6 +1,8 @@ #include <jni.h> +#include <stdio.h>+ #include <errno.h> #include <stdlib.h>
src/Foreign/JNI.cpphs view
@@ -36,12 +36,18 @@ module Foreign.JNI ( -- * JNI functions- -- ** VM creation+ -- ** VM management withJVM+ , newJVM+ , destroyJVM -- ** Class loading , defineClass , JNINativeMethod(..) , registerNatives+ -- ** String wrappers+ , ReferenceTypeName+ , MethodSignature+ , Signature -- ** Exceptions , JVMException(..) , throw@@ -56,6 +62,8 @@ -- ** Reference manipulation , newGlobalRef , deleteGlobalRef+ , newGlobalRefNonFinalized+ , deleteGlobalRefNonFinalized , newLocalRef , deleteLocalRef , pushLocalFrame@@ -187,6 +195,7 @@ , newForeignPtr_ , withForeignPtr )+import Foreign.JNI.Internal import Foreign.JNI.NativeMethod import Foreign.JNI.Types import qualified Foreign.JNI.String as JNI@@ -195,12 +204,14 @@ import GHC.ForeignPtr (newConcForeignPtr) import qualified Language.C.Inline as C import qualified Language.C.Inline.Unsafe as CU+import System.IO (fixIO) import System.IO.Unsafe (unsafePerformIO) import Prelude hiding (String) C.context (C.baseCtx <> C.bsCtx <> jniCtx) C.include "<jni.h>"+C.include "<stdio.h>" C.include "<errno.h>" C.include "<stdlib.h>" @@ -269,16 +280,15 @@ \st@(readers, aim) -> ((readers - 1, aim), st) case st of -- Notify the writer if I'm the last reader.- (0, Writing mv) -> putMVar mv ()+ (1, Writing mv) -> putMVar mv () _ -> return () -- | Waits until the current read locks are released and grants a write lock. acquireWriteLock :: RWLock -> IO () acquireWriteLock (RWLock ref) = do mv <- newEmptyMVar- join $ atomicModifyIORef ref $ \case- (0, _) -> ((0, Writing mv), return ())- st -> ( st, takeMVar mv)+ join $ atomicModifyIORef ref $ \(readers, _) ->+ ((readers, Writing mv), when (readers > 0) (takeMVar mv)) -- | This lock is used to avoid the JVM from dying before any finalizers -- deleting global references are finished.@@ -331,40 +341,46 @@ foldr (\str k cstrs -> BS.useAsCString str $ \cstr -> k (cstr:cstrs)) m strs [] -- | Create a new JVM, with the given arguments. /Can only be called once/. Best--- practice: use it to wrap your @main@ function.+-- practice: use 'withJVM' instead. Only useful for GHCi.+newJVM :: [ByteString] -> IO JVM+newJVM options = JVM_ <$> do+ useAsCStrings options $ \cstrs -> do+ withArray cstrs $ \(coptions :: Ptr (Ptr CChar)) -> do+ let n = fromIntegral (length cstrs) :: C.CInt+ [C.block| JavaVM * {+ JavaVM *jvm;+ JNIEnv *env;+ JavaVMInitArgs vm_args;+ JavaVMOption *options = malloc(sizeof(JavaVMOption) * $(int n));+ for(int i = 0; i < $(int n); i++)+ options[i].optionString = $(char **coptions)[i];+ vm_args.version = JNI_VERSION_1_6;+ vm_args.nOptions = $(int n);+ vm_args.options = options;+ vm_args.ignoreUnrecognized = 0;+ JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);+ free(options);+ return jvm; } |]++-- | Deallocate a 'JVM' created using 'newJVM'.+destroyJVM :: JVM -> IO ()+destroyJVM (JVM_ jvm) = do+ acquireWriteLock globalJVMLock+ [C.block| void { (*$(JavaVM *jvm))->DestroyJavaVM($(JavaVM *jvm)); } |]++-- | Create a new JVM, with the given arguments. Destroy it once the given+-- action completes. /Can only be called once/. Best practice: use it to wrap+-- your @main@ function. withJVM :: [ByteString] -> IO a -> IO a-withJVM options action =- bracket ini fini (const action)- where- ini = do- useAsCStrings options $ \cstrs -> do- withArray cstrs $ \(coptions :: Ptr (Ptr CChar)) -> do- let n = fromIntegral (length cstrs) :: C.CInt- [C.block| JavaVM * {- JavaVM *jvm;- JNIEnv *env;- JavaVMInitArgs vm_args;- JavaVMOption *options = malloc(sizeof(JavaVMOption) * $(int n));- for(int i = 0; i < $(int n); i++)- options[i].optionString = $(char **coptions)[i];- vm_args.version = JNI_VERSION_1_6;- vm_args.nOptions = $(int n);- vm_args.options = options;- vm_args.ignoreUnrecognized = 0;- JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);- free(options);- return jvm; } |]- fini jvm = do- acquireWriteLock globalJVMLock- [C.block| void { (*$(JavaVM *jvm))->DestroyJavaVM($(JavaVM *jvm)); } |]+withJVM options action = bracket (newJVM options) destroyJVM (const action) defineClass :: Coercible o (J ('Class "java.lang.ClassLoader"))- => JNI.String -- ^ Class name- -> o -- ^ Loader+ => ReferenceTypeName -- ^ Class name+ -> o -- ^ Loader -> ByteString -- ^ Bytecode buffer -> IO JClass-defineClass name (coerce -> upcast -> loader) buf = withJNIEnv $ \env ->+defineClass (coerce -> name) (coerce -> upcast -> loader) buf = withJNIEnv $ \env -> throwIfException env $ JNI.withString name $ \namep -> objectFromPtr =<<@@ -404,16 +420,16 @@ $(char *msgp)) } |] findClass- :: JNI.String -- ^ Class name+ :: ReferenceTypeName -- ^ Class name -> IO JClass-findClass name = withJNIEnv $ \env ->+findClass (coerce -> name) = withJNIEnv $ \env -> throwIfException env $ JNI.withString name $ \namep -> objectFromPtr =<< [CU.exp| jclass { (*$(JNIEnv *env))->FindClass($(JNIEnv *env), $(char *namep)) } |] -newObject :: JClass -> JNI.String -> [JValue] -> IO JObject-newObject cls sig args = withJNIEnv $ \env ->+newObject :: JClass -> MethodSignature -> [JValue] -> IO JObject+newObject cls (coerce -> sig) args = withJNIEnv $ \env -> throwIfException env $ withJValues args $ \cargs -> do constr <- getMethodID cls "<init>" sig@@ -426,9 +442,9 @@ getFieldID :: JClass -- ^ A class object as returned by 'findClass' -> JNI.String -- ^ Field name- -> JNI.String -- ^ JNI signature+ -> Signature -- ^ JNI signature -> IO JFieldID-getFieldID cls fieldname sig = withJNIEnv $ \env ->+getFieldID cls fieldname (coerce -> sig) = withJNIEnv $ \env -> throwIfException env $ JNI.withString fieldname $ \fieldnamep -> JNI.withString sig $ \sigp ->@@ -441,9 +457,9 @@ getStaticFieldID :: JClass -- ^ A class object as returned by 'findClass' -> JNI.String -- ^ Field name- -> JNI.String -- ^ JNI signature+ -> Signature -- ^ JNI signature -> IO JFieldID-getStaticFieldID cls fieldname sig = withJNIEnv $ \env ->+getStaticFieldID cls fieldname (coerce -> sig) = withJNIEnv $ \env -> throwIfException env $ JNI.withString fieldname $ \fieldnamep -> JNI.withString sig $ \sigp ->@@ -548,9 +564,9 @@ getMethodID :: JClass -- ^ A class object as returned by 'findClass' -> JNI.String -- ^ Field name- -> JNI.String -- ^ JNI signature+ -> MethodSignature -- ^ JNI signature -> IO JMethodID-getMethodID cls methodname sig = withJNIEnv $ \env ->+getMethodID cls methodname (coerce -> sig) = withJNIEnv $ \env -> throwIfException env $ JNI.withString methodname $ \methodnamep -> JNI.withString sig $ \sigp ->@@ -563,9 +579,9 @@ getStaticMethodID :: JClass -- ^ A class object as returned by 'findClass' -> JNI.String -- ^ Field name- -> JNI.String -- ^ JNI signature+ -> MethodSignature -- ^ JNI signature -> IO JMethodID-getStaticMethodID cls methodname sig = withJNIEnv $ \env ->+getStaticMethodID cls methodname (coerce -> sig) = withJNIEnv $ \env -> throwIfException env $ JNI.withString methodname $ \methodnamep -> JNI.withString sig $ \sigp ->@@ -593,20 +609,35 @@ [CU.exp| jobject { (*$(JNIEnv *env))->NewGlobalRef($(JNIEnv *env), $fptr-ptr:(jobject obj)) } |]- coerce <$> J <$> newConcForeignPtr gobj (finalize gobj)- where- finalize gobj = do- bracket (tryAcquireReadLock globalJVMLock)- (\doRead -> when (toBool doRead) $ releaseReadLock globalJVMLock)- $ \doRead ->- when (toBool doRead) $ withJNIEnv $ \env ->- [CU.block| void { (*$(JNIEnv *env))->DeleteGlobalRef($(JNIEnv *env)- ,$(jobject gobj));- } |]+ fixIO $ \j ->+ coerce <$> J <$> newConcForeignPtr gobj (deleteGlobalRefNonFinalized j) deleteGlobalRef :: Coercible o (J ty) => o -> IO () deleteGlobalRef (coerce -> J p) = finalizeForeignPtr p +-- | Like 'newGlobalRef' but it doesn't attach a finalizer to destroy+-- the reference when it is not longer reachable. Use+-- 'deleteGlobalRefNonFinalized' to destroy this reference.+newGlobalRefNonFinalized :: Coercible o (J ty) => o -> IO o+newGlobalRefNonFinalized (coerce -> upcast -> obj) = withJNIEnv $ \env -> do+ gobj <-+ [CU.exp| jobject {+ (*$(JNIEnv *env))->NewGlobalRef($(JNIEnv *env),+ $fptr-ptr:(jobject obj)) } |]+ coerce <$> J <$> newForeignPtr_ gobj++-- | Like 'deleteGlobalRef' but it can be used only on references created with+-- 'newGlobalRefNonFinalized'.+deleteGlobalRefNonFinalized :: Coercible o (J ty) => o -> IO ()+deleteGlobalRefNonFinalized (coerce -> upcast -> obj) = do+ bracket (tryAcquireReadLock globalJVMLock)+ (\doRead -> when (toBool doRead) $ releaseReadLock globalJVMLock)+ $ \doRead ->+ when (toBool doRead) $ withJNIEnv $ \env -> do+ [CU.block| void { (*$(JNIEnv *env))->DeleteGlobalRef($(JNIEnv *env)+ ,$fptr-ptr:(jobject obj));+ } |]+ -- NB: Cannot add a finalizer to local references because it may -- run in a thread where the reference is not valid. newLocalRef :: Coercible o (J ty) => o -> IO (J ty)@@ -819,16 +850,32 @@ $fptr-ptr:(jstring jstr), $(jchar *chars)) } |] -getObjectArrayElement :: Coercible o (JArray a) => o -> Int32 -> IO (J a)-getObjectArrayElement (coerce -> upcast -> array) i = withJNIEnv $ \env ->- unsafeCast <$> (objectFromPtr =<<)+getObjectArrayElement+ :: forall a o.+ (IsReferenceType a, Coercible o (J a))+ => JArray a+ -> Int32+ -> IO o+getObjectArrayElement (arrayUpcast -> array) i = withJNIEnv $ \env ->+ ( (coerce :: J a -> o)+ . (unsafeCast :: JObject -> J a)+ ) <$> (objectFromPtr =<<) [C.exp| jobject { (*$(JNIEnv *env))->GetObjectArrayElement($(JNIEnv *env), $fptr-ptr:(jarray array), $(jsize i)) } |] -setObjectArrayElement :: Coercible o (J a) => JObjectArray -> Int32 -> o -> IO ()-setObjectArrayElement array i (coerce -> upcast -> x) = withJNIEnv $ \env ->+setObjectArrayElement+ :: forall a o.+ (IsReferenceType a, Coercible o (J a))+ => JArray a+ -> Int32+ -> o+ -> IO ()+setObjectArrayElement (arrayUpcast -> array)+ i+ ((coerce :: o -> J a) -> upcast -> x) =+ withJNIEnv $ \env -> [C.exp| void { (*$(JNIEnv *env))->SetObjectArrayElement($(JNIEnv *env), $fptr-ptr:(jobjectArray array),
+ src/Foreign/JNI/Internal.hs view
@@ -0,0 +1,25 @@+module Foreign.JNI.Internal where++import qualified Foreign.JNI.String as JNI++-- | A reference type name is not just any 'JNI.String', but a fully qualified+-- identifier well-formed by construction.+newtype ReferenceTypeName = ReferenceTypeName JNI.String+ deriving (Eq, Ord)++instance Show ReferenceTypeName where+ show (ReferenceTypeName str) = show str++-- | A string representing a signature, well-formed by construction.+newtype Signature = Signature JNI.String+ deriving (Eq, Ord)++instance Show Signature where+ show (Signature str) = show str++-- | A string representing a method signature, well-formed by construction.+newtype MethodSignature = MethodSignature JNI.String+ deriving (Eq, Ord)++instance Show MethodSignature where+ show (MethodSignature str) = show str
src/Foreign/JNI/NativeMethod.hsc view
@@ -6,6 +6,8 @@ module Foreign.JNI.NativeMethod where import qualified Data.ByteString.Unsafe as BS+import Data.Coerce (coerce)+import Foreign.JNI.Internal import qualified Foreign.JNI.String as JNI import Foreign.Ptr (FunPtr) import Foreign.Storable (Storable(..))@@ -18,7 +20,7 @@ data JNINativeMethod = forall a. JNINativeMethod { jniNativeMethodName :: JNI.String- , jniNativeMethodSignature :: JNI.String+ , jniNativeMethodSignature :: MethodSignature , jniNativeMethodFunPtr :: FunPtr a } @@ -32,9 +34,9 @@ return $ JNINativeMethod (JNI.unsafeFromByteString name)- (JNI.unsafeFromByteString sig)+ (coerce (JNI.unsafeFromByteString sig)) fptr poke ptr JNINativeMethod{..} = do JNI.withString jniNativeMethodName $ #{poke JNINativeMethod, name} ptr- JNI.withString jniNativeMethodSignature $ #{poke JNINativeMethod, signature} ptr+ JNI.withString (coerce jniNativeMethodSignature) $ #{poke JNINativeMethod, signature} ptr #{poke JNINativeMethod, fnPtr} ptr jniNativeMethodFunPtr
src/Foreign/JNI/String.hs view
@@ -23,6 +23,7 @@ ) where import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BS import qualified Data.ByteString.Unsafe as BS import Data.ByteString (ByteString) import Data.String (IsString(..))@@ -33,6 +34,7 @@ import qualified Prelude import Prelude hiding (String) +-- A JNI string is represented as a NUL terminated bytestring in UTF-8 encoding. newtype String = String ByteString deriving (Eq, Ord) @@ -44,8 +46,11 @@ fromChars :: Prelude.String -> String {-# INLINE [0] fromChars #-}-fromChars str = unsafeDupablePerformIO $ do- String <$> (BS.unsafePackCString =<< GHC.newCString GHC.utf8 str)+fromChars str = unsafeDupablePerformIO $+ GHC.withCString GHC.utf8 str $ \cstr -> do+ -- we need to copy the trailing NUL+ len <- BS.c_strlen cstr+ String <$> BS.packCStringLen (cstr, fromIntegral len + 1) toChars :: String -> Prelude.String toChars (String bs) = unsafeDupablePerformIO $ BS.unsafeUseAsCString bs $ GHC.peekCString GHC.utf8@@ -53,8 +58,9 @@ withString :: String -> (CString -> IO a) -> IO a withString (String bs) f = BS.unsafeUseAsCString bs f +-- Discards the trailing NUL. toByteString :: String -> ByteString-toByteString (String bs) = bs+toByteString (String bs) = BS.init bs -- | O(1) if the input is null-terminated. Otherwise the input is copied into -- a null-terminated buffer first.
src/Foreign/JNI/Types.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-}@@ -26,12 +27,17 @@ , J(..) , jnull , upcast+ , arrayUpcast , unsafeCast , generic , unsafeUngeneric , jtypeOf+ , ReferenceTypeName+ , singToIsReferenceType , referenceTypeName+ , Signature , signature+ , MethodSignature , methodSignature , JVM(..) , JNIEnv(..)@@ -61,11 +67,13 @@ , jniCtx ) where +import Control.DeepSeq (NFData) import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Builder as Builder import qualified Data.ByteString.Builder.Prim as Prim import Data.ByteString.Builder (Builder) import Data.Char (chr, ord)+import Data.Constraint (Dict(..)) import Data.Int import qualified Data.Map as Map import Data.Monoid ((<>))@@ -77,6 +85,7 @@ , KProxy(..) #endif )+import Data.Singletons.Prelude (Sing(..)) import Data.Singletons.TypeLits (KnownSymbol, symbolVal) import Data.Word import Foreign.C (CChar)@@ -87,6 +96,7 @@ , withForeignPtr ) import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)+import Foreign.JNI.Internal import Foreign.JNI.NativeMethod import qualified Foreign.JNI.String as JNI import Foreign.Marshal.Alloc (allocaBytesAligned)@@ -99,19 +109,19 @@ -- | A JVM instance. newtype JVM = JVM_ (Ptr JVM)- deriving (Eq, Show, Storable)+ deriving (Eq, Show, Storable, NFData) -- | The thread-local JNI context. Do not share this object between threads. newtype JNIEnv = JNIEnv_ (Ptr JNIEnv)- deriving (Eq, Show, Storable)+ deriving (Eq, Show, Storable, NFData) -- | A thread-local reference to a field of an object. newtype JFieldID = JFieldID_ (Ptr JFieldID)- deriving (Eq, Show, Storable)+ deriving (Eq, Show, Storable, NFData) -- | A thread-local reference to a method of an object. newtype JMethodID = JMethodID_ (Ptr JMethodID)- deriving (Eq, Show, Storable)+ deriving (Eq, Show, Storable, NFData) -- | Not part of the JNI. The kind of 'J' type indices. Useful to reflect the -- object's class at the type-level.@@ -133,7 +143,22 @@ instance IsReferenceType ('Array ty) instance IsReferenceType ty => IsReferenceType ('Generic ty tys) +-- | Produces evidence for IsReferenceType from a `Sing ty`.+singToIsReferenceType :: Sing (ty :: JType) -> Maybe (Dict (IsReferenceType ty))+singToIsReferenceType tysing = case tysing of+ SClass _ -> Just Dict+ SPrim _ -> Nothing+ SIface _ -> Just Dict+ SArray _ -> Just Dict+ SGeneric tysing' _ -> (\Dict -> Dict) <$> singToIsReferenceType tysing'+ SVoid -> Nothing+ data instance Sing (a :: JType) where+ -- Using String instead of JNI.String for the singleton data constructors+ -- is an optimization. Otherwise, the comparisons in Language.Java.call+ -- and callStatic would involve allocations and cannot be cached.+ --+ -- See commit 3da51a4 and https://github.com/tweag/inline-java/issues/11 SClass :: String -> Sing ('Class sym) SIface :: String -> Sing ('Iface sym) SPrim :: String -> Sing ('Prim sym)@@ -141,6 +166,24 @@ SGeneric :: Sing ty -> Sing tys -> Sing ('Generic ty tys) SVoid :: Sing 'Void +instance Show (Sing (a :: JType)) where+ showsPrec d (SClass s) = showParen (d > 10) $+ showString "SClass " . showsPrec 11 s+ showsPrec d (SIface s) = showParen (d > 10) $+ showString "SIface " . showsPrec 11 s+ showsPrec d (SPrim s) = showParen (d > 10) $+ showString "SPrim " . showsPrec 11 s+ showsPrec d (SArray s) = showParen (d > 10) $+ showString "SArray " . showsPrec 11 s+ showsPrec d (SGeneric s sargs) = showParen (d > 10) $+ showString "SGeneric " . showsPrec 11 s . showsPrec 11 sargs+ showsPrec _ SVoid = showString "SVoid"++instance Show (Sing (a :: [JType])) where+ showsPrec _ SNil = showString "SNil"+ showsPrec d (SCons ty tys) = showParen (d > 10) $+ showString "SCons " . showsPrec 11 ty . showChar ' ' . showsPrec 11 tys+ -- XXX SingI constraint temporary hack because GHC 7.10 has trouble inferring -- this constraint in 'signature'. instance (KnownSymbol sym, SingI sym) => SingI ('Class (sym :: Symbol)) where@@ -173,6 +216,10 @@ upcast :: J a -> JObject upcast = unsafeCast +-- | Any array of a reference type can be casted to an array of @Object@s.+arrayUpcast :: IsReferenceType ty => J ('Array ty) -> JObjectArray+arrayUpcast = unsafeCast+ -- | Unsafe type cast. Should only be used to downcast. unsafeCast :: J a -> J b unsafeCast (J x) = J (castForeignPtr x)@@ -278,10 +325,10 @@ (<> Builder.char7 '\NUL') -- | The name of a type, suitable for passing to 'Foreign.JNI.findClass'.-referenceTypeName :: IsReferenceType ty => Sing (ty :: JType) -> JNI.String-referenceTypeName (SClass sym) = build $ classSymbolBuilder sym-referenceTypeName (SIface sym) = build $ classSymbolBuilder sym-referenceTypeName ty@(SArray _) = build $ signatureBuilder ty+referenceTypeName :: IsReferenceType ty => Sing (ty :: JType) -> ReferenceTypeName+referenceTypeName (SClass sym) = ReferenceTypeName $ build $ classSymbolBuilder sym+referenceTypeName (SIface sym) = ReferenceTypeName $ build $ classSymbolBuilder sym+referenceTypeName ty@(SArray _) = ReferenceTypeName $ build $ signatureBuilder ty referenceTypeName (SGeneric ty@(SClass _) _) = referenceTypeName ty referenceTypeName (SGeneric ty@(SIface _) _) = referenceTypeName ty referenceTypeName _ = error "referenceTypeName: Impossible."@@ -311,8 +358,8 @@ signatureBuilder SVoid = Builder.char7 'V' -- | Construct a JNI type signature from a Java type.-signature :: Sing (ty :: JType) -> JNI.String-signature = build . signatureBuilder+signature :: Sing (ty :: JType) -> Signature+signature = Signature . build . signatureBuilder -- | Construct a method's JNI type signature, given the type of the arguments -- and the return type.@@ -323,8 +370,9 @@ :: [SomeSing ('KProxy :: KProxy JType)] #endif -> Sing (ty :: JType)- -> JNI.String+ -> MethodSignature methodSignature args ret =+ MethodSignature $ build $ Builder.char7 '(' <> mconcat (map (\(SomeSing s) -> signatureBuilder s) args) <>