Skip to content

Common Client Changes

Sean Arms edited this page Dec 4, 2020 · 2 revisions

This page highlights common changes to client code that are necessary to move to the new public API. The public API is described by the javadocs.

As a rule, deprecated methods indicate their replacement in the javadocs that includes deprecations. Consider these sets of javadocs definitive and open an issue if they are incorrect, misleading, or missing. In some cases, functionality is being withdrawn. If that impacts you and there is no workaround, please open an issue and let us know.

Please open issues with any tips you have for changes as you encounter them.

Design considerations

Best practices for Java Libraries

We are following Google Best Practices for Java Libraries for the evolution of interconnected Java libraries. If you are building Java libraries for use by others outside of your organization, we strongly recommend them.

Our transition to fully using these practices is a long term goal that will be realized over the next several versions of Netcdf-Java.

Building Immutable Objects

The overarching change being made for version 6 is to make (almost) all objects immutable. To do so, methods that mutate internal state are deprecated in version 5 (the maint-5.x branch), and will be removed in version 6 (currently the develop branch). Creating an object is done with a Builder, which are static nested classes within the class that is being built. All builders follow the same fluent api idiom: Class.builder().setProperty(*).addProperty(*).build().

Separating the creation and the use of an object greatly simplifies the API, and immutability has proven to be an essential tool for bug-free programming.

Changing Collection return types to Immutable

Most methods that return a Collection will return the Immutable variant of it in version 6. For example, List<*> will become ImmutableList<*>, Set<*> will become ImmutableSet<*>, Map<*> will become ImmutableMap<*>, etc.

We will use the Guava immutable collections in order to make immutability part of the API contract.

Since ImmutableList implements List, client code does not need to be changed to compile. The list must be copied to a mutable list if the client needs to modify it, so this change may uncover those instances.

See https://github.com/google/guava/wiki/ImmutableCollectionsExplained for more background.

Changes to be made in version 6, not in version 5

Certain changes will wait until version 6, and can't be backported to version 5, because they break existing code.

  • ucar.nc2.dataset.SequenceDS will extend ucar.nc2.Sequence, not ucar.nc2.dataset.StructureDS
  • Uses of ucar.nc2.util.Optional will be changed to use java.util.Optional.
  • In ucar.unidata.geoloc.Projection:
    • latLonToProj() will return ProjectionPoint, not ProjectionPointImpl.
    • projToLatLon() will return LatLonPoint, not LatLonPointImpl.

ucar.nc2

ucar.nc2.Attribute

An Attribute no longer has a reference to its containing Group or Variable.

There is no getFullName(); getName() is preferred, getShortName() returns getName().

ucar.nc2.CDMNode

CDMNode will be moved into the DAP modules that use it. The classes in ucar.nc2 will not extend it.

ucar.nc2.Dimension

A Dimension no longer has a reference to its containing Group.

There is no getFullName(); getName() is preferred, getShortName() returns getName().

Public static methods from ucar.nc2.Dimension have been moved to ucar.nc2.Dimensions.

ucar.nc2.EnumTypedef

The method getMap() return a BiMap. Since a Bimap is a Map, client code does not need to change.

String lookupEnumString(int e) returns null if not found.

ucar.nc2.Group

Group does not implement AttributeContainer in 6, use Group.attributes(). findAttribute(String name) and findAttributeString(String attName, String defaultValue) remain as convenience methods that call the equivalent method in attributes().

Use findGroupLocal() instead of findGroup() to look for subgroups local to this Group.

Use findVariableLocal() instead of findVariable() to look for variables local to this Group. Use findVariableOrInPsrent() to look for variables in this Group or a parent Group. Use NetcdfFile.findVariable(String fullNameEscaped) to find a variable anywhere in the NetcdfFile using the full name.

ucar.nc2.NetcdfFile

All public static methods from ucar.nc2.NetcdfFile have been moved to ucar.nc2.NetcdfFiles. NetcdfFiles uses the new internal IOSP classes, which produce immutable NetcdfFile objects.

In particular, open(*) and openInMemory(*) have been moved to NetcdfFiles.

As described above, NetcdfFile objects are no longer constructed using a constructor with various mutator methods, such as the add methods on ucar.nc2.NetcdfFile objects. Instead, NetcdfFile objects are constructed using a ucar.nc2.NetcdfFile.Builder builder object.

ucar.nc2.Variable

Variable does not implement AttributeContainer in 6, use Variable.attributes(). findAttribute(String name) and findAttributeString(String attName, String defaultValue) remain as convenience methods that call the equivalent method in attributes().

ucar.nc2.dataset

ucar.nc2.NetcdfDataset

All public static methods from ucar.nc2.dataset.NetcdfDataset have been moved to ucar.nc2.dataset.NetcdfDatasets.

In particular the acquireFile(*), acquireDataset(*), openFile(*) and openDataset(*) methods have been moved to NetcdfDatasets.

NetcdfDataset objects are no longer constructed using a constructor and the various mutator methods such as add methods on ucar.nc2.dataset.NetcdfDataset. Instead, NetcdfDataset objects are constructed using the a ucar.nc2.dataset.NetcdfFile.Builder builder object.

