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:
- R option:
loadeR.netcdf_java_classpath
- Environment variable:
LOADER_NETCDF_JAVA_CLASSPATH
- 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)
```
Background / Motivation
A developer or user of
loadeR.javamay eventually need to run with different netCDF-Java setups without editing the package code:netcdfAll-*.jar).build/classes/java/main,build/resources/main, plus deps).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.javashould determine the Java classpath for netCDF-Java at startup using this precedence:loadeR.netcdf_java_classpathLOADER_NETCDF_JAVA_CLASSPATHjava/(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
-cpsemantics).netcdfAll) and works equally well for ToolsUI fat jars or module class dirs.User-facing Configuration (examples)
Production (single JAR)
Development (directories + jars)
Environment variable (persistent, default)
Bundled fallback (no config)
java/.Expected Startup Messages
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)
.onLoad():getOption("loadeR.netcdf_java_classpath", "")andSys.getenv("LOADER_NETCDF_JAVA_CLASSPATH", "")..Platform$path.sep.loadeR.java.strict_classpathto error).file.path(system.file("java", package = pkgname), "*").rJava::.jinit(classpath = classpath, parameters = ...)..onAttach():Package.getImplementationVersion()when available; otherwise print a friendly “version unknown/dev” message when using dirs/wildcards.Tests (suggested)
.jclassPath().inst/java/*.;) works as expected.Documentation snippet (README)