Skip to content

Commit 05c8211

Browse files
committed
test even higher level bindings
1 parent 316f8ef commit 05c8211

File tree

5 files changed

+250
-2
lines changed

5 files changed

+250
-2
lines changed

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ libpeer.$(dylib)_SOURCES = examples/native_peer.cpp
4040
CXXFLAGS__examples/native_peer.cpp = -Wno-shadow
4141
libpeer.$(dylib)_LDFLAGS = $(LDFLAGS_shared)
4242

43+
TARGETS += libbinding.$(dylib)
44+
libbinding.$(dylib)_SOURCES = examples/binding.cpp
45+
CXXFLAGS__examples/binding.cpp = -Wno-shadow
46+
libbinding.$(dylib)_LDFLAGS = $(LDFLAGS_shared)
47+
4348
.PHONY: all
4449
all: $(TARGETS)
4550

@@ -49,9 +54,15 @@ test: low_level high_level
4954
$(BUILD)/high_level
5055

5156
.PHONY: examples
52-
examples: libhello.$(dylib) examples/Hello.class libpeer.$(dylib) examples/NativePeer.class
57+
examples: libhello.$(dylib) examples/Hello.class
58+
examples: libpeer.$(dylib) examples/NativePeer.class
59+
examples: libbinding.$(dylib) examples/Binding.class
5360
java -Djava.library.path=$(BUILD) -Xcheck:jni -cp examples Hello $(shell whoami)
5461
java -Djava.library.path=$(BUILD) -Xcheck:jni -cp examples NativePeer
62+
java -Djava.library.path=$(BUILD) -Xcheck:jni -cp examples Binding
63+
64+
example-binding: libbinding.$(dylib) examples/Binding.class
65+
java -Djava.library.path=$(BUILD) -Xcheck:jni -cp examples Binding
5566

5667
# --------------------------------------------------------------------------------------------------
5768

examples/Binding.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class HighLevelBinding {
2+
public native void greet(String args);
3+
public native void greet(int args);
4+
public static native void greet(double args);
5+
public int quadruple(int num) {
6+
return num * 4;
7+
}
8+
}
9+
10+
public class Binding {
11+
public static void main(String[] args) {
12+
System.loadLibrary("binding");
13+
new HighLevelBinding().greet("test");
14+
new HighLevelBinding().greet(4);
15+
HighLevelBinding.greet(3.14);
16+
}
17+
}

examples/binding.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#include "binding.hpp"
2+
3+
namespace java { namespace lang { struct Object; } }
4+
namespace java { namespace lang { struct String; } }
5+
6+
namespace jni {
7+
8+
template <> struct Name<java::lang::Object> {
9+
using Tag = ObjectTag;
10+
};
11+
12+
template <> struct Name<java::lang::String> {
13+
using Tag = StringTag;
14+
};
15+
16+
} // namespace jni
17+
18+
19+
namespace java {
20+
namespace lang {
21+
22+
struct Object : jni::Binding<Object> {
23+
using Binding::Binding;
24+
};
25+
26+
struct String : jni::Binding<String> {
27+
using Binding::Binding;
28+
29+
// Java methods
30+
31+
jni::jint length(jni::JNIEnv& env) {
32+
static const auto method = jni_GetMethod<jni::jint()>(env, "length");
33+
return self.Call(env, method);
34+
}
35+
};
36+
37+
} // namespace lang
38+
} // namespace java
39+
40+
41+
42+
struct HighLevelBinding;
43+
44+
namespace jni {
45+
template <> struct Name<HighLevelBinding>::Tag {
46+
static constexpr auto Name() { return "HighLevelBinding"; }
47+
};
48+
} // namespace jni
49+
50+
struct HighLevelBinding : jni::Binding<HighLevelBinding> {
51+
using Binding::Binding;
52+
53+
HighLevelBinding(jni::JNIEnv& env) : Binding(jni_New<>(env)) {}
54+
55+
// Java methods
56+
jni::jint quadruple(jni::JNIEnv& env, jni::jint num) {
57+
// Call Java method
58+
static const auto method = jni_GetMethod<jni::jint(jni::jint)>(env, "quadruple");
59+
return self.Call(env, method, num);
60+
}
61+
62+
// Native methods
63+
void greet(jni::JNIEnv&, java::lang::String args);
64+
void greet(jni::JNIEnv&, jni::jint args);
65+
static void greet(jni::JNIEnv&, jni::jdouble args);
66+
67+
68+
static void jni_Register(jni::JNIEnv& env) {
69+
jni::RegisterNatives(env, jni_Class(env),
70+
jni_Bind<void(java::lang::String)>::Method<&HighLevelBinding::greet>("greet"),
71+
jni_Bind<void(jni::jint)>::Method<&HighLevelBinding::greet>("greet"),
72+
jni_Bind<void(jni::jdouble)>::StaticMethod<&HighLevelBinding::greet>("greet")
73+
);
74+
}
75+
};
76+
77+
78+
void HighLevelBinding::greet(jni::JNIEnv& env, java::lang::String args) {
79+
const auto test = jni::Make<std::string>(env, args);
80+
fprintf(stderr, "greet '%s' (length %d)\n", test.c_str(), args.length(env));
81+
}
82+
83+
void HighLevelBinding::greet(jni::JNIEnv& env, jni::jint args) {
84+
fprintf(stderr, "greet %d\n", quadruple(env, args));
85+
}
86+
87+
void HighLevelBinding::greet(jni::JNIEnv&, jni::jdouble args) {
88+
fprintf(stderr, "greet static %f\n", args);
89+
}
90+
91+
92+
93+
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
94+
jni::JNIEnv& env{ jni::GetEnv(*vm) };
95+
try {
96+
java::lang::Object::jni_Register(env);
97+
java::lang::String::jni_Register(env);
98+
HighLevelBinding::jni_Register(env);
99+
} catch (const jni::PendingJavaException&) {
100+
jni::ExceptionDescribe(env);
101+
}
102+
return jni::Unwrap(jni::jni_version_1_2);
103+
}

