diff --git a/Dockerfile b/Dockerfile index ae5edace42519..98a5dfe13c9ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -153,6 +153,7 @@ RUN --mount=type=cache,target=/root/.cache \ source .venv/bin/activate && \ python -m localstack.cli.lpm install \ lambda-runtime \ + jpype-jsonata \ dynamodb-local && \ chown -R localstack:localstack /usr/lib/localstack && \ chmod -R 777 /usr/lib/localstack diff --git a/localstack-core/localstack/dev/run/__main__.py b/localstack-core/localstack/dev/run/__main__.py index 610c77e4fac09..39ab236c9e3c2 100644 --- a/localstack-core/localstack/dev/run/__main__.py +++ b/localstack-core/localstack/dev/run/__main__.py @@ -36,7 +36,7 @@ type=str, required=False, help="Overwrite the container image to be used (defaults to localstack/localstack or " - "localstack/localstack-pro.", + "localstack/localstack-pro).", ) @click.option( "--volume-dir", @@ -66,7 +66,7 @@ "--mount-source/--no-mount-source", is_flag=True, default=True, - help="Mount source files from localstack, localstack-ext, and moto into the container.", + help="Mount source files from localstack and localstack-ext. Use --local-packages for optional dependencies such as moto.", ) @click.option( "--mount-dependencies/--no-mount-dependencies", diff --git a/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py b/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py index bf1ad25843035..459dba2ed80b2 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py +++ b/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py @@ -8,8 +8,8 @@ import jpype import jpype.imports -from localstack.services.stepfunctions.asl.jsonata.packages import jsonata_package from localstack.services.stepfunctions.asl.utils.encoding import to_json_str +from localstack.services.stepfunctions.packages import jpype_jsonata_package from localstack.utils.objects import singleton_factory JSONataExpression = str @@ -40,17 +40,19 @@ class _JSONataJVMBridge: _java_JSONATA: "com.dashjoin.jsonata.Jsonata.jsonata" # noqa def __init__(self): - installer = jsonata_package.get_installer() + installer = jpype_jsonata_package.get_installer() installer.install() from jpype import config as jpype_config jpype_config.destroy_jvm = False + # Limitation: We can only start one JVM instance within LocalStack and using JPype for another purpose + # (e.g., event-ruler) fails unless we change the way we load/reload the classpath. jvm_path = installer.get_java_lib_path() jsonata_libs_path = Path(installer.get_installed_dir()) - event_ruler_libs_pattern = jsonata_libs_path.joinpath("*") - jpype.startJVM(jvm_path, classpath=[event_ruler_libs_pattern], interrupt=False) + jsonata_libs_pattern = jsonata_libs_path.joinpath("*") + jpype.startJVM(jvm_path, classpath=[jsonata_libs_pattern], interrupt=False) from com.fasterxml.jackson.databind import ObjectMapper # noqa from com.dashjoin.jsonata.Jsonata import jsonata # noqa diff --git a/localstack-core/localstack/services/stepfunctions/asl/jsonata/packages.py b/localstack-core/localstack/services/stepfunctions/packages.py similarity index 70% rename from localstack-core/localstack/services/stepfunctions/asl/jsonata/packages.py rename to localstack-core/localstack/services/stepfunctions/packages.py index 277959f9143fa..b96f7a8d775f0 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/jsonata/packages.py +++ b/localstack-core/localstack/services/stepfunctions/packages.py @@ -12,6 +12,9 @@ class JSONataPackage(Package): def __init__(self): super().__init__("JSONataLibs", JSONATA_DEFAULT_VERSION) + # Match the dynamodb-local JRE version to reduce the LocalStack image size by sharing the same JRE version + self.java_version = "21" + def get_versions(self) -> list[str]: return list(JSONATA_JACKSON_VERSION_STORE.keys()) @@ -24,10 +27,13 @@ def __init__(self, version: str): jackson_version = JSONATA_JACKSON_VERSION_STORE[version] super().__init__( f"pkg:maven/com.dashjoin/jsonata@{version}", + # jackson-databind is imported in jsonata.py as "from com.fasterxml.jackson.databind import ObjectMapper" + # jackson-annotations and jackson-core are dependencies of jackson-databind: + # https://central.sonatype.com/artifact/com.fasterxml.jackson.core/jackson-databind/dependencies f"pkg:maven/com.fasterxml.jackson.core/jackson-core@{jackson_version}", f"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@{jackson_version}", f"pkg:maven/com.fasterxml.jackson.core/jackson-databind@{jackson_version}", ) -jsonata_package = JSONataPackage() +jpype_jsonata_package = JSONataPackage() diff --git a/localstack-core/localstack/services/stepfunctions/plugins.py b/localstack-core/localstack/services/stepfunctions/plugins.py new file mode 100644 index 0000000000000..b407ee2875396 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/plugins.py @@ -0,0 +1,9 @@ +from localstack.packages import Package, package + + +@package(name="jpype-jsonata") +def jpype_jsonata_package() -> Package: + """The Java-based jsonata library uses JPype and depends on a JVM installation.""" + from localstack.services.stepfunctions.packages import jpype_jsonata_package + + return jpype_jsonata_package