Skip to content

Commit eda4979

Browse files
committed
Use Local<> ubiquitously
1 parent a0d8ecd commit eda4979

15 files changed

+438
-340
lines changed

examples/hello.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ static void RegisterHighLevel(JavaVM* vm)
4444

4545
jni::JNIEnv& env { jni::GetEnv(*vm) };
4646

47-
static auto system = jni::Class<System>::Find(env).NewGlobalRef(env).release();
48-
static auto printStream = jni::Class<PrintStream>::Find(env).NewGlobalRef(env).release();
47+
static auto& system = jni::Class<System>::Singleton(env);
48+
static auto& printStream = jni::Class<PrintStream>::Singleton(env);
4949

5050
static auto out = system.GetStaticField<jni::Object<PrintStream>>(env, "out");
5151
static auto println = printStream.GetMethod<void (jni::String)>(env, "println");
5252

53-
auto greet = [] (jni::JNIEnv& env, jni::Object<Greeter>, jni::Array<jni::String> args)
53+
auto greet = [] (jni::JNIEnv& env, jni::Object<Greeter>&, jni::Array<jni::String>& args)
5454
{
5555
system.Get(env, out).Call(env, println,
5656
jni::Make<jni::String>(env,

examples/native_peer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*)
2121
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
2222

2323
jni::RegisterNativePeer<Calculator>(env, jni::Class<Calculator>::Find(env), "peer",
24-
std::make_unique<Calculator, JNIEnv&>,
24+
jni::MakePeer<Calculator>,
2525
"initialize",
2626
"finalize",
2727
METHOD(&Calculator::Add, "add"),

include/jni/advanced_ownership.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,39 @@ namespace jni
7474
}
7575
}
7676
};
77+
78+
// A deleter that tries to get the JNIEnv via GetEnv, and does nothing if that fails.
79+
//
80+
// This is used to ignore GlobalRef deletions that happen after a thread has been detached,
81+
// for instance during process shutdown, when there's no need to release the reference anyway.
82+
// Specifically, it's what Class<T>::Singleton uses.
83+
//
84+
template < RefDeletionMethod DeleteRef >
85+
class EnvIgnoringDeleter
86+
{
87+
private:
88+
JavaVM* vm = nullptr;
89+
90+
public:
91+
EnvIgnoringDeleter() = default;
92+
EnvIgnoringDeleter(JNIEnv& e) : vm(&GetJavaVM(e)) {}
93+
94+
void operator()(jobject* p) const
95+
{
96+
if (p)
97+
{
98+
assert(vm);
99+
JNIEnv* env = nullptr;
100+
jint err = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_1);
101+
if (err == JNI_OK)
102+
{
103+
(env->*DeleteRef)(Unwrap(p));
104+
}
105+
else if (err != JNI_EDETACHED)
106+
{
107+
CheckErrorCode(err);
108+
}
109+
}
110+
}
111+
};
77112
}

include/jni/array.hpp

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <jni/object.hpp>
55
#include <jni/tagging.hpp>
66
#include <jni/make.hpp>
7-
#include <jni/unique_pointerlike.hpp>
87

98
namespace jni
109
{
@@ -21,29 +20,24 @@ namespace jni
2120
private:
2221
UntaggedType* array = nullptr;
2322

24-
template < class T, class D > friend class UniquePointerlike;
25-
26-
void reset(UntaggedType* a) { array = a; }
27-
28-
public:
23+
protected:
2924
explicit Array(std::nullptr_t = nullptr)
3025
{}
3126

3227
explicit Array(UntaggedType* a)
3328
: array(a)
3429
{}
3530

36-
explicit Array(UntaggedType& a)
37-
: array(&a)
38-
{}
39-
4031
Array(const Array& a)
4132
: array(a.array)
4233
{}
4334

44-
// Not reassignable; it would break UniquePointerlike's abstraction.
35+
~Array() = default;
36+
4537
Array& operator=(const Array&) = delete;
38+
void reset(UntaggedType* a) { array = a; }
4639

40+
public:
4741
explicit operator bool() const { return array; }
4842

4943
operator UntaggedType*() const { return array; }
@@ -82,15 +76,15 @@ namespace jni
8276
SetArrayRegion(env, SafeDereference(env, array), start, buf);
8377
}
8478

