chore: fix PMD warnings and improve code quality

This commit is contained in:
2026-03-09 23:30:45 +01:00
parent 2dd3a687a5
commit 32ddfa988b
6 changed files with 40 additions and 18 deletions

View File

@@ -12,6 +12,17 @@ configurations {
mockitoAgent
}
pmd {
consoleOutput = true
toolVersion = '7.20.0'
sourceSets = [sourceSets.main]
ruleSetFiles = files(rootProject.file(".ruleset"))
}
tasks.withType(Pmd) {
maxHeapSize = "16g"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)

View File

@@ -7,6 +7,7 @@ import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -25,6 +26,7 @@ import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.ParserConfiguration.LanguageLevel;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
@@ -145,7 +147,7 @@ import com.github.javaparser.ast.expr.MemberValuePair;
* @see org.egothor.methodatlas.ai.AiSuggestionEngine
* @see #main(String[])
*/
public class MethodAtlasApp {
public class MethodAtlasApp { // NOPMD
private static final Logger LOG = Logger.getLogger(MethodAtlasApp.class.getName());
@@ -296,8 +298,8 @@ public class MethodAtlasApp {
private static void processFile(Path path, OutputMode mode, AiOptions aiOptions, AiSuggestionEngine aiEngine) {
try {
CompilationUnit compilationUnit = StaticJavaParser.parse(path);
String packageName = compilationUnit.getPackageDeclaration()
.map(packageDeclaration -> packageDeclaration.getNameAsString()).orElse("");
String packageName = compilationUnit.getPackageDeclaration().map(PackageDeclaration::getNameAsString)
.orElse("");
compilationUnit.findAll(ClassOrInterfaceDeclaration.class).forEach(clazz -> {
String className = clazz.getNameAsString();
@@ -317,8 +319,9 @@ public class MethodAtlasApp {
});
});
} catch (Exception e) {
LOG.log(Level.WARNING, "Failed to parse: {0}", path);
e.printStackTrace();
if (LOG.isLoggable(Level.WARNING)) {
LOG.log(Level.WARNING, "Failed to parse: {0} due to {1}", new Object[] { path, e.getMessage() });
}
}
}
@@ -346,8 +349,10 @@ public class MethodAtlasApp {
String classSource = clazz.toString();
if (classSource.length() > aiOptions.maxClassChars()) {
LOG.log(Level.INFO, "Skipping AI for {0}: class source too large ({1} chars)",
new Object[] { fqcn, classSource.length() });
if (LOG.isLoggable(Level.INFO)) {
LOG.log(Level.INFO, "Skipping AI for {0}: class source too large ({1} chars)",
new Object[] { fqcn, classSource.length() });
}
return SuggestionLookup.from(null);
}
@@ -355,7 +360,10 @@ public class MethodAtlasApp {
AiClassSuggestion aiClassSuggestion = aiEngine.suggestForClass(fqcn, classSource);
return SuggestionLookup.from(aiClassSuggestion);
} catch (AiSuggestionException e) {
LOG.log(Level.WARNING, "AI suggestion failed for class " + fqcn + ": " + e.getMessage());
if (LOG.isLoggable(Level.WARNING)) {
LOG.log(Level.WARNING, "AI suggestion failed for class {0}: {1}",
new Object[] { fqcn, e.getMessage() });
}
return SuggestionLookup.from(null);
}
}
@@ -523,7 +531,8 @@ public class MethodAtlasApp {
* @throws IllegalArgumentException if an option value is missing, malformed, or
* unsupported
*/
private static CliConfig parseArgs(String[] args) {
@SuppressWarnings("PMD.AvoidReassigningLoopVariables")
private static CliConfig parseArgs(String... args) {
OutputMode outputMode = OutputMode.CSV;
List<Path> paths = new ArrayList<>();
AiOptions.Builder aiBuilder = AiOptions.builder();
@@ -534,14 +543,15 @@ public class MethodAtlasApp {
switch (arg) {
case "-plain" -> outputMode = OutputMode.PLAIN;
case "-ai" -> aiBuilder.enabled(true);
case "-ai-provider" -> aiBuilder.provider(AiProvider.valueOf(nextArg(args, ++i, arg).toUpperCase()));
case "-ai-provider" ->
aiBuilder.provider(AiProvider.valueOf(nextArg(args, ++i, arg).toUpperCase(Locale.ROOT)));
case "-ai-model" -> aiBuilder.modelName(nextArg(args, ++i, arg));
case "-ai-base-url" -> aiBuilder.baseUrl(nextArg(args, ++i, arg));
case "-ai-api-key" -> aiBuilder.apiKey(nextArg(args, ++i, arg));
case "-ai-api-key-env" -> aiBuilder.apiKeyEnv(nextArg(args, ++i, arg));
case "-ai-taxonomy" -> aiBuilder.taxonomyFile(Paths.get(nextArg(args, ++i, arg)));
case "-ai-taxonomy-mode" ->
aiBuilder.taxonomyMode(AiOptions.TaxonomyMode.valueOf(nextArg(args, ++i, arg).toUpperCase()));
case "-ai-taxonomy-mode" -> aiBuilder
.taxonomyMode(AiOptions.TaxonomyMode.valueOf(nextArg(args, ++i, arg).toUpperCase(Locale.ROOT)));
case "-ai-max-class-chars" -> aiBuilder.maxClassChars(Integer.parseInt(nextArg(args, ++i, arg)));
case "-ai-timeout-sec" ->
aiBuilder.timeout(Duration.ofSeconds(Long.parseLong(nextArg(args, ++i, arg))));
@@ -635,9 +645,9 @@ public class MethodAtlasApp {
for (AnnotationExpr annotation : method.getAnnotations()) {
String name = annotation.getNameAsString();
if ("Tag".equals(name)) {
if ("Tag".equals(name)) { // NOPMD
extractTagValue(annotation).ifPresent(tagValues::add);
} else if ("Tags".equals(name)) {
} else if ("Tags".equals(name)) { // NOPMD
extractTagsContainerValues(annotation, tagValues);
}
}
@@ -665,7 +675,7 @@ public class MethodAtlasApp {
if (annotation.isNormalAnnotationExpr()) {
for (MemberValuePair pair : annotation.asNormalAnnotationExpr().getPairs()) {
if ("value".equals(pair.getNameAsString())) {
if ("value".equals(pair.getNameAsString())) { // NOPMD
extractTagsFromContainerValue(pair.getValue(), tagValues);
}
}

View File

@@ -34,6 +34,7 @@ package org.egothor.methodatlas.ai;
* @see AiProviderClient
* @see org.egothor.methodatlas.MethodAtlasApp
*/
@SuppressWarnings("PMD.ImplicitFunctionalInterface")
public interface AiSuggestionEngine {
/**
* Requests AI-generated security classification for a single parsed test class.

View File

@@ -158,7 +158,7 @@ public final class AnthropicClient implements AiProviderClient {
AiClassSuggestion suggestion = httpSupport.objectMapper().readValue(json, AiClassSuggestion.class);
return normalize(suggestion);
} catch (Exception e) {
} catch (Exception e) { // NOPMD
throw new AiSuggestionException("Anthropic suggestion failed for " + fqcn, e);
}
}

View File

@@ -162,7 +162,7 @@ public final class OllamaClient implements AiProviderClient {
AiClassSuggestion suggestion = httpSupport.objectMapper().readValue(json, AiClassSuggestion.class);
return normalize(suggestion);
} catch (Exception e) {
} catch (Exception e) { // NOPMD
throw new AiSuggestionException("Ollama suggestion failed for " + fqcn, e);
}
}

View File

@@ -170,7 +170,7 @@ public final class OpenAiCompatibleClient implements AiProviderClient {
AiClassSuggestion suggestion = httpSupport.objectMapper().readValue(json, AiClassSuggestion.class);
return normalize(suggestion);
} catch (Exception e) {
} catch (Exception e) { // NOPMD
throw new AiSuggestionException("OpenAI-compatible suggestion failed for " + fqcn, e);
}
}