Skip to content

Commit

Permalink
feat(java): ref<> and object<> redesign
Browse files Browse the repository at this point in the history
Added: ref<> now fully supports incomplete element_type.
Among other things, this improves compilation speed x10 with
new Java API generated headers (version 2.0), which forward declare
parameter types, instead of including full definitions.

Fixed: ref<> now supports all type conversions allowed by corresponding
Java types, including array conversions. This also works for converting
between generated and manually defined element types:

ref<java::lang::RuntimeException> e; // generated
ref<java::lang::Throwable> e2 = e;  // generated
ref<throwable> e3 = e; // manually defined
  • Loading branch information
Boris-Rasin committed Jul 10, 2023
1 parent 72f3c33 commit a66a6ad
Show file tree
Hide file tree
Showing 33 changed files with 839 additions and 523 deletions.
4 changes: 2 additions & 2 deletions source/scapix/bridge/java/object.h
Expand Up @@ -39,7 +39,7 @@ class bridge : public link::java::object<SCAPIX_META_STRING("com/scapix/Bridge")

protected:

bridge(handle_type h) : object_type(h) {}
bridge(handle_type h) : object(h) {}

};

Expand All @@ -57,7 +57,7 @@ class function : public link::java::object<SCAPIX_META_STRING("com/scapix/Functi

protected:

function(handle_type h) : object_type(h) {}
function(handle_type h) : object(h) {}

};

Expand Down
15 changes: 15 additions & 0 deletions source/scapix/detail/warning/inaccessible_base.h
@@ -0,0 +1,15 @@
/*
scapix/detail/warning/pop.h
Copyright (c) 2019-2023 Boris Rasin (boris@scapix.com)
*/

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4584) // 'class1' : base-class 'class2' is already a base-class of 'class3'
#endif

#if defined(__GNUG__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winaccessible-base"
#endif
13 changes: 13 additions & 0 deletions source/scapix/detail/warning/pop.h
@@ -0,0 +1,13 @@
/*
scapix/detail/warning/pop.h
Copyright (c) 2019-2023 Boris Rasin (boris@scapix.com)
*/

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#if defined(__GNUG__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
7 changes: 2 additions & 5 deletions source/scapix/java_api.h
Expand Up @@ -8,17 +8,14 @@
#define SCAPIX_JAVA_API_H

#include <scapix/link/java/object_base.h>
#include <scapix/link/java/ref.h>
#include <scapix/link/java/convert.h>

namespace scapix {
namespace java_api {
namespace scapix::java_api {

using link::java::object_base;
using link::java::ref;
using link::java::generic;

} // namespace java_api
} // namespace scapix
} // namespace scapix::java_api

#endif // SCAPIX_JAVA_API_H
20 changes: 2 additions & 18 deletions source/scapix/link/java/array.h
Expand Up @@ -18,18 +18,10 @@

namespace scapix::link::java {

//template <typename T>
//using array = object_type<signature_t<T[]>>;

// fix: already declared in ref.h

//template <typename T, typename = void>
//class array;

template <typename T>
class array_base : public object<signature_t<T[]>, handle_type_t<T[]>>
class array_base : public object<signature_t<T[]>>
{
using base = object<signature_t<T[]>, handle_type_t<T[]>>;
using base = object<signature_t<T[]>>;

public:

Expand Down Expand Up @@ -458,14 +450,6 @@ class array<T, std::enable_if_t<is_primitive_v<T>>> : public array_base<T>

};

// to do: array<"Ljava/lang/Object;"> and array<'I'> is wrong

template <char... Chars>
class object<meta::string<'[', Chars...>> : public array<meta::string<Chars...>>
{
using array<meta::string<Chars...>>::array;
};

} // namespace scapix::link::java

#endif // SCAPIX_LINK_JAVA_ARRAY_H
19 changes: 4 additions & 15 deletions source/scapix/link/java/byte_buffer.h
Expand Up @@ -7,13 +7,11 @@
#ifndef SCAPIX_LINK_JAVA_BYTE_BUFFER_H
#define SCAPIX_LINK_JAVA_BYTE_BUFFER_H

#include <scapix/link/java/ref.h>
#include <scapix/link/java/object.h>

