Skip to content

Java and C# linting fixes and suppressions #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions checkstyle-suppressions.xml

This file was deleted.

50 changes: 50 additions & 0 deletions csharp/GlobalSuppressions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Global Suppression Notes

## Overview

Senzing has chosen to suppress some of the default coding guidance for .NET development in the
provided examples and code snippets via the use of `GlobalSuppressions.cs` files. This is done
to favor of readability and clarity of the examples and, in places, to encourage developers to
implement code that is more robust and easily maintained. The reasoning for each such suppression
is given here along with alternatives if you instead choose to follow the guidance from
the suppressed directives.

### CA1859: Use concrete types when possible for improved performance

Senzing encourages developers to use the `Senzing.Sdk.SzEnvironment` interface in favor of its concrete
implementation type throughout their code with the exception of the construction and initialization of
the `Senzing.Sdk.SzEnvironment` instance. This is encouraged so that your code can easily interchange one
implementation for another without concerns for dependencies on methods that may be specific to a concrete
implementation type. For example, one might swap `SzCoreEnvironment` for an open-source `SzGrpcEnvironment`
on a single line for initialization without concerns for searching out incompatibilities that might be
caused elsewhere in the code due to such a change.

In short, Senzing feels that in the case of `SzEnvironment` the performance concerns referenced by `CA1859`
are insignificant and negligible especially when compared to the cost of sacrificing good Object-Oriented
Programming principles that would otherwise improve the maintainability of your source code.

Therefore, Senzing encourages:

```java
// initialize the Senzing environment
SzEnvironment env = SzCoreEnvironment.NewBuilder()
.Settings(settings)
.InstanceName(instanceName)
.VerboseLogging(false)
.Build();
```

Over:

```java
// initialize the Senzing environment
SzCoreEnvironment env = SzCoreEnvironment.NewBuilder()
.Settings(settings)
.InstanceName(instanceName)
.VerboseLogging(false)
.Build();
```

If, however, you prefer to adhere to the guidance encouraged by `CA1859`, then simply use the
concrete type in your declaration of the environment variable **OR** use the `var` keyword in
place of a specific type name.
8 changes: 8 additions & 0 deletions csharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ Further, you will need to set environment variables so the Senzing installation
set Path=%SENZING_PATH%\er\lib;%Path%
```

## Using Example Code

Senzing encourages and allows you to freely copy the provided example code and modify it to your own needs as you
see fit. However, please refer to the [Global Suppression Notes] to understand how to best adapt the example code
to your own coding project.

## Building

The C# snippets can built using the `dotnet build [project-name]` command under each directory. They can be run using `dotnet run --project [project-name]` command. Attempting to run a snippet will also trigger building it.
Expand Down Expand Up @@ -162,3 +168,5 @@ The `SnippetRunner` project will run one or more snippets for you and create a t
- stewardship.ForceResolve
- stewardship.ForceUnresolve
```

[Global Suppression Notes]: GlobalSuppressions.md
10 changes: 10 additions & 0 deletions csharp/runner/SnippetRunner/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Performance", "CA1854:Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method", Justification = "Nullable Dictionary making for less readable code.")]
[assembly: SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "These are examples and there is no need to use more specific exceptions")]
[assembly: SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "It is better to OOP principle to use interfaces rather than concrete types")]
13 changes: 7 additions & 6 deletions csharp/runner/SnippetRunner/InstallLocations.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
namespace Senzing.Snippets.Runner;

using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -315,8 +317,7 @@ private static bool IsDirectory(string path)
supportDir = (supportPath != null) ? new DirectoryInfo(supportPath) : null;

// check if support dir is not defined AND we have a local dev build
if (supportDir == null && installDir != null
&& "dist".Equals(installDir.Name, OrdinalIgnoreCase))
if (supportDir == null && "dist".Equals(installDir.Name, OrdinalIgnoreCase))
{
supportDir = new DirectoryInfo(Path.Combine(installDir.FullName, "data"));
if (!supportDir.Exists)
Expand Down Expand Up @@ -386,7 +387,7 @@ private static bool IsDirectory(string path)
resourceDir = (resourcePath != null) ? new DirectoryInfo(resourcePath) : null;

// try the "resources" sub-directory of the installation
if (resourceDir == null && installDir != null)
if (resourceDir == null)
{
resourceDir = new DirectoryInfo(Path.Combine(installDir.FullName, "resources"));
if (!resourceDir.Exists)
Expand Down Expand Up @@ -456,7 +457,7 @@ private static bool IsDirectory(string path)
configDir = (configPath != null) ? new DirectoryInfo(configPath) : null;

// check if config dir is not defined AND we have a local dev build
if (configDir == null && installDir != null && templatesDir != null
if (configDir == null && templatesDir != null
&& "dist".Equals(installDir.Name, OrdinalIgnoreCase))
{
configDir = templatesDir;
Expand All @@ -473,7 +474,7 @@ private static bool IsDirectory(string path)
}

// if still null, try to use the install's etc directory
if (configDir == null && installDir != null)
if (configDir == null)
{
configDir = new DirectoryInfo(
Path.Combine(installDir.FullName, "etc"));
Expand Down Expand Up @@ -572,7 +573,7 @@ private static bool IsDirectory(string path)
result.supportDir = supportDir;
result.resourceDir = resourceDir;
result.templatesDir = templatesDir;
result.devBuild = (installDir != null) && ("dist".Equals(installDir.Name, OrdinalIgnoreCase));
result.devBuild = ("dist".Equals(installDir.Name, OrdinalIgnoreCase));

// return the result
return result;
Expand Down
63 changes: 37 additions & 26 deletions csharp/runner/SnippetRunner/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
using System.Collections;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;

using Microsoft.Data.Sqlite;

using Senzing.Sdk;
using Senzing.Sdk.Core;
using Senzing.Snippets.Runner;

using static System.StringComparison;
using static Senzing.Sdk.SzFlags;

Assembly assembly = Assembly.GetExecutingAssembly();
Expand Down Expand Up @@ -52,7 +58,7 @@
if (snippetDir == null && runnerDir != null)
{
csharpDir = Directory.GetParent(runnerDir.FullName);
if (!"csharp".Equals(csharpDir?.Name))
if (!"csharp".Equals(csharpDir?.Name, Ordinal))
{
HandleWrongDirectory();
}
Expand Down Expand Up @@ -86,7 +92,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
{
string group = entry.Key;
IDictionary<string, string> snippetMap = entry.Value;
IList<(string, string, string)> tuples
List<(string, string, string)> tuples
= new List<(string, string, string)>(snippetMap.Count);

foreach (KeyValuePair<string, string> subEntry in snippetMap)
Expand All @@ -106,7 +112,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
{
string snippet = subEntry.Key;
string snippetPath = subEntry.Value;
IList<(string, string, string)> tuples = new List<(string, string, string)>(1);
List<(string, string, string)> tuples = new List<(string, string, string)>(1);
tuples.Add((group, snippet, snippetPath));
snippetOptions.Add(snippet, tuples.AsReadOnly());
}
Expand All @@ -132,7 +138,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
settingsJson = JsonNode.Parse(settings)?.AsObject();
if (settingsJson == null)
{
throw new Exception("Setting must be a JSON object: " + settings);
throw new ArgumentNullException("Setting must be a JSON object: " + settings);
}
}
catch (Exception e)
Expand All @@ -141,6 +147,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
Console.Error.WriteLine("The provided Senzing settings were not valid JSON:");
Console.Error.WriteLine();
Environment.Exit(1);
throw;
}
}

Expand All @@ -155,6 +162,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
{
Console.Error.WriteLine(e);
Environment.Exit(1);
throw;
}
if (installLocations == null)
{
Expand All @@ -164,11 +172,11 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
return;
}

IList<(string, string)> snippets = new List<(string, string)>(100);
List<(string, string)> snippets = new List<(string, string)>(100);
for (int index = 0; index < args.Length; index++)
{
string arg = args[index];
if (arg.Equals("all"))
if (arg.Equals("all", Ordinal))
{
foreach (IDictionary<string, string> snippetMap in snippetsMap.Values)
{
Expand Down Expand Up @@ -230,7 +238,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
{
Console.WriteLine();
Stopwatch stopwatch = Stopwatch.StartNew();
IDictionary<string, string> properties = new Dictionary<string, string>();
Dictionary<string, string> properties = new Dictionary<string, string>();
string resourceName = $"""{assemblyName}.Resources.{snippet}.properties""";
LoadProperties(properties, resourceName);
Console.WriteLine("Preparing repository for " + snippet + "...");
Expand Down Expand Up @@ -285,14 +293,14 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
"Missing resource (" + fileName + ") for load file ("
+ loadKey + ") for snippet (" + snippet + ")");
}
StreamReader rdr = new StreamReader(stream, Encoding.UTF8);
try
{
StreamReader rdr = new StreamReader(stream, Encoding.UTF8);
for (string? line = rdr.ReadLine(); line != null; line = rdr.ReadLine())
{
line = line.Trim();
if (line.Length == 0) continue;
if (line.StartsWith("#")) continue;
if (line.StartsWith('#')) continue;
JsonObject? record = JsonNode.Parse(line)?.AsObject();
if (record == null)
{
Expand All @@ -307,6 +315,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
}
finally
{
rdr.Close();
stream.Close();
}

Expand Down Expand Up @@ -337,7 +346,7 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
{
Console.Error.WriteLine(e);
Environment.Exit(1);
return;
throw;
}

static void LoadProperties(IDictionary<string, string> properties, String resourceName)
Expand All @@ -352,9 +361,9 @@ static void LoadProperties(IDictionary<string, string> properties, String resour
for (string? line = rdr.ReadLine(); line != null; line = rdr.ReadLine())
{
if (line.Trim().Length == 0) continue;
if (line.StartsWith("#")) continue;
if (line.StartsWith("!")) continue;
int index = line.IndexOf('=');
if (line.StartsWith('#')) continue;
if (line.StartsWith('!')) continue;
int index = line.IndexOf('=', Ordinal);
if (index < 1) continue;
string key = line.Substring(0, index).Trim();
string value = "";
Expand All @@ -363,18 +372,19 @@ static void LoadProperties(IDictionary<string, string> properties, String resour
value = line.Substring(index + 1);
}
value = value.Trim();
while (value.EndsWith("\\"))
while (value.EndsWith('\\'))
{
line = rdr.ReadLine();
if (line == null) break;
line = line.Trim();
value = value.Substring(0, value.Length - 1) + line;
value = string.Concat(value.AsSpan(0, value.Length - 1), line);
}
properties[key] = value;
}
}
finally
{
rdr.Close();
stream.Close();
}
}
Expand All @@ -393,11 +403,12 @@ SortedDictionary<string, SortedDictionary<string, string>> snippetsMap
{
continue;
}
if (!snippetsMap.ContainsKey(group))
snippetsMap.TryGetValue(group, out SortedDictionary<string, string>? snippetMap);
if (snippetMap == null)
{
snippetsMap.Add(group, new SortedDictionary<string, string>());
snippetMap = new SortedDictionary<string, string>();
snippetsMap.Add(group, snippetMap);
}
SortedDictionary<string, string> snippetMap = snippetsMap[group];

foreach (string subdir in Directory.GetDirectories(dir))
{
Expand Down Expand Up @@ -495,7 +506,7 @@ static void ExecuteSnippet(string snippet,
Process? process = Process.Start(startInfo);
if (process == null)
{
throw new Exception("Failed to execute snippet; " + snippet);
throw new ArgumentNullException("Failed to execute snippet; " + snippet);
}

if (properties != null && properties.ContainsKey(InputKeyPrefix + 0))
Expand All @@ -520,7 +531,7 @@ static void ExecuteSnippet(string snippet,
if (properties != null && properties.ContainsKey(DestroyAfterKey))
{
string propValue = properties[DestroyAfterKey];
int delay = Int32.Parse(propValue);
int delay = Int32.Parse(propValue, CultureInfo.InvariantCulture);
bool exited = process.WaitForExit(delay);
if (!exited && !process.HasExited)
{
Expand Down Expand Up @@ -622,11 +633,11 @@ static string SetupTempRepository(InstallLocations senzingInstall)
}
}

string supportPath = supportDir.FullName.Replace("\\", "\\\\");
string configPath = configDir.FullName.Replace("\\", "\\\\"); ;
string resourcePath = resourcesDir.FullName.Replace("\\", "\\\\"); ;
string baseConfig = File.ReadAllText(configFile).Replace("\\", "\\\\");
string databasePath = databaseFile.Replace("\\", "\\\\");
string supportPath = supportDir.FullName.Replace("\\", "\\\\", Ordinal);
string configPath = configDir.FullName.Replace("\\", "\\\\", Ordinal);
string resourcePath = resourcesDir.FullName.Replace("\\", "\\\\", Ordinal);
string baseConfig = File.ReadAllText(configFile).Replace("\\", "\\\\", Ordinal);
string databasePath = databaseFile.Replace("\\", "\\\\", Ordinal);
string settings = $$"""
{
"PIPELINE": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "Performance hit is insignificant versus OOP best practices for code maintainability")]
4 changes: 2 additions & 2 deletions csharp/snippets/configuration/AddDataSources/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

// get the SzConfig for the config ID
SzConfig config = configMgr.CreateConfig(configID);

// create an array of the data sources to add
string[] dataSources = { "CUSTOMERS", "EMPLOYEES", "WATCHLIST" };

Expand All @@ -56,7 +56,7 @@

// add the modified config to the repository with a comment
long newConfigID = configMgr.RegisterConfig(modifiedConfig);

try
{
// replace the default config
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "Performance hit is insignificant versus OOP best practices for code maintainability")]
Loading
Loading