Skip to content

Commit

Permalink
Add java.lang.ref.WeakReference wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Aug 28, 2018
1 parent 350c507 commit a0d8ecd
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/jni/jni.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
#include <jni/native_method.hpp>
#include <jni/boxing.hpp>
#include <jni/advanced_ownership.hpp>
#include <jni/weak_reference.hpp>
8 changes: 8 additions & 0 deletions include/jni/unique_pointerlike.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ namespace jni

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

// Attempt to promote a weak reference to a strong one. Returns an empty result
// if the weak reference has expired.
//
// Beware that the semantics of JNI weak references are weaker than is typically
// desired: a JNI weak reference may still be promoted to a non-null strong reference
// even during finalization. Consider using jni::WeakReference<T> instead.
template < class T, template < RefDeletionMethod > class WeakDeleter >
Local<T> NewLocal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
{
Expand Down
40 changes: 40 additions & 0 deletions include/jni/weak_reference.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <jni/class.hpp>
#include <jni/object.hpp>

namespace jni
{
struct WeakReferenceTag { static constexpr auto Name() { return "java/lang/ref/WeakReference"; } };

// Wraps a JNI global reference to a java.lang.ref.WeakReference, producing an ownership class
// similar to jni::Weak<T> (JNI's weak global reference), but with more reliable promotion semantics.
// Whereas a JNI weak global reference may still be promoted to a strong reference even during
// finalization, leading to potential use-after-free errors, a WeakReference cannot.
template < class T, template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
class WeakReference
{
private:
Global<Object<WeakReferenceTag>, Deleter> reference;

public:
WeakReference(JNIEnv& env, T referent)
{
static auto klass = Class<WeakReferenceTag>::Singleton(env);
static auto constructor = klass.GetConstructor<Object<>>(env);
reference = klass.New(env, constructor, Object<>(referent.Get())).template NewGlobalRef<Deleter>(env);
}

Local<T> get(JNIEnv& env)
{
if (!reference)
{
return Local<T>();
}

static auto klass = Class<WeakReferenceTag>::Singleton(env);
static auto get = klass.template GetMethod<Object<> ()>(env, "get");
return SeizeLocal(env, T(reinterpret_cast<UntaggedType<T>>(reference->Call(env, get).Get())));
}
};
}

0 comments on commit a0d8ecd

Please sign in to comment.