namespace scapix::link::java {

template <typename ClassName = SCAPIX_META_STRING("java/nio/ByteBuffer")>
class byte_buffer : public object<ClassName>
class byte_buffer : public object<SCAPIX_META_STRING("java/nio/ByteBuffer")>
{
public:

Expand All @@ -24,29 +22,20 @@ class byte_buffer : public object<ClassName>

void* direct_address() const
{
return detail::env()->GetDirectBufferAddress(this->handle());
return detail::env()->GetDirectBufferAddress(handle());
}

jlong direct_capacity() const
{
return detail::env()->GetDirectBufferCapacity(this->handle());
return detail::env()->GetDirectBufferCapacity(handle());
}

protected:

using base = object<ClassName>;
byte_buffer(typename base::handle_type h) : base(h) {}
byte_buffer(handle_type h) : object(h) {}

};

// to do: fix dependence on handle template parameter (add third bool template parameter?)

//template <>
//class object<SCAPIX_META_STRING("java/nio/ByteBuffer")> : public byte_buffer<>
//{
// using byte_buffer<>::byte_buffer;
//};

} // namespace scapix::link::java

#endif // SCAPIX_LINK_JAVA_BYTE_BUFFER_H
19 changes: 6 additions & 13 deletions source/scapix/link/java/class.h
Expand Up @@ -4,24 +4,23 @@
Copyright (c) 2019-2023 Boris Rasin (boris@scapix.com)
*/

#include <scapix/link/java/object.h>
// outside of include guard
#include <scapix/link/java/object_impl.h>

#ifndef SCAPIX_LINK_JAVA_CLASS_H
#define SCAPIX_LINK_JAVA_CLASS_H

#include <scapix/link/java/ref.h>
#include <scapix/link/java/object.h>
#include <scapix/link/java/signature.h>
#include <scapix/link/java/detail/exception.h>

namespace scapix::link::java {

class class_ : public object<SCAPIX_META_STRING("java/lang/Class"), jclass>
class class_ : public object<SCAPIX_META_STRING("java/lang/Class")>
{
public:

// Note: DefineClass() not supported on Android

static local_ref<class_> define_class(const char* name, ref<> loader, const jbyte* buf, jsize size)
static local_ref<class_> define_class(const char* name, ref<SCAPIX_META_STRING("java/lang/ClassLoader")> loader, const jbyte* buf, jsize size)
{
jclass cls = detail::env()->DefineClass(name, loader.handle(), buf, size);
detail::check_exception(cls);
Expand Down Expand Up @@ -114,16 +113,10 @@ class class_ : public object<SCAPIX_META_STRING("java/lang/Class"), jclass>

protected:

class_(handle_type h) : object_type(h) {}
class_(handle_type h) : object(h) {}

};

template <>
class object<SCAPIX_META_STRING("java/lang/Class")> : public class_
{
using class_::class_;
};

} // namespace scapix::link::java

#endif // SCAPIX_LINK_JAVA_CLASS_H
3 changes: 3 additions & 0 deletions source/scapix/link/java/class_loader.h
Expand Up @@ -4,6 +4,9 @@
Copyright (c) 2019-2023 Boris Rasin (boris@scapix.com)
*/

// outside of include guard
#include <scapix/link/java/object_impl.h>

#ifndef SCAPIX_LINK_JAVA_CLASS_LOADER_H
#define SCAPIX_LINK_JAVA_CLASS_LOADER_H

Expand Down
29 changes: 0 additions & 29 deletions source/scapix/link/java/class_name.h

This file was deleted.

16 changes: 8 additions & 8 deletions source/scapix/link/java/convert.h
Expand Up @@ -139,7 +139,7 @@ struct convert_string
};

template <typename J, typename Cpp>
struct convert<ref<J>, Cpp, std::enable_if_t<ref<string>::convertible_from<J> && std::is_convertible_v<Cpp, std::string> && !is_ref_v<Cpp>>> : convert_string
struct convert<ref<J>, Cpp, std::enable_if_t<detail::is_convertible_element<J, string> && std::is_convertible_v<Cpp, std::string> && !is_ref_v<Cpp>>> : convert_string
{
};

Expand All @@ -158,39 +158,39 @@ struct convert_primitive_object
};

using boolean_class_name = SCAPIX_META_STRING("java/lang/Boolean");
template <typename J> struct convert<ref<J>, bool, std::enable_if_t<ref<boolean_class_name>::convertible_from<J>>> :
template <typename J> struct convert<ref<J>, bool, std::enable_if_t<detail::is_convertible_element<J, boolean_class_name>>> :
convert_primitive_object<boolean_class_name, bool, jboolean, SCAPIX_META_STRING("booleanValue")> {};