85-
static Array<E> New(JNIEnv& env, jsize length)
79+
static Local<Array<E>> New(JNIEnv& env, jsize length)
8680
{
87-
return Array<E>(&NewArray<E>(env, length));
81+
return Local<Array<E>>(env, &NewArray<E>(env, length));
8882
}
8983

9084
template < template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
9185
Global<Array<E>, Deleter> NewGlobalRef(JNIEnv& env) const
9286
{
93-
return SeizeGlobal<Deleter>(env, Array(jni::NewGlobalRef(env, array).release()));
87+
return Global<Array<E>, Deleter>(env, jni::NewGlobalRef(env, array).release());
9488
}
9589
};
9690

@@ -106,29 +100,24 @@ namespace jni
106100
private:
107101
UntaggedType* array = nullptr;
108102

109-
template < class T, class D > friend class UniquePointerlike;
110-
111-
void reset(UntaggedType* a) { array = a; }
112-
113-
public:
103+
protected:
114104
explicit Array(std::nullptr_t = nullptr)
115105
{}
116106

117107
explicit Array(UntaggedType* a)
118108
: array(a)
119109
{}
120110

121-
explicit Array(UntaggedType& a)
122-
: array(&a)
123-
{}
124-
125111
Array(const Array& a)
126112
: array(a.array)
127113
{}
128114

129-
// Not reassignable; it would break UniquePointerlike's abstraction.
115+
~Array() = default;
116+
130117
Array& operator=(const Array&) = delete;
118+
void reset(UntaggedType* a) { array = a; }
131119

120+
public:
132121
explicit operator bool() const { return array; }
133122

134123
operator UntaggedType*() const { return array; }
@@ -143,9 +132,9 @@ namespace jni
143132
return GetArrayLength(env, SafeDereference(env, array));
144133
}
145134

146-
ElementType Get(JNIEnv& env, jsize index) const
135+
Local<ElementType> Get(JNIEnv& env, jsize index) const
147136
{
148-
return ElementType(
137+
return Local<ElementType>(env,
149138
reinterpret_cast<UntaggedElementType*>(
150139
GetObjectArrayElement(env, SafeDereference(env, array), index)));
151140
}
@@ -155,15 +144,15 @@ namespace jni
155144
SetObjectArrayElement(env, SafeDereference(env, array), index, Untag(value));
156145
}
157146

158-
static Array<Object<TheTag>> New(JNIEnv& env, jsize length, const Object<TheTag>& initialElement = Object<TheTag>())
147+
static Local<Array<Object<TheTag>>> New(JNIEnv& env, jsize length, const Object<TheTag>& initialElement = Object<TheTag>())
159148
{
160-
return Array<Object<TheTag>>(&NewObjectArray(env, length, Class<TheTag>::Singleton(env), initialElement.Get()));
149+
return Local<Array<Object<TheTag>>>(env, &NewObjectArray(env, length, Class<TheTag>::Singleton(env), initialElement.Get()));
161150
}
162151

163152
template < template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
164153
Global<Array<Object<TheTag>>, Deleter> NewGlobalRef(JNIEnv& env) const
165154
{
166-
return SeizeGlobal<Deleter>(env, Array(jni::NewGlobalRef(env, array).release()));
155+
return Global<Array<Object<TheTag>>, Deleter>(env, jni::NewGlobalRef(env, array).release());
167156
}
168157
};
169158

@@ -177,9 +166,9 @@ namespace jni
177166
}
178167

179168
template < class T >
180-
Array<T> MakeAnything(ThingToMake<Array<T>>, JNIEnv& env, const std::vector<T>& array)
169+
Local<Array<T>> MakeAnything(ThingToMake<Array<T>>, JNIEnv& env, const std::vector<T>& array)
181170
{
182-
Array<T> result(&NewArray<T>(env, array.size()));
171+
Local<Array<T>> result = Local<Array<T>>(env, &NewArray<T>(env, array.size()));
183172
SetArrayRegion(env, *result, 0, array);
184173
return result;
185174
}
@@ -195,9 +184,9 @@ namespace jni
195184
}
196185

197186
inline
198-
Array<jbyte> MakeAnything(ThingToMake<Array<jbyte>>, JNIEnv& env, const std::string& string)
187+
Local<Array<jbyte>> MakeAnything(ThingToMake<Array<jbyte>>, JNIEnv& env, const std::string& string)
199188
{
200-
Array<jbyte> result(&NewArray<jbyte>(env, string.size()));
189+
Local<Array<jbyte>> result(env, &NewArray<jbyte>(env, string.size()));
201190
SetArrayRegion(env, *result, 0, string.size(), reinterpret_cast<const jbyte*>(&string[0]));
202191
return result;
203192
}

