Skip to content

Commit 3232f34

Browse files
authored
Merge pull request #1474 from lesserwhirls/gh-1473
Fix netCDF-C loading in RuntimeConfigParser
2 parents ad7903a + c5f9486 commit 3232f34

7 files changed

Lines changed: 50 additions & 7 deletions

File tree

cdm/core/src/main/java/ucar/nc2/NetcdfFileWriter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ protected NetcdfFileWriter(Version version, String location, boolean isExisting,
194194
if (version.useJniIosp()) {
195195
IOServiceProviderWriter spi;
196196
try {
197-
// Nc4Iosp.setLibraryAndPath(path, name);
198197
Class iospClass = this.getClass().getClassLoader().loadClass("ucar.nc2.jni.netcdf.Nc4Iosp");
199198
Constructor<IOServiceProviderWriter> ctor = iospClass.getConstructor(Version.class);
200199
spi = ctor.newInstance(version);

cdm/core/src/main/java/ucar/nc2/util/xml/RuntimeConfigParser.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
2+
* Copyright (c) 1998-2025 John Caron and University Corporation for Atmospheric Research/Unidata
33
* See LICENSE for license information.
44
*/
55

@@ -269,7 +269,7 @@ public static void read(org.jdom2.Element root, StringBuilder errlog) {
269269
// so we cannot refer to the Nc4Iosp.class and NetcdfClibrary.class object.
270270
String nc4IospClassName = "ucar.nc2.jni.netcdf.Nc4Iosp";
271271
// The setLibraryAndPath method from Nc4Iosp has been deprecated
272-
// and splited into separated class: NetcdfClibrary
272+
// and split into separated class: NetcdfClibrary
273273
String netcdfClibraryClassName = "ucar.nc2.ffi.netcdf.NetcdfClibrary";
274274
/*
275275
* <Netcdf4Clibrary>
@@ -285,8 +285,9 @@ public static void read(org.jdom2.Element root, StringBuilder errlog) {
285285
if (path != null && name != null) {
286286
// reflection is used to decouple optional jars
287287
try {
288-
Class netcdfClibraryClass = RuntimeConfigParser.class.getClassLoader().loadClass(netcdfClibraryClassName);
289-
Method method = netcdfClibraryClass.getMethod("setLibraryAndPath", String.class, String.class);
288+
Class<?> netcdfClibraryClass =
289+
RuntimeConfigParser.class.getClassLoader().loadClass(netcdfClibraryClassName);
290+
Method method = netcdfClibraryClass.getMethod("setLibraryNameAndPath", String.class, String.class);
290291
method.invoke(null, path, name); // static method has null for object
291292
} catch (Throwable e) {
292293
errlog.append(netcdfClibraryClassName + " is not on classpath\n");

docs/src/site/pages/netcdfJava/netcdf4Clibrary.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ For standalone CDM library use, you can:
101101
* create a system environment variable: `JNA_PATH=/path/to/library`
102102
* set a Java property on the command line: `-Djna.library.path=/path/to/library`
103103
* set the library path and name in the runtime configuration file
104-
* directly call `Nc4Iosp.setLibraryAndPath()` from your Java program
104+
* directly call `ucar.nc2.ffi.netcdf.NetcdfClibrary.setLibraryNameAndPath` from your Java program
105+
(Note: this must be called prior to calling `isLibraryPresent()` or `getForeignFunctionInterface()` as the C library can only be successfully loaded once)
105106

106107
In all cases, we recommended that you use an absolute path to specify the library location.
107108

docs/src/site/pages/netcdfJava_tutorial/runtime/runtimeloading.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Runtime loading
3-
last_updated: 2021-06-08
3+
last_updated: 2025-08-12
44
sidebar: netcdfJavaTutorial_sidebar
55
permalink: runtime_loading.html
66
toc: false

netcdf4/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
testImplementation project(':cdm-test-utils')
2020

2121
testImplementation 'com.google.truth:truth'
22+
testImplementation 'org.jdom:jdom2'
2223

2324
testRuntimeOnly 'ch.qos.logback:logback-classic'
2425
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2025 University Corporation for Atmospheric Research/Unidata
3+
* See LICENSE.txt for license information.
4+
*/
5+
6+
package ucar.nc2.util.xml;
7+
8+
import static com.google.common.truth.Truth.assertThat;
9+
10+
import java.io.File;
11+
import java.io.FileInputStream;
12+
import java.io.IOException;
13+
import java.nio.file.Paths;
14+
import org.junit.Test;
15+
16+
public class TestRuntimeConfigParser {
17+
@Test
18+
public void testReflection() throws IOException {
19+
// not testing that the loading actually work, but testing that the reflection
20+
// calls in the RuntimeConfigParser work
21+
File nj22config =
22+
Paths.get("src/test/resources/runtimeConfig/nj22Config.xml").toAbsolutePath().normalize().toFile();
23+
StringBuilder errlog = new StringBuilder();
24+
try (FileInputStream fis = new FileInputStream(nj22config)) {
25+
RuntimeConfigParser.read(fis, errlog);
26+
}
27+
String err = errlog.toString();
28+
assertThat(err).isNotEmpty();
29+
// since this test lives in the netcdf4 subproject, we should only see
30+
// the "is not on classpath" message if the reflection call used in the
31+
// RuntimeConfigParser code fails
32+
assertThat(err).doesNotContain("is not on classpath");
33+
}
34+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<nj22Config>
2+
<Netcdf4Clibrary>
3+
<libraryPath>/not/a/real/path</libraryPath>
4+
<libraryName>netcdf</libraryName>
5+
<useForReading>false</useForReading>
6+
</Netcdf4Clibrary>
7+
</nj22Config>

0 commit comments

Comments
 (0)