using byte_class_name = SCAPIX_META_STRING("java/lang/Byte");

template <typename J, typename Cpp>
struct convert<ref<J>, Cpp, std::enable_if_t<ref<byte_class_name>::convertible_from<J> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int8_t)>> :
struct convert<ref<J>, Cpp, std::enable_if_t<detail::is_convertible_element<J, byte_class_name> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int8_t)>> :
convert_primitive_object<byte_class_name, Cpp, jbyte, SCAPIX_META_STRING("byteValue")> {};

using short_class_name = SCAPIX_META_STRING("java/lang/Short");

template <typename J, typename Cpp>
struct convert<ref<J>, Cpp, std::enable_if_t<ref<short_class_name>::convertible_from<J> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int16_t)>> :
struct convert<ref<J>, Cpp, std::enable_if_t<detail::is_convertible_element<J, short_class_name> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int16_t)>> :
convert_primitive_object<short_class_name, Cpp, jshort, SCAPIX_META_STRING("shortValue")> {};

using integer_class_name = SCAPIX_META_STRING("java/lang/Integer");

template <typename J, typename Cpp>
struct convert<ref<J>, Cpp, std::enable_if_t<ref<integer_class_name>::convertible_from<J> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int32_t)>> :
struct convert<ref<J>, Cpp, std::enable_if_t<detail::is_convertible_element<J, integer_class_name> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int32_t)>> :
convert_primitive_object<integer_class_name, Cpp, jint, SCAPIX_META_STRING("intValue")> {};

using long_class_name = SCAPIX_META_STRING("java/lang/Long");

template <typename J, typename Cpp>
struct convert<ref<J>, Cpp, std::enable_if_t<ref<long_class_name>::convertible_from<J> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int64_t)>> :
struct convert<ref<J>, Cpp, std::enable_if_t<detail::is_convertible_element<J, long_class_name> && std::is_integral_v<Cpp> && sizeof(Cpp) == sizeof(std::int64_t)>> :
convert_primitive_object<long_class_name, Cpp, jlong, SCAPIX_META_STRING("longValue")> {};

using float_class_name = SCAPIX_META_STRING("java/lang/Float");
template <typename J> struct convert<ref<J>, float, std::enable_if_t<ref<float_class_name>::convertible_from<J>>> :
template <typename J> struct convert<ref<J>, float, std::enable_if_t<detail::is_convertible_element<J, float_class_name>>> :
convert_primitive_object<float_class_name, float, jfloat, SCAPIX_META_STRING("floatValue")> {};

using double_class_name = SCAPIX_META_STRING("java/lang/Double");
template <typename J> struct convert<ref<J>, double, std::enable_if_t<ref<double_class_name>::convertible_from<J>>> :
template <typename J> struct convert<ref<J>, double, std::enable_if_t<detail::is_convertible_element<J, double_class_name>>> :
convert_primitive_object<double_class_name, double, jdouble, SCAPIX_META_STRING("doubleValue")> {};

