Skip to content

Commit

Permalink
Moves implementation of JniReference to cpp
Browse files Browse the repository at this point in the history
Signed-off-by: Yauheni Khnykin <[email protected]>
  • Loading branch information
Hsilgos committed Apr 15, 2024
1 parent 1a7710a commit e124173
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,10 @@ internal class JavaGenerator : Generator {
"JniWrapperCache",
"JniCallJavaMethod",
"JniExceptionThrower",
"JniReference"
)
private val UTILS_FILES_HEADER_ONLY =
listOf("ArrayConversionUtils", "JniReference", "JniTemplateMetainfo")
listOf("ArrayConversionUtils", "JniTemplateMetainfo")

private fun annotationFromOption(option: Pair<String, List<String>>?) = option?.let { JavaImport(option.second, option.first) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#pragma once

#include "JniTemplateMetainfo.h"
#include "JniBase.h"

#include <jni.h>
#include <cstddef>
Expand All @@ -36,49 +35,18 @@ namespace {{.}}
namespace jni
{
class JniReferenceDeleter
class JNIEXPORT JniReferenceDeleter final
{
public:
JniReferenceDeleter() = default;
JniReferenceDeleter() noexcept;
static JniReferenceDeleter create_local(JNIEnv* jni_env)
{
return JniReferenceDeleter(jni_env, DeleteReferenceMethod::LOCAL);
}
static JniReferenceDeleter create_local(JNIEnv* jni_env) noexcept;
static JniReferenceDeleter create_global()
{
return JniReferenceDeleter(nullptr, DeleteReferenceMethod::GLOBAL);
}
static JniReferenceDeleter create_global() noexcept;
static JniReferenceDeleter create_non_releasing()
{
return JniReferenceDeleter(nullptr, DeleteReferenceMethod::NON_RELEASING);
}
static JniReferenceDeleter create_non_releasing() noexcept;
template<class JniType>
void operator () (JniType obj) const
{
if (!obj)
{
return;
}
switch (m_delete_reference_method)
{
case DeleteReferenceMethod::LOCAL:
m_jni_env->DeleteLocalRef( obj );
break;
case DeleteReferenceMethod::GLOBAL:
if (JNIEnv* jni_env = {{>common/InternalNamespace}}jni::getJniEnvironmentForCurrentThread( ))
{
jni_env->DeleteGlobalRef( obj );
}
break;
case DeleteReferenceMethod::NON_RELEASING:
// noop
break;
}
}
void operator () (jobject obj) const noexcept;
private:
enum class DeleteReferenceMethod
Expand All @@ -88,11 +56,7 @@ private:
NON_RELEASING
};

JniReferenceDeleter(JNIEnv* jni_env, DeleteReferenceMethod delete_reference_method)
: m_jni_env(jni_env)
, m_delete_reference_method(delete_reference_method)
{
}
JniReferenceDeleter(JNIEnv* jni_env, DeleteReferenceMethod delete_reference_method) noexcept;

private:
JNIEnv* m_jni_env = nullptr;
Expand All @@ -103,60 +67,57 @@ template<class JniType>
using JniReference = std::unique_ptr<typename std::remove_pointer<JniType>::type, JniReferenceDeleter>;

template<class T, class Deleter, template<class, class> class SmartPointer>
T* jni_reference_unwrap(const SmartPointer<T, Deleter>& argument)
T* jni_reference_unwrap(const SmartPointer<T, Deleter>& argument) noexcept
{
return argument.get();
}

template<class T>
T jni_reference_unwrap(const T& argument)
T jni_reference_unwrap(const T& argument) noexcept
{
return argument;
}

template<class JniType>
JniReference<JniType> make_local_ref(JNIEnv* jni_env, JniType jobj)
JniReference<JniType> make_local_ref(JNIEnv* jni_env, JniType jobj) noexcept
{
static_assert((IsDerivedFromJObject<JniType>::value),
"Detected attempt to create local reference to type which is not derived from jobject");
return JniReference<JniType>(jobj, JniReferenceDeleter::create_local(jni_env));
}

template<class JniType>
JniReference<JniType> make_global_ref(JniType jobj)
JniReference<JniType> make_global_ref(JniType jobj) noexcept
{
static_assert((IsDerivedFromJObject<JniType>::value),
"Detected attempt to create global reference to type which is not derived from jobject");
return JniReference<JniType>(jobj, JniReferenceDeleter::create_global());
}

template<class JniType>
JniReference<JniType> make_non_releasing_ref(JniType jobj)
JniReference<JniType> make_non_releasing_ref(JniType jobj) noexcept
{
static_assert((IsDerivedFromJObject<JniType>::value),
"Detected attempt to create local reference to type which is not derived from jobject");
return JniReference<JniType>(jobj, JniReferenceDeleter::create_non_releasing());
}

template<class JniType>
JniReference<JniType> new_global_ref(JNIEnv* jni_env, JniType jobj)
JniReference<JniType> new_global_ref(JNIEnv* jni_env, JniType jobj) noexcept
{
return make_global_ref(static_cast<JniType>(jni_env->NewGlobalRef( jobj )));
}

inline JniReference<jclass> find_class(JNIEnv* jni_env, const char* name)
{
return make_local_ref(jni_env, jni_env->FindClass(name));
}
JniReference<jclass> find_class(JNIEnv* jni_env, const char* name) noexcept;

template<class JniType>
JniReference<jclass> get_object_class(JNIEnv* jni_env, const JniType& java_instance)
JniReference<jclass> get_object_class(JNIEnv* jni_env, const JniType& java_instance) noexcept
{
return make_local_ref(jni_env, jni_env->GetObjectClass(jni_reference_unwrap(java_instance)));
}

template<class ... Args>
JniReference<jobject> new_object_impl(JNIEnv* env, jclass java_class, jmethodID constructor_id, Args ... args)
JniReference<jobject> new_object_impl(JNIEnv* env, jclass java_class, jmethodID constructor_id, Args ... args) noexcept
{
static_assert((JniMethodArgumentTypeChecker<Args...>::are_all_jni_types),
"Detected attempt to pass to Java constructor non JNI type parameter");
Expand All @@ -167,39 +128,21 @@ template<class JavaClass, class ... Args>
JniReference<jobject> new_object(JNIEnv* env,
const JavaClass& java_class,
jmethodID constructor_id,
const Args& ... args)
const Args& ... args) noexcept
{
return new_object_impl(env, jni_reference_unwrap(java_class), constructor_id, jni_reference_unwrap(args)...);
}

inline JniReference<jobject>
create_object( JNIEnv* env, const JniReference<jclass>& javaClass )
{
const char* name = "<init>";
const char* signature = "()V";
auto theConstructor = env->GetMethodID( javaClass.get(), name, signature );
JniReference<jobject>
create_object( JNIEnv* env, const JniReference<jclass>& javaClass ) noexcept;

return new_object(env, javaClass, theConstructor);
}
JniReference<jobject>
create_instance_object( JNIEnv* env, const JniReference<jclass>& javaClass, jlong instancePointer ) noexcept;

inline JniReference<jobject>
create_instance_object( JNIEnv* env, const JniReference<jclass>& javaClass, jlong instancePointer )
{
const char* name = "<init>";
const char* signature = "(JLjava/lang/Object;)V";
auto theConstructor = env->GetMethodID( javaClass.get(), name, signature );
// On Mac platform `jlong` and `jobject` are `long long`, but `NULL` is `long`, so need to cast here.
return new_object(env, javaClass, theConstructor, instancePointer, static_cast<jobject>(NULL));
}

inline JniReference<jobject>
alloc_object( JNIEnv* env, const JniReference<jclass>& javaClass )
{
return make_local_ref( env, env->AllocObject( javaClass.get( ) ) );
}
JniReference<jobject>
alloc_object( JNIEnv* env, const JniReference<jclass>& javaClass ) noexcept;

}
} // namespace jni
{{#internalNamespace}}
}
} // namespace {{.}}
{{/internalNamespace}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{{!!
!
! Copyright (C) 2016-2024 HERE Europe B.V.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
! http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!
! SPDX-License-Identifier: Apache-2.0
! License-Filename: LICENSE
!
!}}
{{>java/CopyrightHeader}}

#include "JniReference.h"

#include "JniBase.h"

{{#internalNamespace}}
namespace {{.}}
{
{{/internalNamespace}}
namespace jni
{
JniReferenceDeleter::JniReferenceDeleter() noexcept = default;
JniReferenceDeleter JniReferenceDeleter::create_local(JNIEnv* jni_env) noexcept
{
return JniReferenceDeleter(jni_env, DeleteReferenceMethod::LOCAL);
}

JniReferenceDeleter JniReferenceDeleter::create_global() noexcept
{
return JniReferenceDeleter(nullptr, DeleteReferenceMethod::GLOBAL);
}

JniReferenceDeleter JniReferenceDeleter::create_non_releasing() noexcept
{
return JniReferenceDeleter(nullptr, DeleteReferenceMethod::NON_RELEASING);
}

JniReferenceDeleter::JniReferenceDeleter(JNIEnv* jni_env, DeleteReferenceMethod delete_reference_method) noexcept
: m_jni_env(jni_env)
, m_delete_reference_method(delete_reference_method)
{
}

void JniReferenceDeleter::operator () (jobject obj) const noexcept
{
if (obj)
{
switch (m_delete_reference_method)
{
case DeleteReferenceMethod::LOCAL:
m_jni_env->DeleteLocalRef( obj );
break;
case DeleteReferenceMethod::GLOBAL:
if (JNIEnv* jni_env = {{>common/InternalNamespace}}jni::getJniEnvironmentForCurrentThread( ))
{
jni_env->DeleteGlobalRef( obj );
}
break;
case DeleteReferenceMethod::NON_RELEASING:
// noop
break;
}
}
}


JniReference<jclass> find_class(JNIEnv* jni_env, const char* name) noexcept
{
return make_local_ref(jni_env, jni_env->FindClass(name));
}

JniReference<jobject>
create_object( JNIEnv* env, const JniReference<jclass>& javaClass ) noexcept
{
const char* name = "<init>";
const char* signature = "()V";
auto theConstructor = env->GetMethodID( javaClass.get(), name, signature );
return new_object(env, javaClass, theConstructor);
}

JniReference<jobject>
create_instance_object( JNIEnv* env, const JniReference<jclass>& javaClass, jlong instancePointer ) noexcept
{
const char* name = "<init>";
const char* signature = "(JLjava/lang/Object;)V";
auto theConstructor = env->GetMethodID( javaClass.get(), name, signature );
// On Mac platform `jlong` and `jobject` are `long long`, but `NULL` is `long`, so need to cast here.
return new_object(env, javaClass, theConstructor, instancePointer, static_cast<jobject>(NULL));
}

JniReference<jobject>
alloc_object( JNIEnv* env, const JniReference<jclass>& javaClass ) noexcept
{
return make_local_ref( env, env->AllocObject( javaClass.get( ) ) );
}

} // namespace jni
{{#internalNamespace}}
} // namespace {{.}}
{{/internalNamespace}}

0 comments on commit e124173

Please sign in to comment.