examples/binding.hpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
3+
#include <jni/jni.hpp>
4+
5+
namespace jni
6+
{
7+
8+
template < class T >
9+
struct Name
10+
{
11+
struct Tag {};
12+
};
13+
14+
template < class T >
15+
class Binding
16+
{
17+
using Tag = typename Name<T>::Tag;
18+
19+
public:
20+
// Constructs from jobject* pointers directly.
21+
explicit Binding(UntaggedType<Object<Tag>> self_) : self(self_) {}
22+
23+
Binding(Object<Tag> self_) : self(self_) {}
24+
25+
static void jni_Register(jni::JNIEnv&) {}
26+
27+
operator Object<Tag>() const { return self; }
28+
29+
protected:
30+
static auto jni_Class(JNIEnv& env)
31+
{
32+
static auto javaClass = Class<Tag>::Find(env).NewGlobalRef(env).release();
33+
return *javaClass;
34+
}
35+
36+
template < class... Args >
37+
static auto jni_New(JNIEnv& env, Args&&... args)
38+
{
39+
static const auto constructor = jni_Class(env).template GetConstructor<Args...>(env);
40+
return jni_Class(env).New(env, constructor, std::forward<Args>(args)...);
41+
}
42+
43+
template < class Signature >
44+
static auto jni_GetMethod(JNIEnv& env, const char* name)
45+
{
46+
return jni_Class(env).template GetMethod<Signature>(env, name);
47+
}
48+
49+
template < class M >
50+
struct jni_Bind;
51+
52+
template < class R, class... Args >
53+
struct jni_Bind< R (Args...) > {
54+
template <R (*method)(JNIEnv&, Args...)>
55+
static auto StaticMethod(const char* name)
56+
{
57+
auto wrapper = [](JNIEnv* env, UntaggedType<Class<Tag>>, UntaggedType<Args>... args) -> UntaggedType<R>
58+
{
59+
try
60+
{
61+
return method(*env, AddTag<Args>(args)...);
62+
}
63+
catch (...)
64+
{
65+
ThrowJavaError(*env, std::current_exception());
66+
return UntaggedType<R>();
67+
}
68+
};
69+
70+
using FunctionType = typename NativeMethodTraits<decltype(wrapper)>::Type;
71+
return JNINativeMethod<FunctionType>{ name, TypeSignature<R (Args...)>()(), wrapper };
72+
}
73+
74+
template <R (T::*method)(JNIEnv&, Args...)>
75+
static auto Method(const char* name)
76+
{
77+
using Subject = Object<Tag>;
78+
auto wrapper = [](JNIEnv* env, UntaggedType<Subject> subject, UntaggedType<Args>... args) -> UntaggedType<R>
79+
{
80+
try
81+
{
82+
return (T(AddTag<Subject>(*subject)).*method)(*env, AddTag<Args>(args)...);
83+
}
84+
catch (...)
85+
{
86+
ThrowJavaError(*env, std::current_exception());
87+
return UntaggedType<R>();
88+
}
89+
};
90+
91+
using FunctionType = typename NativeMethodTraits<decltype(wrapper)>::Type;
92+
return JNINativeMethod<FunctionType>{ name, TypeSignature<R(Args...)>()(), wrapper };
93+
}
94+
};
95+
96+
protected:
97+
Object<Tag> self;
98+
};
99+
100+
101+
102+
template < class T >
103+
auto RemoveTag(const Binding<T>& t)
104+
{
105+
return Object<typename Name<T>::Tag>(t).Get();
106+
}
107+
108+
109+
template < class T >
110+
struct TypeSignature< T, std::enable_if_t<std::is_base_of<Binding<T>, T>::value> > {
111+
const char * operator()() const
112+
{
113+
return TypeSignature<Object<typename Name<T>::Tag>>()();
114+
}
115+
};
116+
117+
} // jni

include/jni/type_signature.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace jni
1111
{
12-
template < class > struct TypeSignature;
12+
template < class, class = void > struct TypeSignature;
1313

1414
template <> struct TypeSignature< jboolean > { const char * operator()() const { return "Z"; } };
1515
template <> struct TypeSignature< jbyte > { const char * operator()() const { return "B"; } };

0 commit comments

Comments
 (0)