Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
name: Build the examples
name: CI

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: ruff check
uses: astral-sh/ruff-action@v3
with:
args: check

- name: ruff format
uses: astral-sh/ruff-action@v3
with:
args: format --check

build:
runs-on: ubuntu-latest

Expand All @@ -34,7 +48,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.12", "3.13", "3.14"]

steps:
- name: Checkout repository
Expand All @@ -46,12 +60,15 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Install giws
run: python -m pip install .
run: python -m pip install . pytest

- name: Run the test suite
run: python -m pytest

- name: Smoke-test the installed script
run: |
giws --version
cd examples/basic_example
giws -f MyComplexClass.giws.xml
giws -p -f MyComplexClass.giws.xml
test -f basic_example.cpp
test -f basic_example.hxx
15 changes: 0 additions & 15 deletions .github/workflows/lint.yml

This file was deleted.

6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ giws (3.1.0)
--body-extension-file as intended
* Fix the error message raised for an unknown datatype
* CI: update actions, add a Python 3.9-3.14 install/smoke-test matrix
* Generated GiwsException: check for pending exceptions after each
CallObjectMethod (fixes -Xcheck:jni warnings while building the
C++ exception)
* Add a test suite (tests/) run by CI; no JDK needed
* New example bug_nonstatic_exception demonstrating the exception
fix on non-static methods
* Modernize the Python code (f-strings, type hints, with-statement)
* Add a pre-commit configuration running ruff

Expand Down
29 changes: 29 additions & 0 deletions CXXException.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,12 @@ def generateCXXBody(self, config):
// call getLocalizedMessage
jstring description = (jstring) curEnv->CallObjectMethod(javaException, getLocalizedMessageId);

if (curEnv->ExceptionCheck())
{
curEnv->ExceptionClear();
return "";
}

