Skip to content

Support configurable netCDF-Java CLASSPATH via R option and env var #16

@cofinoa

Description

@cofinoa

Background / Motivation

A developer or user of loadeR.java may eventually need to run with different netCDF-Java setups without editing the package code:

  • In production, use a single JAR (e.g., netcdfAll-*.jar).
  • In development, point to class directories and/or multiple JARs (e.g., Gradle build/classes/java/main, build/resources/main, plus deps).
  • In packaged installs, if nothing is configured, just use JAR bundle with the R package.

Right now, switching between these scenarios requires modifying the package or copying JARs into the repo. A small, standard initialization hook would cover all cases cleanly.

Proposed Behaviour (non-breaking)

loadeR.java should determine the Java classpath for netCDF-Java at startup using this precedence:

  1. R option: loadeR.netcdf_java_classpath
  2. Environment variable: LOADER_NETCDF_JAVA_CLASSPATH
  3. Bundled fallback: package directory java/ (include directories and JARs in the classpath)

Both the option and env var accept a classpath string: one or many entries, directories and/or JARs, separated by the platform path separator (: on Linux/macOS, ; on Windows).

Why this approach

  • Mirrors standard JVM usage (explicit -cp semantics).
  • Avoids hardcoding a specific artifact (e.g., netcdfAll) and works equally well for ToolsUI fat jars or module class dirs.
  • Keeps the current default (bundled jars) working for users who don’t configure anything.

User-facing Configuration (examples)

Production (single JAR)

# Session override
options(loadeR.netcdf_java_classpath = "/opt/netcdf-java/netcdfAll-5.9.0.jar")
library(loadeR.java)

Development (directories + jars)

options(loadeR.netcdf_java_classpath = paste(
  "~/dev/netcdf-java/cdm/build/classes/java/main",
  "~/dev/netcdf-java/cdm/build/resources/main",
  "~/dev/netcdf-java/grib/build/classes/java/main",
  "~/dev/netcdf-java/grib/build/resources/main",
  sep = .Platform$path.sep
))
library(loadeR.java)

Environment variable (persistent, default)

# Linux/macOS
export LOADER_NETCDF_JAVA_CLASSPATH="/opt/netcdf-java/lib/*"
R -q -e "library(loadeR.java)"

# Windows PowerShell
$env:LOADER_NETCDF_JAVA_CLASSPATH = "C:\netcdf-java\lib\*"
R -NoSave -e "library(loadeR.java)"

Bundled fallback (no config)

  • Drop any required jars and directory into java/.

Expected Startup Messages

  • Print which source was used:
    • netCDF-Java CLASSPATH from R option loadeR.netcdf_java_classpath: ...
    • netCDF-Java CLASSPATH from env LOADER_NETCDF_JAVA_CLASSPATH: ...
    • netCDF-Java CLASSPATH from bundled inst/java/*: ...

Implementation Notes (sketch, not a full rewrite)

  • In .onLoad():
    • Read getOption("loadeR.netcdf_java_classpath", "") and Sys.getenv("LOADER_NETCDF_JAVA_CLASSPATH", "").
    • Split by .Platform$path.sep.
    • If both option and env are set and differ, option wins; consider warning (or loadeR.java.strict_classpath to error).
    • Fallback: file.path(system.file("java", package = pkgname), "*").
    • Initialize JVM via rJava::.jinit(classpath = classpath, parameters = ...).
  • In .onAttach():
    • Optionally report detected netCDF-Java runtime version via Package.getImplementationVersion() when available; otherwise print a friendly “version unknown/dev” message when using dirs/wildcards.

Tests (suggested)

  • Option supplies two directories → both present in .jclassPath().
  • Env var supplies wildcard dir → jars are available (verify a known class loads).
  • Neither option nor env set → classpath contains one entry ending in inst/java/*.
  • Already-initialized JVM → entries added, wildcard warning printed.
  • Windows path separator (;) works as expected.

Documentation snippet (README)

#### Selecting netCDF-Java at startup

`loadeR.java` looks for a netCDF-Java classpath in this order:

1. `options(loadeR.netcdf_java_classpath)`
2. `LOADER_NETCDF_JAVA_CLASSPATH` (env var)
3. All jars under the package’s `inst/java/` (`inst/java/*`)

The classpath may contain one or more directories and/or JARs separated by the platform path separator (`:` on Linux/macOS, `;` on Windows). Wildcards like `.../lib/*` are supported and are expanded by the JVM at startup. Example:

```r
options(loadeR.netcdf_java_classpath = "/opt/netcdf-java/lib/*")
library(loadeR.java)
```

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions