From e9b9698e5721fa69b431f100417435e22f1499c4 Mon Sep 17 00:00:00 2001 From: Nick Griffiths Date: Tue, 12 May 2026 22:00:44 +1200 Subject: [PATCH 1/2] Add centralized service loader utility This allows library consumers to control the classloader in applications with non-trivial classloading requirements. --- .../java/ucar/nc2/util/NcServiceLoader.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 cdm/core/src/main/java/ucar/nc2/util/NcServiceLoader.java diff --git a/cdm/core/src/main/java/ucar/nc2/util/NcServiceLoader.java b/cdm/core/src/main/java/ucar/nc2/util/NcServiceLoader.java new file mode 100644 index 0000000000..9f7f15cf6c --- /dev/null +++ b/cdm/core/src/main/java/ucar/nc2/util/NcServiceLoader.java @@ -0,0 +1,50 @@ +package ucar.nc2.util; + +import java.util.ServiceLoader; + +/** + * Centralized access to the jdk's built in {@link ServiceLoader} utility to support using the NetCDF library in + * applications with non-trivial class loading requirements. + */ +public class NcServiceLoader { + + private static ClassLoader classLoader; + + public static ServiceLoader load(Class service) { + ClassLoader useClassLoader; + + if (classLoader == null) { + useClassLoader = Thread.currentThread().getContextClassLoader(); + } else { + useClassLoader = classLoader; + } + + return ServiceLoader.load(service, useClassLoader); + } + + /** + * Services will be loaded using whatever happens to be the current thread's context class loader at the time + * services are loaded. This is the default behaviour and will work for applications that use the NetCDF library + * without any special class-loading requirements. + */ + public static void useContextClassLoader() { + classLoader = null; + } + + /** + * Services will be loaded using the same classloader that loaded this class, assumed to be + * the same one that will load the rest of the netcdf library. This option is suitable for applications that + * use only the built-in functionality, i.e they do not extend the library via the {@link ServiceLoader} mechanism + */ + public static void usePackageClassLoader() { + classLoader = NcServiceLoader.class.getClassLoader(); + } + + /** + * Services will be loaded using a specific custom class loader. This class loader should 'descend' from the one that + * loaded the NetCDF library code, otherwise any services loaded are likely to throw {@link ClassCastException}s + */ + public static void useCustomClassLoader(ClassLoader useClassLoader) { + classLoader = useClassLoader; + } +} From a37efdbd3fb3040dacb3172446cec477f7003ebb Mon Sep 17 00:00:00 2001 From: Nick Griffiths Date: Tue, 12 May 2026 22:00:23 +1200 Subject: [PATCH 2/2] Switch to using centralized service loader --- .../java/thredds/inventory/CollectionSpecParsers.java | 4 ++-- .../src/main/java/thredds/inventory/MControllers.java | 4 ++-- cdm/core/src/main/java/thredds/inventory/MFiles.java | 6 ++++-- cdm/core/src/main/java/ucar/nc2/NetcdfFile.java | 5 +++-- cdm/core/src/main/java/ucar/nc2/NetcdfFiles.java | 5 +++-- .../main/java/ucar/nc2/dataset/CoordSysBuilder.java | 3 ++- .../src/main/java/ucar/nc2/dataset/NetcdfDataset.java | 5 +++-- .../src/main/java/ucar/nc2/dataset/NetcdfDatasets.java | 6 +++--- .../src/main/java/ucar/nc2/dataset/VariableDS.java | 3 ++- .../src/main/java/ucar/nc2/dt/grid/GridDataset.java | 4 ++-- cdm/core/src/main/java/ucar/nc2/filter/Filters.java | 4 ++-- .../java/ucar/nc2/ft/FeatureDatasetFactoryManager.java | 4 ++-- .../src/main/java/ucar/nc2/ft/fmrc/GridDatasetInv.java | 4 ++-- .../ucar/nc2/internal/dataset/CoordSystemFactory.java | 10 +++++----- 14 files changed, 37 insertions(+), 30 deletions(-) diff --git a/cdm/core/src/main/java/thredds/inventory/CollectionSpecParsers.java b/cdm/core/src/main/java/thredds/inventory/CollectionSpecParsers.java index fa9a9334cc..cca23ac609 100644 --- a/cdm/core/src/main/java/thredds/inventory/CollectionSpecParsers.java +++ b/cdm/core/src/main/java/thredds/inventory/CollectionSpecParsers.java @@ -5,8 +5,8 @@ package thredds.inventory; import java.util.Formatter; -import java.util.ServiceLoader; import javax.annotation.Nullable; +import ucar.nc2.util.NcServiceLoader; /** * Static helper methods for CollectionSpecParserAbstract objects. @@ -49,7 +49,7 @@ private static CollectionSpecParserProvider getProvider(String spec) { CollectionSpecParserProvider collectionSpecParserProvider = null; // look for dynamically loaded CollectionSpecParserProvider - for (CollectionSpecParserProvider provider : ServiceLoader.load(CollectionSpecParserProvider.class)) { + for (CollectionSpecParserProvider provider : NcServiceLoader.load(CollectionSpecParserProvider.class)) { if (provider.canParse(spec)) { collectionSpecParserProvider = provider; break; diff --git a/cdm/core/src/main/java/thredds/inventory/MControllers.java b/cdm/core/src/main/java/thredds/inventory/MControllers.java index 1dfbe54784..d50e7962fe 100644 --- a/cdm/core/src/main/java/thredds/inventory/MControllers.java +++ b/cdm/core/src/main/java/thredds/inventory/MControllers.java @@ -7,8 +7,8 @@ import java.io.IOException; import java.nio.file.DirectoryStream; -import java.util.ServiceLoader; import thredds.filesystem.ControllerOS; +import ucar.nc2.util.NcServiceLoader; public class MControllers { @@ -23,7 +23,7 @@ public static MController create(String location) { // look for dynamically loaded MControllerProviders if (location != null) { - for (MControllerProvider provider : ServiceLoader.load(MControllerProvider.class)) { + for (MControllerProvider provider : NcServiceLoader.load(MControllerProvider.class)) { if (provider.canScan(location)) { mControllerProvider = provider; break; diff --git a/cdm/core/src/main/java/thredds/inventory/MFiles.java b/cdm/core/src/main/java/thredds/inventory/MFiles.java index 799267ea50..e20650a2a0 100644 --- a/cdm/core/src/main/java/thredds/inventory/MFiles.java +++ b/cdm/core/src/main/java/thredds/inventory/MFiles.java @@ -6,7 +6,6 @@ package thredds.inventory; import java.io.IOException; -import java.util.ServiceLoader; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.slf4j.Logger; @@ -14,6 +13,9 @@ import thredds.filesystem.MFileOS; import thredds.filesystem.MFileOS7; import ucar.nc2.internal.ncml.NcmlReader; +import ucar.nc2.util.NcServiceLoader; + + /** * Static helper methods for MFile objects. @@ -34,7 +36,7 @@ public static MFile create(@Nonnull String location) { MFileProvider mFileProvider = null; // look for dynamically loaded MFileProviders - for (MFileProvider provider : ServiceLoader.load(MFileProvider.class)) { + for (MFileProvider provider : NcServiceLoader.load(MFileProvider.class)) { if (provider.canProvide(location)) { mFileProvider = provider; break; diff --git a/cdm/core/src/main/java/ucar/nc2/NetcdfFile.java b/cdm/core/src/main/java/ucar/nc2/NetcdfFile.java index 8730fa9383..e6d1fe7c40 100644 --- a/cdm/core/src/main/java/ucar/nc2/NetcdfFile.java +++ b/cdm/core/src/main/java/ucar/nc2/NetcdfFile.java @@ -56,6 +56,7 @@ import ucar.nc2.util.EscapeStrings; import ucar.nc2.util.IO; import ucar.nc2.util.Indent; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.util.cache.FileCacheIF; import ucar.nc2.util.cache.FileCacheable; import ucar.nc2.util.rc.RC; @@ -422,7 +423,7 @@ private static boolean canOpen(RandomAccessFile raf) throws IOException { if (N3header.isValidFile(raf)) { return true; } else { - for (IOServiceProvider iosp : ServiceLoader.load(IOServiceProvider.class)) { + for (IOServiceProvider iosp : NcServiceLoader.load(IOServiceProvider.class)) { log.info("ServiceLoader IOServiceProvider {}", iosp.getClass().getName()); System.out.printf("ServiceLoader IOServiceProvider found %s%n", iosp.getClass().getName()); if (iosp.isValidFile(raf)) { @@ -835,7 +836,7 @@ private static IOServiceProvider getIosp(RandomAccessFile raf) throws IOExceptio } else { // look for dynamically loaded IOSPs - for (IOServiceProvider loadedSpi : ServiceLoader.load(IOServiceProvider.class)) { + for (IOServiceProvider loadedSpi : NcServiceLoader.load(IOServiceProvider.class)) { if (loadedSpi.isValidFile(raf)) { Class c = loadedSpi.getClass(); try { diff --git a/cdm/core/src/main/java/ucar/nc2/NetcdfFiles.java b/cdm/core/src/main/java/ucar/nc2/NetcdfFiles.java index 74f17f028f..a3e92277de 100644 --- a/cdm/core/src/main/java/ucar/nc2/NetcdfFiles.java +++ b/cdm/core/src/main/java/ucar/nc2/NetcdfFiles.java @@ -36,6 +36,7 @@ import ucar.nc2.util.DiskCache; import ucar.nc2.util.EscapeStrings; import ucar.nc2.util.IO; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.util.rc.RC; import ucar.unidata.io.UncompressInputStream; import ucar.unidata.io.bzip2.CBZip2InputStream; @@ -423,7 +424,7 @@ public static ucar.unidata.io.RandomAccessFile getRaf(String location, int buffe if (raf == null) { // look for dynamically loaded RandomAccessFile Providers - for (RandomAccessFileProvider provider : ServiceLoader.load(RandomAccessFileProvider.class)) { + for (RandomAccessFileProvider provider : NcServiceLoader.load(RandomAccessFileProvider.class)) { if (provider.isOwnerOf(location)) { raf = provider.open(location, buffer_size); // might cause issues if the end of a resource location string @@ -809,7 +810,7 @@ private static IOServiceProvider getIosp(ucar.unidata.io.RandomAccessFile raf) t } else { // look for dynamically loaded IOSPs, and sort before using - final ServiceLoader iosps = ServiceLoader.load(IOServiceProvider.class); + final ServiceLoader iosps = NcServiceLoader.load(IOServiceProvider.class); final List sortedIosps = Lists.newArrayList(iosps); Collections.sort(sortedIosps); diff --git a/cdm/core/src/main/java/ucar/nc2/dataset/CoordSysBuilder.java b/cdm/core/src/main/java/ucar/nc2/dataset/CoordSysBuilder.java index 4b7b28b301..9bec29639c 100644 --- a/cdm/core/src/main/java/ucar/nc2/dataset/CoordSysBuilder.java +++ b/cdm/core/src/main/java/ucar/nc2/dataset/CoordSysBuilder.java @@ -16,6 +16,7 @@ import java.lang.reflect.Method; import java.io.IOException; import java.util.*; +import ucar.nc2.util.NcServiceLoader; /** * Abstract class for implementing Convention-specific parsing of netCDF files. @@ -401,7 +402,7 @@ public static CoordSysBuilderIF factory(NetcdfDataset ds, CancelTask cancelTask) // call static isMine() using reflection. CoordSysBuilderIF builder = null; if (convClass == null) { - for (CoordSysBuilderIF csb : ServiceLoader.load(CoordSysBuilderIF.class)) { + for (CoordSysBuilderIF csb : NcServiceLoader.load(CoordSysBuilderIF.class)) { Class c = csb.getClass(); Method m; diff --git a/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDataset.java b/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDataset.java index 0374e73285..5b48ebc22d 100644 --- a/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDataset.java +++ b/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDataset.java @@ -18,6 +18,7 @@ import ucar.nc2.iosp.IOServiceProvider; import ucar.nc2.ncml.NcMLReader; import ucar.nc2.util.CancelTask; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.util.cache.FileCache; import ucar.nc2.util.cache.FileFactory; import java.io.IOException; @@ -808,14 +809,14 @@ private static NetcdfFile openProtocolOrFile(DatasetUrl durl, int buffer_size, u } // look for dynamically loaded NetcdfFileProvider - for (NetcdfFileProvider provider : ServiceLoader.load(NetcdfFileProvider.class)) { + for (NetcdfFileProvider provider : NcServiceLoader.load(NetcdfFileProvider.class)) { if (provider.isOwnerOf(durl)) { return provider.open(durl.getTrueurl(), cancelTask); } } // look for providers who do not have an associated ServiceType. - for (NetcdfFileProvider provider : ServiceLoader.load(NetcdfFileProvider.class)) { + for (NetcdfFileProvider provider : NcServiceLoader.load(NetcdfFileProvider.class)) { if (provider.isOwnerOf(durl.getTrueurl())) { return provider.open(durl.getTrueurl(), cancelTask); } diff --git a/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDatasets.java b/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDatasets.java index 588d6abada..b54f16def8 100644 --- a/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDatasets.java +++ b/cdm/core/src/main/java/ucar/nc2/dataset/NetcdfDatasets.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.Reader; import java.util.EnumSet; -import java.util.ServiceLoader; import java.util.Set; import ucar.nc2.NetcdfFile; import ucar.nc2.NetcdfFiles; @@ -13,6 +12,7 @@ import ucar.nc2.internal.dataset.DatasetEnhancer; import ucar.nc2.internal.ncml.NcmlReader; import ucar.nc2.util.CancelTask; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.util.cache.FileCache; import ucar.nc2.util.cache.FileCacheIF; import ucar.nc2.util.cache.FileFactory; @@ -426,14 +426,14 @@ private static NetcdfFile openProtocolOrFile(DatasetUrl durl, int buffer_size, u Object spiObject) throws IOException { // look for dynamically loaded NetcdfFileProvider - for (NetcdfFileProvider provider : ServiceLoader.load(NetcdfFileProvider.class)) { + for (NetcdfFileProvider provider : NcServiceLoader.load(NetcdfFileProvider.class)) { if (provider.isOwnerOf(durl)) { return provider.open(durl.getTrueurl(), cancelTask); } } // look for providers who do not have an associated ServiceType. - for (NetcdfFileProvider provider : ServiceLoader.load(NetcdfFileProvider.class)) { + for (NetcdfFileProvider provider : NcServiceLoader.load(NetcdfFileProvider.class)) { if (provider.isOwnerOf(durl.getTrueurl())) { return provider.open(durl.getTrueurl(), cancelTask); } diff --git a/cdm/core/src/main/java/ucar/nc2/dataset/VariableDS.java b/cdm/core/src/main/java/ucar/nc2/dataset/VariableDS.java index a57ece8994..b0a25a09e7 100644 --- a/cdm/core/src/main/java/ucar/nc2/dataset/VariableDS.java +++ b/cdm/core/src/main/java/ucar/nc2/dataset/VariableDS.java @@ -14,6 +14,7 @@ import ucar.nc2.internal.dataset.CoordinatesHelper; import ucar.nc2.util.CancelTask; import ucar.nc2.util.Misc; +import ucar.nc2.util.NcServiceLoader; import javax.annotation.Nullable; import java.io.IOException; @@ -38,7 +39,7 @@ public class VariableDS extends Variable implements VariableEnhanced, EnhanceSca static { ENHANCEMENT_PROVIDERS = new ArrayList<>(); - for (EnhancementProvider enhancementProvider : ServiceLoader.load(EnhancementProvider.class)) { + for (EnhancementProvider enhancementProvider : NcServiceLoader.load(EnhancementProvider.class)) { ENHANCEMENT_PROVIDERS.add(enhancementProvider); } } diff --git a/cdm/core/src/main/java/ucar/nc2/dt/grid/GridDataset.java b/cdm/core/src/main/java/ucar/nc2/dt/grid/GridDataset.java index 99529c19ff..32483aad79 100644 --- a/cdm/core/src/main/java/ucar/nc2/dt/grid/GridDataset.java +++ b/cdm/core/src/main/java/ucar/nc2/dt/grid/GridDataset.java @@ -12,7 +12,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.ServiceLoader; import java.util.Set; import ucar.nc2.Attribute; import ucar.nc2.AttributeContainer; @@ -30,6 +29,7 @@ import ucar.nc2.time.CalendarDate; import ucar.nc2.time.CalendarDateRange; import ucar.nc2.units.DateRange; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.util.cache.FileCacheIF; import ucar.unidata.geoloc.LatLonRect; import ucar.unidata.geoloc.ProjectionRect; @@ -116,7 +116,7 @@ public static ucar.nc2.dt.GridDataset openIfce(String location) throws java.io.I */ public static ucar.nc2.dt.GridDataset openIfce(String location, Set enhanceMode) throws java.io.IOException { - for (GridDatasetProvider gdsProvider : ServiceLoader.load(GridDatasetProvider.class)) { + for (GridDatasetProvider gdsProvider : NcServiceLoader.load(GridDatasetProvider.class)) { if (gdsProvider.isMine(location, enhanceMode)) { return gdsProvider.open(location, enhanceMode); } diff --git a/cdm/core/src/main/java/ucar/nc2/filter/Filters.java b/cdm/core/src/main/java/ucar/nc2/filter/Filters.java index 1d6f415b0a..f8ce43bbc0 100644 --- a/cdm/core/src/main/java/ucar/nc2/filter/Filters.java +++ b/cdm/core/src/main/java/ucar/nc2/filter/Filters.java @@ -7,7 +7,7 @@ import com.google.common.collect.ImmutableList; import java.util.Map; -import java.util.ServiceLoader; +import ucar.nc2.util.NcServiceLoader; public class Filters { @@ -16,7 +16,7 @@ public class Filters { // load filter service providers static { ImmutableList.Builder spFiltersBuilder = ImmutableList.builder(); - for (FilterProvider fp : ServiceLoader.load(FilterProvider.class)) { + for (FilterProvider fp : NcServiceLoader.load(FilterProvider.class)) { spFiltersBuilder.add(fp); } spFilters = spFiltersBuilder.build(); diff --git a/cdm/core/src/main/java/ucar/nc2/ft/FeatureDatasetFactoryManager.java b/cdm/core/src/main/java/ucar/nc2/ft/FeatureDatasetFactoryManager.java index e10e00343b..2375093a7d 100644 --- a/cdm/core/src/main/java/ucar/nc2/ft/FeatureDatasetFactoryManager.java +++ b/cdm/core/src/main/java/ucar/nc2/ft/FeatureDatasetFactoryManager.java @@ -18,13 +18,13 @@ import ucar.nc2.ft.remote.CdmrFeatureDataset; import ucar.nc2.ft2.coverage.CoverageDatasetFactory; import ucar.nc2.ft2.coverage.FeatureDatasetCoverage; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.util.Optional; import java.util.List; import java.util.ArrayList; import java.util.Formatter; import java.io.IOException; import java.lang.reflect.Method; -import java.util.ServiceLoader; /** * Manager of factories for FeatureDatasets opened as NetcdfDatasets. @@ -51,7 +51,7 @@ public class FeatureDatasetFactoryManager { // search in the order added static { // user can override - for (FeatureDatasetFactory csb : ServiceLoader.load(FeatureDatasetFactory.class)) { + for (FeatureDatasetFactory csb : NcServiceLoader.load(FeatureDatasetFactory.class)) { registerFactory(csb.getClass()); } diff --git a/cdm/core/src/main/java/ucar/nc2/ft/fmrc/GridDatasetInv.java b/cdm/core/src/main/java/ucar/nc2/ft/fmrc/GridDatasetInv.java index ec222d6170..f8a7c197d2 100644 --- a/cdm/core/src/main/java/ucar/nc2/ft/fmrc/GridDatasetInv.java +++ b/cdm/core/src/main/java/ucar/nc2/ft/fmrc/GridDatasetInv.java @@ -17,7 +17,6 @@ import java.util.Formatter; import java.util.List; import java.util.Locale; -import java.util.ServiceLoader; import java.util.StringTokenizer; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -38,6 +37,7 @@ import ucar.nc2.time.CalendarDate; import ucar.nc2.time.CalendarDateFormatter; import ucar.nc2.units.DateUnit; +import ucar.nc2.util.NcServiceLoader; import ucar.nc2.constants._Coordinate; import org.jdom2.output.XMLOutputter; import org.jdom2.output.Format; @@ -85,7 +85,7 @@ private static class GenerateInv implements Callable { // Persistence is needed for the TDS static { InventoryCacheProvider icp = null; - for (InventoryCacheProvider provider : ServiceLoader.load(InventoryCacheProvider.class)) { + for (InventoryCacheProvider provider : NcServiceLoader.load(InventoryCacheProvider.class)) { // first one wins icp = provider; } diff --git a/cdm/core/src/main/java/ucar/nc2/internal/dataset/CoordSystemFactory.java b/cdm/core/src/main/java/ucar/nc2/internal/dataset/CoordSystemFactory.java index 9d923eaf60..f4a7588017 100644 --- a/cdm/core/src/main/java/ucar/nc2/internal/dataset/CoordSystemFactory.java +++ b/cdm/core/src/main/java/ucar/nc2/internal/dataset/CoordSystemFactory.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.ServiceLoader; import java.util.StringTokenizer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -24,6 +23,7 @@ import ucar.nc2.internal.dataset.spi.CFSubConventionProvider; import ucar.nc2.internal.ncml.NcmlReader; import ucar.nc2.util.CancelTask; +import ucar.nc2.util.NcServiceLoader; import ucar.unidata.util.StringUtil2; /** Static methods for managing CoordSystemBuilderFactory classes */ @@ -55,7 +55,7 @@ public interface ConventionNameOk { // These get precedence static { registerConvention(_Coordinate.Convention, new CoordSystemBuilder.Factory()); - for (CFSubConventionProvider provider : ServiceLoader.load(CFSubConventionProvider.class)) { + for (CFSubConventionProvider provider : NcServiceLoader.load(CFSubConventionProvider.class)) { registerConvention(provider.getConventionName(), provider); } registerConvention("CF-1.", new CF1Convention.Factory(), String::startsWith); @@ -278,7 +278,7 @@ private static CoordSystemBuilderFactory findConventionByIsMine(NetcdfFile orgFi } // Use service loader mechanism isMine() - for (CoordSystemBuilderFactory csb : ServiceLoader.load(CoordSystemBuilderFactory.class)) { + for (CoordSystemBuilderFactory csb : NcServiceLoader.load(CoordSystemBuilderFactory.class)) { if (csb.isMine(orgFile)) { return csb; } @@ -299,7 +299,7 @@ private static CoordSystemBuilderFactory findCfSubConvention(NetcdfFile orgFile, } // Use service loader mechanism isMine() - for (CFSubConventionProvider cfSubCon : ServiceLoader.load(CFSubConventionProvider.class)) { + for (CFSubConventionProvider cfSubCon : NcServiceLoader.load(CFSubConventionProvider.class)) { if (cfSubCon.isMine(orgFile) || cfSubCon.isMine(convs)) { return cfSubCon; } @@ -356,7 +356,7 @@ private static CoordSystemBuilderFactory findRegisteredConventionByName(String c @Nullable private static CoordSystemBuilderFactory findLoadedConventionByName(String convName) { // use service loader mechanism - for (CoordSystemBuilderFactory csb : ServiceLoader.load(CoordSystemBuilderFactory.class)) { + for (CoordSystemBuilderFactory csb : NcServiceLoader.load(CoordSystemBuilderFactory.class)) { if (convName.equals(csb.getConventionName())) { return csb; }