if (description == NULL)
{
return "";
Expand Down Expand Up @@ -442,6 +448,12 @@ def generateCXXBody(self, config):
// call getStackTrace
jobjectArray stackTrace = (jobjectArray) curEnv->CallObjectMethod(javaException, getStackTraceId);

if (curEnv->ExceptionCheck())
{
curEnv->ExceptionClear();
return "";
}

if (stackTrace == NULL)
{
return "";
Expand All @@ -463,6 +475,15 @@ def generateCXXBody(self, config):
// call to string on the object
jstring stackElementString = (jstring) curEnv->CallObjectMethod(curStackTraceElement, toStringId);

if (curEnv->ExceptionCheck())
{
curEnv->ExceptionClear();
curEnv->DeleteLocalRef(stackTraceElementClass);
curEnv->DeleteLocalRef(stackTrace);
curEnv->DeleteLocalRef(curStackTraceElement);
return res;
}

if (stackElementString == NULL)
{
curEnv->DeleteLocalRef(stackTraceElementClass);
Expand Down Expand Up @@ -505,6 +526,14 @@ def generateCXXBody(self, config):
// call the getName function
jstring javaName = (jstring) curEnv->CallObjectMethod(exceptionClass, getNameId);

if (curEnv->ExceptionCheck())
{
curEnv->ExceptionClear();
curEnv->DeleteLocalRef(exceptionClass);
curEnv->DeleteLocalRef(classClass);
return "";
}

if (javaName == NULL)
{
return "";
Expand Down
9 changes: 2 additions & 7 deletions datatypes/dataGiws.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@
from JNIFrameWork import JNIFrameWork


def abstractMethod(obj=None):
"""Use this instead of 'pass' for the body of abstract methods."""
raise Exception(f"Unimplemented abstract method: {obj}")


#
# This class intend to create a generic object for datatype
# see http://en.wikipedia.org/wiki/Java_Native_Interface#Mapping_types
Expand Down Expand Up @@ -126,11 +121,11 @@ def getCallStaticMethod(self):

def getRealJavaType(self):
"""Returns the real datatype"""
abstractMethod(self)
raise NotImplementedError(type(self).__name__)

def getDescription(self):
"""Returns the description"""
abstractMethod(self)
raise NotImplementedError(type(self).__name__)

def setIsArray(self, isItAnArray):
"""Defines if we have to deal with an array or not"""
Expand Down
2 changes: 1 addition & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ SHELL = /bin/sh

# list of buildable examples
EX = basic_example example1 example2 example3 example4 example5 inherit bytebuffer \
bug_no_param_int_array bug_disable_return bug_string_array_len
bug_no_param_int_array bug_disable_return bug_string_array_len bug_nonstatic_exception


# verify that JAVA_HOME is set to something (should be the bare minimum)
Expand Down
82 changes: 82 additions & 0 deletions examples/bug_nonstatic_exception/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
SHELL = /bin/sh

# verify that JAVA_HOME is set to something (should be the bare minimum)
ifndef JAVA_HOME
$(error ERROR: Variable JAVA_HOME is not set!)
endif


#
# C++ compiler options
#
CC = g++
CFLAGS = -g
INCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
LIBS = -ljvm -L$(JAVA_HOME)/lib/server/

#
# Java compiler option
#
JCC = $(JAVA_HOME)/bin/javac
JFLAGS =

#
# GIWS options
#
GIWS = ../../giws
GFLAGS = -p --throws-exception-on-error -g

#
# GIWS PROJECT INFORMATION
#
PACKAGE_NAME = bug_nonstatic_exception
OBJECT_NAME = MyThrowingObject
BINARY = main

GIWS_CPP_FILE = main.cpp
GIWS_DESC_FILE = $(OBJECT_NAME).giws.xml
GIWS_OUT_FILES = $(addprefix $(PACKAGE_NAME),.cpp .hxx)


# in case of --throws-exception-on-error, add 2 files to the list
# of the ones generated by GIWS.
ifneq (,$(findstring --throws-exception-on-error,$(GFLAGS)))
GIWS_OUT_FILES += GiwsException.cpp GiwsException.hxx
endif


#########################################################################
#########################################################################
#########################################################################

# look for sources in current folder and in package name
VPATH = .:$(PACKAGE_NAME)


all: $(OBJECT_NAME).class $(BINARY)


# build java class file
$(OBJECT_NAME).class: $(OBJECT_NAME).java
$(JCC) $(JFLAGS) $<


# build output binary
$(BINARY): $(GIWS_OUT_FILES)
$(CC) $(GIWS_CPP_FILE) $(GIWS_OUT_FILES) $(CFLAGS) $(LIBS) $(INCLUDES) -o $(BINARY)
@if test $(MAKELEVEL) -eq 0; then \
echo "==========================================================================="; \
echo "Dont forget to set library path before running the program:"; \
echo "# export LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(JAVA_HOME)/lib/server/"; \
echo "==========================================================================="; \
fi


# run giws to generate cpp code
$(GIWS_OUT_FILES):
$(GIWS) -f $(GIWS_DESC_FILE) $(GFLAGS)


# cleanup giws generated files (cpp/hxx, bin) and .class
clean:
rm -f $(GIWS_OUT_FILES) $(PACKAGE_NAME)/$(OBJECT_NAME).class $(BINARY)
12 changes: 12 additions & 0 deletions examples/bug_nonstatic_exception/MyThrowingObject.giws.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!--
Regression test: the exception check after the Java call used to be
generated only for static methods. An exception thrown by a non-static
method was silently carried into the next JNI call instead of being
turned into a C++ exception with the throws-exception-on-error option.
-->

<package name="bug_nonstatic_exception">
<object name="MyThrowingObject">
<method name="alwaysThrows" returnType="void" />
</object>
</package>
16 changes: 16 additions & 0 deletions examples/bug_nonstatic_exception/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Regression test for the missing exception check on non-static methods.

Before giws 3.1.0 the generated code only checked for a pending Java
exception after calls to static methods. With
--throws-exception-on-error, an exception thrown by a non-static Java
method was never converted into a GiwsException::JniCallMethodException.

main returns 0 only if the exception is caught in C++.

Defines where is the JDK
# export JAVA_HOME=/path/to/java/

Build and run
# make
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/lib/server/
# ./main
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package bug_nonstatic_exception;

public class MyThrowingObject {

public void alwaysThrows() {
throw new IllegalStateException("thrown from a non-static method");
}
}
52 changes: 52 additions & 0 deletions examples/bug_nonstatic_exception/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Regression test: before giws 3.1.0, the exception check after the Java
call was only generated for static methods. The Java exception thrown
by this non-static method was never converted into a C++ exception, so
the try/catch below did not catch anything and the program fell through
to the failure branch.
*/

#include <iostream>
#include <jni.h>
#include "bug_nonstatic_exception.hxx"
#include "GiwsException.hxx"

JavaVM* create_vm() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[2];

args.version = JNI_VERSION_1_4;

args.nOptions = 2;
options[0].optionString = const_cast<char*>("-Djava.class.path=.");
options[1].optionString = const_cast<char*>("-Xcheck:jni");
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;

JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return jvm;
}

using namespace bug_nonstatic_exception;
using namespace std;

int main(){
JavaVM* jvm = create_vm();
MyThrowingObject *obj = new MyThrowingObject(jvm);

try {
obj->alwaysThrows();
} catch (GiwsException::JniException & e) {
cout << "Exception caught from a non-static method: "
<< e.getJavaDescription() << endl;
cout << "Exception name: " << e.getJavaExceptionName() << endl;
delete obj;
return 0;
}

cerr << "FAILED: the Java exception was not converted into a C++ exception" << endl;
delete obj;
return 1;
}
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ script-files = ["giws"]

[tool.setuptools.dynamic]
version = { attr = "configGiws.__version__" }

[tool.pytest.ini_options]
testpaths = ["tests"]
Loading
Loading