Skip to content

Commit a0d8ecd

Browse files
committedAug 28, 2018
Add java.lang.ref.WeakReference wrapper
1 parent 350c507 commit a0d8ecd

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed
 

‎include/jni/jni.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
#include <jni/native_method.hpp>
2222
#include <jni/boxing.hpp>
2323
#include <jni/advanced_ownership.hpp>
24+
#include <jni/weak_reference.hpp>

‎include/jni/unique_pointerlike.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ namespace jni
129129

130130
// Attempt to promote a weak reference to a strong one. Returns an empty result
131131
// if the weak reference has expired.
132+
//
133+
// Beware that the semantics of JNI weak references are weaker than is typically
134+
// desired: a JNI weak reference may still be promoted to a non-null strong reference
135+
// even during finalization. Consider using jni::WeakReference<T> instead.
132136
template < template < RefDeletionMethod > class Deleter, class T, template < RefDeletionMethod > class WeakDeleter >
133137
Global<T, Deleter> NewGlobal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
134138
{
@@ -146,6 +150,10 @@ namespace jni
146150

147151
// Attempt to promote a weak reference to a strong one. Returns an empty result
148152
// if the weak reference has expired.
153+
//
154+
// Beware that the semantics of JNI weak references are weaker than is typically
155+
// desired: a JNI weak reference may still be promoted to a non-null strong reference
156+
// even during finalization. Consider using jni::WeakReference<T> instead.
149157
template < class T, template < RefDeletionMethod > class WeakDeleter >
150158
Local<T> NewLocal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
151159
{

‎include/jni/weak_reference.hpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
3+
#include <jni/class.hpp>
4+
#include <jni/object.hpp>
5+
6+
namespace jni
7+
{
8+
struct WeakReferenceTag { static constexpr auto Name() { return "java/lang/ref/WeakReference"; } };
9+
10+
// Wraps a JNI global reference to a java.lang.ref.WeakReference, producing an ownership class
11+
// similar to jni::Weak<T> (JNI's weak global reference), but with more reliable promotion semantics.
12+
// Whereas a JNI weak global reference may still be promoted to a strong reference even during
13+
// finalization, leading to potential use-after-free errors, a WeakReference cannot.
14+
template < class T, template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
15+
class WeakReference
16+
{
17+
private:
18+
Global<Object<WeakReferenceTag>, Deleter> reference;
19+
20+
public:
21+
WeakReference(JNIEnv& env, T referent)
22+
{
23+
static auto klass = Class<WeakReferenceTag>::Singleton(env);
24+
static auto constructor = klass.GetConstructor<Object<>>(env);
25+
reference = klass.New(env, constructor, Object<>(referent.Get())).template NewGlobalRef<Deleter>(env);
26+
}
27+
28+
Local<T> get(JNIEnv& env)
29+
{
30+
if (!reference)
31+
{
32+
return Local<T>();
33+
}
34+
35+
static auto klass = Class<WeakReferenceTag>::Singleton(env);
36+
static auto get = klass.template GetMethod<Object<> ()>(env, "get");
37+
return SeizeLocal(env, T(reinterpret_cast<UntaggedType<T>>(reference->Call(env, get).Get())));
38+
}
39+
};
40+
}

0 commit comments

Comments
 (0)