include/jni/boxing.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ namespace jni
9797
template < class Tag, class Unboxed >
9898
struct PrimitiveTypeBoxer
9999
{
100-
Object<Tag> Box(JNIEnv& env, Unboxed unboxed) const
100+
Local<Object<Tag>> Box(JNIEnv& env, Unboxed unboxed) const
101101
{
102102
static auto klass = Class<Tag>::Singleton(env);
103103
static auto box = klass.template GetStaticMethod<Object<Tag> (Unboxed)>(env, Tag::BoxStaticMethodName());

include/jni/class.hpp

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <jni/functions.hpp>
44
#include <jni/tagging.hpp>
5-
#include <jni/unique_pointerlike.hpp>
5+
#include <jni/advanced_ownership.hpp>
66

77
namespace jni
88
{
@@ -17,29 +17,28 @@ namespace jni
1717
class Class
1818
{
1919
private:
20-
jclass* clazz = nullptr;
21-
22-
template < class T, class D > friend class UniquePointerlike;
23-
24-
void reset(jclass* c) { clazz = c; }
25-
26-
public:
2720
using TagType = TheTag;
2821

22+
jclass* clazz = nullptr;
23+
24+
protected:
2925
explicit Class(std::nullptr_t = nullptr)
3026
{}
3127

32-
explicit Class(jclass& c)
33-
: clazz(&c)
28+
explicit Class(jclass* c)
29+
: clazz(c)
3430
{}
3531

3632
Class(const Class& c)
3733
: clazz(c.clazz)
3834
{}
3935

40-
// Not reassignable; it would break UniquePointerlike's abstraction.
36+
~Class() = default;
37+
4138
Class& operator=(const Class&) = delete;
39+
void reset(jclass* c) { clazz = c; }
4240

41+
public:
4342
explicit operator bool() const { return clazz; }
4443

4544
operator jclass&() const { return *clazz; }
@@ -49,10 +48,11 @@ namespace jni
4948
friend bool operator==( const Class& a, const Class& b ) { return a.Get() == b.Get(); }
5049
friend bool operator!=( const Class& a, const Class& b ) { return !( a == b ); }
5150

52-
template < class... Args >
53-
Object<TagType> New(JNIEnv& env, const Constructor<TagType, Args...>& method, const Args&... args) const
51+
template < class... ExpectedArgs, class... ActualArgs >
52+
auto New(JNIEnv& env, const Constructor<TagType, ExpectedArgs...>& method, const ActualArgs&... args) const
53+
-> std::enable_if_t< Conjunction<std::is_convertible<const ActualArgs&, const ExpectedArgs&>...>::value, Local<Object<TagType>> >
5454
{
55-
return Object<TagType>(&NewObject(env, *clazz, method, Untag(args)...));
55+
return Local<Object<TagType>>(env, &NewObject(env, *clazz, method, Untag(args)...));
5656
}
5757

5858
template < class T >
@@ -64,9 +64,9 @@ namespace jni
6464

6565
template < class T >
6666
auto Get(JNIEnv& env, const StaticField<TagType, T>& field) const
67-
-> std::enable_if_t< !IsPrimitive<T>::value, T >
67+
-> std::enable_if_t< !IsPrimitive<T>::value, Local<T> >
6868
{
69-
return T(reinterpret_cast<UntaggedType<T>>(jni::GetStaticField<jobject*>(env, *clazz, field)));
69+
return Local<T>(env, reinterpret_cast<UntaggedType<T>>(jni::GetStaticField<jobject*>(env, *clazz, field)));
7070
}
7171

7272
template < class T >
@@ -76,44 +76,46 @@ namespace jni
7676
SetStaticField<T>(env, *clazz, field, value);
7777
}
7878

79-
template < class T >
80-
auto Set(JNIEnv& env, const StaticField<TagType, T>& field, const T& value) const
81-
-> std::enable_if_t< !IsPrimitive<T>::value >
79+
template < class Expected, class Actual >
80+
auto Set(JNIEnv& env, const StaticField<TagType, Expected>& field, const Actual& value) const
81+
-> std::enable_if_t< !IsPrimitive<Expected>::value
82+
&& std::is_convertible<const Actual&, const Expected&>::value >
8283
{
8384
SetStaticField<jobject*>(env, *clazz, field, value.Get());
8485
}
8586

86-
template < class R, class... Args >
87-
auto Call(JNIEnv& env, const StaticMethod<TagType, R (Args...)>& method, const Args&... args) const
88-
-> std::enable_if_t< IsPrimitive<R>::value, R >
87+
template < class R, class... ExpectedArgs, class... ActualArgs >
88+
auto Call(JNIEnv& env, const StaticMethod<TagType, R (ExpectedArgs...)>& method, const ActualArgs&... args) const
89+
-> std::enable_if_t< IsPrimitive<R>::value
90+
&& Conjunction<std::is_convertible<const ActualArgs&, const ExpectedArgs&>...>::value, R >
8991
{
9092
return CallStaticMethod<R>(env, *clazz, method, Untag(args)...);
9193
}
9294

93-
template < class R, class... Args >
94-
auto Call(JNIEnv& env, const StaticMethod<TagType, R (Args...)>& method, const Args&... args) const
95-
-> std::enable_if_t< !IsPrimitive<R>::value && !std::is_void<R>::value, R >
95+
template < class R, class... ExpectedArgs, class... ActualArgs >
96+
auto Call(JNIEnv& env, const StaticMethod<TagType, R (ExpectedArgs...)>& method, const ActualArgs&... args) const
97+
-> std::enable_if_t< !IsPrimitive<R>::value
98+
&& !std::is_void<R>::value
99+
&& Conjunction<std::is_convertible<const ActualArgs&, const ExpectedArgs&>...>::value, Local<R> >
96100
{
97-
return R(reinterpret_cast<UntaggedType<R>>(CallStaticMethod<jobject*>(env, *clazz, method, Untag(args)...)));
101+
return Local<R>(env, reinterpret_cast<UntaggedType<R>>(CallStaticMethod<jobject*>(env, *clazz, method, Untag(args)...)));
98102
}
99103

100-
template < class... Args >
101-
void Call(JNIEnv& env, const StaticMethod<TagType, void (Args...)>& method, const Args&... args) const
104+
template < class... ExpectedArgs, class... ActualArgs >
105+
auto Call(JNIEnv& env, const StaticMethod<TagType, void (ExpectedArgs...)>& method, const ActualArgs&... args) const
106+
-> std::enable_if_t< Conjunction<std::is_convertible<const ActualArgs&, const ExpectedArgs&>...>::value >
102107
{
103108
CallStaticMethod<void>(env, *clazz, method, Untag(args)...);
104109
}
105110

106-
static Class Find(JNIEnv& env)
111+
static Local<Class> Find(JNIEnv& env)
107112
{
108-
return Class(FindClass(env, TagType::Name()));
113+
return Local<Class>(env, &FindClass(env, TagType::Name()));
109114
}
110115

111116
static const Class& Singleton(JNIEnv& env)
112117
{
113-
// The global references created here is purposefully leaked. Due to the design
114-
// of Java/JNI, there is virtually no way to reliably release them. See
115-
// http://bleaklow.com/2006/02/18/jni_onunload_mostly_useless.html for details.
116-
static Class singleton = Find(env).NewGlobalRef(env).release();
118+
static Global<Class, EnvIgnoringDeleter> singleton = Find(env).template NewGlobalRef<EnvIgnoringDeleter>(env);
117119
return singleton;
118120
}
119121

@@ -150,7 +152,7 @@ namespace jni
150152
template < template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
151153
Global<Class<TagType>, Deleter> NewGlobalRef(JNIEnv& env) const
152154
{
153-
return SeizeGlobal<Deleter>(env, Class(*jni::NewGlobalRef(env, clazz).release()));
155+
return Global<Class<TagType>, Deleter>(env, jni::NewGlobalRef(env, clazz).release());
154156
}
155157
};
156158
}

include/jni/make.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace jni
55
template < class Result > struct ThingToMake {};
66

77
template < class Result, class... P >
8-
Result Make(P&&... p)
8+
auto Make(P&&... p)
99
{
1010
return MakeAnything(ThingToMake<Result>(), std::forward<P>(p)...);
1111
}

0 commit comments

Comments
 (0)