template <typename J, typename T, typename A>
Expand Down
21 changes: 7 additions & 14 deletions source/scapix/link/java/detail/api/type.h
Expand Up @@ -17,26 +17,19 @@ struct type;
template <typename T>
struct type<java::ref<T>>
{
static local_ref<T> get_field(jobject obj, jfieldID id) noexcept { return make_local_ref(env()->GetObjectField(obj, id)); }
static local_ref<T> get_field(jobject obj, jfieldID id) noexcept { return local_ref<T>(env()->GetObjectField(obj, id)); }
static void set_field(jobject obj, jfieldID id, java::ref<T> value) noexcept { env()->SetObjectField(obj, id, value.handle()); }
static local_ref<T> get_static_field(jclass cls, jfieldID id) noexcept { return make_local_ref(env()->GetStaticObjectField(cls, id)); }
static local_ref<T> get_static_field(jclass cls, jfieldID id) noexcept { return local_ref<T>(env()->GetStaticObjectField(cls, id)); }
static void set_static_field(jclass cls, jfieldID id, java::ref<T> value) noexcept { env()->SetStaticObjectField(cls, id, value.handle()); }

template <typename ...Args> static local_ref<T> call_method(jobject obj, jmethodID id, Args... args) noexcept { return make_local_ref(env()->CallObjectMethod(obj, id, args...)); }
template <typename ...Args> static local_ref<T> call_nonvirtual_method(jobject obj, jclass cls, jmethodID id, Args... args) noexcept { return make_local_ref(env()->CallNonvirtualObjectMethod(obj, cls, id, args...)); }
template <typename ...Args> static local_ref<T> call_static_method(jclass cls, jmethodID id, Args... args) noexcept { return make_local_ref(env()->CallStaticObjectMethod(cls, id, args...)); }
template <typename ...Args> static local_ref<T> call_method(jobject obj, jmethodID id, Args... args) noexcept { return local_ref<T>(env()->CallObjectMethod(obj, id, args...)); }
template <typename ...Args> static local_ref<T> call_nonvirtual_method(jobject obj, jclass cls, jmethodID id, Args... args) noexcept { return local_ref<T>(env()->CallNonvirtualObjectMethod(obj, cls, id, args...)); }
template <typename ...Args> static local_ref<T> call_static_method(jclass cls, jmethodID id, Args... args) noexcept { return local_ref<T>(env()->CallStaticObjectMethod(cls, id, args...)); }

template <typename ...Args> static local_ref<T> new_object(jclass cls, jmethodID id, Args... args) noexcept { return make_local_ref(env()->NewObject(cls, id, args...)); }
template <typename ...Args> static local_ref<T> new_object(jclass cls, jmethodID id, Args... args) noexcept { return local_ref<T>(env()->NewObject(cls, id, args...)); }
static local_ref<java::array<T>> new_array(jsize len, java::ref<T> init) noexcept { return local_ref<java::array<T>>(env()->NewObjectArray(len, detail::befriend<T, type>::class_object().handle(), init.handle())); }
static local_ref<T> get_array_element(java::ref<java::array<T>> array, jsize index) noexcept { return make_local_ref(env()->GetObjectArrayElement(array.handle(), index)); }
static local_ref<T> get_array_element(java::ref<java::array<T>> array, jsize index) noexcept { return local_ref<T>(env()->GetObjectArrayElement(array.handle(), index)); }
static void set_array_element(java::ref<java::array<T>> array, jsize index, java::ref<T> value) noexcept { env()->SetObjectArrayElement(array.handle(), index, value.handle()); }

private:

static local_ref<T> make_local_ref(jobject handle)
{
return local_ref<T>(static_cast<typename java::ref<T>::handle_type>(handle));
}
};

template <>
Expand Down
4 changes: 2 additions & 2 deletions source/scapix/link/java/detail/exception.cpp
Expand Up @@ -16,7 +16,7 @@ namespace scapix::link::java::detail {
{
// env()->ExceptionDescribe();
env()->ExceptionClear();
throw vm_exception(local_ref<throwable<>>(e));
throw vm_exception(local_ref<throwable>(e));
}

/*
Expand All @@ -37,7 +37,7 @@ which can throw any exception thrown by executed Java code:
// env()->ExceptionDescribe();
env()->ExceptionClear();

local_ref<throwable<>> exception(e);
local_ref<throwable> exception(e);

if (auto native = dynamic_pointer_cast<native_exception>(std::move(exception)))
native->rethrow();
Expand Down
6 changes: 3 additions & 3 deletions source/scapix/link/java/detail/native_exception.h
Expand Up @@ -12,13 +12,13 @@

namespace scapix::link::java::detail {

class native_exception : public throwable<SCAPIX_META_STRING("com/scapix/NativeException")>
class native_exception : public object<SCAPIX_META_STRING("com/scapix/NativeException"), throwable>
{
public:

static local_ref<native_exception> new_object()
{
return object_type::new_object<void(jlong)>(reinterpret_cast<jlong>(new std::exception_ptr(std::current_exception())));
return object::new_object<void(jlong)>(reinterpret_cast<jlong>(new std::exception_ptr(std::current_exception())));
}

[[noreturn]] void rethrow()
Expand All @@ -34,7 +34,7 @@ class native_exception : public throwable<SCAPIX_META_STRING("com/scapix/NativeE

protected:

native_exception(handle_type h) : throwable(h) {}
native_exception(handle_type h) : object(h) {}

};

Expand Down

0 comments on commit a66a6ad

Please sign in to comment.