THREDDS Client Catalogs

thredds.catalog

Constructing and reading THREDDS Client Catalogs is now handled by thredds.client.catalog.builder.CatalogBuilder

Existing catalogs can be read using one of the following methods:

  • buildFromCatref(CatalogRef catref)
  • buildFromJdom(org.jdom2.Element root, URI docBaseUri)
  • buildFromLocation(String location, URI baseURI)
  • buildFromStream(InputStream stream, URI docBaseUri)
  • buildFromString(String catalogAsString, URI docBaseUri)
  • buildFromURI(URI uri)

Writing with Netcdf-Java

All of the classes for writing in the ucar.nc2 package are deprecated (ucar.nc2.FileWriter2, ucar.nc2.NetcdfFileWriter, ucar.nc2.NcDumpW), and equivalent functionality now lives in ucar.nc2.write.

NetcdfDataset.main() was used as a CLI for writing a CDM file (eg GRIB) to NetCDF. This is deprecated and replaced by ucar.nc2.write.Nccopy.

  • ucar.nc2.write.Nccopy is a command line interface similar to the nccopy c utility, replacing ucar.nc2.dataset.NetcdfDataset.main().
  • ucar.nc2.write.Ncdump is a command line interface similar to ncdump c utility, replacing ucar.nc2.NCdumpW.
  • ucar.nc2.write.NetcdfCopier replaces FileWriter2, this is the medium level interface.
  • ucar.nc2.write.NetcdfFormatWriter replaces NetcdfFileWriter, this is the low level interface.

Note that Netcdf-Java only supports writing to netCDF-3 or netCDF-4 files (this is not new to version 5 or 6). In the case of netCDF-4, the netCDF C library must be loaded.

The notion of being in define mode is no longer supported. For netCDF-3, writing to existing files is limited to writing data to existing variables, including extending along the unlimited dimension. NetCDF-4 supports arbitrary modifications to existing files.

Writing NcML

ucar.nc2.NcmlWriter is deprecated. To write to NcML (as a file, stream, or string), use ucar.nc2.write.NcmlWriter.

Service Provider Interfaces

The use of Java Service Provider Interfaces is not new, but in version 5+, we use it exclusively for dynamic runtime class loading and discovery. A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services of the jar file that the implementing class lives in. See https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html for details.

All of Unidata's released jar files have these provider-configuration files, there is nothing you need to do. The information here is needed only if you are adding dynamically loaded classes to netCDF-Java.

ucar.unidata.iosp.IOServiceProvider

Custom IOSPs are loaded into netCDF-Java by implementing the ucar.unidata.iosp.IOServiceProvider interface. These depend on having a RandomAccessFile to read data and metadata from.

Version 5 contains extensive module refactoring and dependency management in order to minimize runtime memory use. The core CDM library now contains only netCDF-3, netCDF-4, HDF-4, and HDF-5 IOSPs. All other IOSPs are discovered at runtime by examining the jar files on the classpath.

ucar.nc2.dataset.spi.NetcdfFileProvider

NetcdfFile providers that are not based on RandomAccessFile implement the NetcdfFileProvider interface. These are typically remote access protocols such as OpenDAP and CdmRemote.

ucar.nc2.dataset.spi.CoordSystemBuilderFactory

A CoordSystemBuilder knows how to interpret a dataset's metadata to construct Coordinate Systems for the dataset. These implement a CoordSystemBuilderFactory interface for runtime discovery.

ucar.unidata.io.spi.RandomAccessFileProvider

A RandomAccessFileProvider can provide a ucar.unidata.io.RandomAccessFile that is not based on a java.io.RandomAccessFile. This is used for remote access like HttpRandomAccessFile and S3RandomAccessFile, and non-standard access like InMemoryRandomAccessFile.

Utility and Miscellaneous classes

Most utility and miscellaneous classes have been marked INTERNAL CLASSES DO NOT USE. If you need to use any of these directly, please let us know. These include:

  • ucar.nc2.util.*
  • ucar.unidata.util.*
  • subpackages of ucar.unidata.io.*

ucar.unidata.geoloc

These concrete classes will be removed, only use the interfaces:

  • EarthLocationImpl: use EarthLocation
  • LatLonPointImpl: use LatLonPoint
  • ProjectionImpl: use Projection
  • ProjectionPointImpl: use ProjectionPoint
  • StationImpl: use Station
  • VerticalTransformImpl: use VerticalTransform

Public static methods have been moved from LatLonPointImpl to LatLonPoints.

All subpackages are withdrawn from the public API (ogc, projection, vertical).

Changes to the public API in version 6, not in version 5

  • The above interfaces will become immutable classes (should be no client code changes needed).
  • VerticalTransform will move from package ucar.unidata.geoloc.vertical to ucar.unidata.geoloc.

In ucar.unidata.geoloc.Projection:

  • ProjectionPoint latLonToProj(LatLonPoint latlon, ProjectionPoint result);
  • LatLonPoint projToLatLon(ProjectionPoint ppt, LatLonPoint result);