chore: add PMD 7.8.0 and fix warnings/antipatterns
- build.gradle.kts: add pmd plugin with security/bestpractices ruleset (UnusedPrivateField, PreserveStackTrace, AvoidPrintStackTrace, CloseResource, etc), html/xml reports
- fix 8 deprecation warnings: Bukkit.getOfflinePlayer(String) suppressed via @SuppressWarnings(deprecation) in ColorCommandHandler, PrefixCommandHandler, GradientAdminCommand, PlayerUtil
- fix 9 try-resource warnings in IgnoreServiceTest via @SuppressWarnings({"try","PMD.UnusedLocalVariable"})
- PMD fixes: AvoidPrintStackTrace -> logger.log in BaseCommand, MuteHistoryManager, CustomCommandManager; CloseResource via try-with-resources in BaseConfig, GradientMessages, GradientDataManager, DiscordConfig; UnusedPrivateField removed plugin field in PlayerEventListener; MuteHistoryManager System.err -> logger
- verified: gradle clean build pmdMain pmdTest checkstyleMain checkstyleTest test shadowJar all green, zero javac warnings, no secrets found, antipatterns (Thread.sleep in async webhook/rate-limiter kept isolated, printStackTrace removed)
This commit is contained in:
parent
83e980d1bb
commit
bd39118b14
14 changed files with 85 additions and 34 deletions
|
|
@ -3,6 +3,7 @@ plugins {
|
|||
id("com.gradleup.shadow") version "9.0.0"
|
||||
jacoco
|
||||
checkstyle
|
||||
pmd
|
||||
}
|
||||
|
||||
group = "com.loki"
|
||||
|
|
@ -57,6 +58,37 @@ tasks.withType<Checkstyle>().configureEach {
|
|||
}
|
||||
}
|
||||
|
||||
pmd {
|
||||
toolVersion = "7.8.0"
|
||||
ruleSetConfig = resources.text.fromString(
|
||||
"""
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="LoChat PMD"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
<description>LoChat security + best practices (no style nit)</description>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
|
||||
<rule ref="category/java/bestpractices.xml/PreserveStackTrace"/>
|
||||
<rule ref="category/java/bestpractices.xml/AvoidPrintStackTrace"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
|
||||
<rule ref="category/java/errorprone.xml/CloseResource"/>
|
||||
<rule ref="category/java/errorprone.xml/BrokenNullCheck"/>
|
||||
<rule ref="category/java/security.xml/HardCodedCryptoKey"/>
|
||||
</ruleset>
|
||||
""".trimIndent()
|
||||
)
|
||||
isIgnoreFailures = false
|
||||
}
|
||||
|
||||
tasks.withType<org.gradle.api.plugins.quality.Pmd>().configureEach {
|
||||
reports {
|
||||
xml.required.set(true)
|
||||
html.required.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Базовый класс для всех команд плагина
|
||||
|
|
@ -30,8 +31,7 @@ public abstract class BaseCommand implements CommandExecutor, TabCompleter {
|
|||
try {
|
||||
return executeCommand(sender, command, label, args);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe("Ошибка в команде " + command.getName() + ": " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().log(Level.WARNING, "Ошибка в команде " + command.getName() + ": " + e.getMessage(), e);
|
||||
sender.sendMessage("§cПроизошла ошибка при выполнении команды!");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,13 +68,13 @@ public abstract class BaseConfig {
|
|||
if (!configFile.exists()) {
|
||||
try {
|
||||
String resourcePath = inConfigFolder ? "config/" + fileName : fileName;
|
||||
InputStream in = plugin.getResource(resourcePath);
|
||||
if (in != null) {
|
||||
Files.copy(in, configFile.toPath());
|
||||
in.close();
|
||||
plugin.getLogger().info("Created config file: " + (inConfigFolder ? "config/" : "") + fileName);
|
||||
} else {
|
||||
plugin.getLogger().warning("Resource not found: " + resourcePath);
|
||||
try (InputStream in = plugin.getResource(resourcePath)) {
|
||||
if (in != null) {
|
||||
Files.copy(in, configFile.toPath());
|
||||
plugin.getLogger().info("Created config file: " + (inConfigFolder ? "config/" : "") + fileName);
|
||||
} else {
|
||||
plugin.getLogger().warning("Resource not found: " + resourcePath);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to copy " + fileName + ": " + e.getMessage());
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import java.util.Map;
|
|||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MuteHistoryManager {
|
||||
|
||||
|
|
@ -112,7 +114,7 @@ public class MuteHistoryManager {
|
|||
}
|
||||
moveIntoPlace(tmp);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Failed to save mute history: " + e.getMessage());
|
||||
Logger.getLogger(MuteHistoryManager.class.getName()).log(Level.WARNING, "Failed to save mute history", e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
|
@ -140,7 +142,7 @@ public class MuteHistoryManager {
|
|||
history.putAll(loaded);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Logger.getLogger(MuteHistoryManager.class.getName()).log(Level.WARNING, "Failed to load mute history", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
sender.sendMessage("§e/aprefix updateall §7— обновить display names всех игроков");
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void handleInfo(CommandSender sender, String playerName, GradientMessages msg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public class ColorCommandHandler {
|
|||
/**
|
||||
* Установить цвет игроку
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void handleSetColor(CommandSender sender, String[] args, GradientMessages msg) {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage("§cИспользование: /aprefix setcolor <игрок> <цвет1> [цвет2] ...");
|
||||
|
|
@ -69,6 +70,7 @@ public class ColorCommandHandler {
|
|||
/**
|
||||
* Включить/выключить цвет
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void handleColorToggle(CommandSender sender, String[] args, boolean enable, GradientMessages msg) {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix " + (enable ? "coloron" : "coloroff") + " <игрок>");
|
||||
|
|
@ -93,6 +95,7 @@ public class ColorCommandHandler {
|
|||
/**
|
||||
* Сбросить цвет
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void handleResetColor(CommandSender sender, String[] args, GradientMessages msg) {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix resetcolor <игрок>");
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public class PrefixCommandHandler {
|
|||
/**
|
||||
* Установить префикс игроку
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void handleSetPrefix(CommandSender sender, String[] args, GradientMessages msg) {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage("§cИспользование: /aprefix setprefix <игрок> <префикс>");
|
||||
|
|
@ -65,6 +66,7 @@ public class PrefixCommandHandler {
|
|||
/**
|
||||
* Включить/выключить префикс
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void handlePrefixToggle(CommandSender sender, String[] args, boolean enable, GradientMessages msg) {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix " + (enable ? "prefixon" : "prefixoff") + " <игрок>");
|
||||
|
|
@ -89,6 +91,7 @@ public class PrefixCommandHandler {
|
|||
/**
|
||||
* Сбросить префикс
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void handleResetPrefix(CommandSender sender, String[] args, GradientMessages msg) {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix resetprefix <игрок>");
|
||||
|
|
|
|||
|
|
@ -37,11 +37,14 @@ public class GradientMessages {
|
|||
}
|
||||
messages = YamlConfiguration.loadConfiguration(messagesFile);
|
||||
|
||||
InputStream defStream = plugin.getResource("messages.yml");
|
||||
if (defStream != null) {
|
||||
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(
|
||||
new InputStreamReader(defStream, StandardCharsets.UTF_8));
|
||||
messages.setDefaults(defConfig);
|
||||
try (InputStream defStream = plugin.getResource("messages.yml")) {
|
||||
if (defStream != null) {
|
||||
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(
|
||||
new InputStreamReader(defStream, StandardCharsets.UTF_8));
|
||||
messages.setDefaults(defConfig);
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
plugin.getLogger().warning("Failed to load default messages.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,18 +104,19 @@ public class GradientDataManager {
|
|||
"SELECT prefix, colors, color_enabled, prefix_enabled, "
|
||||
+ "prefix_purchased, last_color_change, last_prefix_change FROM gradient_data WHERE uuid = ?")) {
|
||||
stmt.setString(1, uuid.toString());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
if (rs.next()) {
|
||||
data.setPrefix(rs.getString("prefix"));
|
||||
String colorsStr = rs.getString("colors");
|
||||
if (colorsStr != null && !colorsStr.isEmpty()) {
|
||||
data.setColors(List.of(colorsStr.split(",")));
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
data.setPrefix(rs.getString("prefix"));
|
||||
String colorsStr = rs.getString("colors");
|
||||
if (colorsStr != null && !colorsStr.isEmpty()) {
|
||||
data.setColors(List.of(colorsStr.split(",")));
|
||||
}
|
||||
data.setColorEnabled(rs.getBoolean("color_enabled"));
|
||||
data.setPrefixEnabled(rs.getBoolean("prefix_enabled"));
|
||||
data.setPrefixPurchased(rs.getBoolean("prefix_purchased"));
|
||||
data.setLastColorChange(rs.getLong("last_color_change"));
|
||||
data.setLastPrefixChange(rs.getLong("last_prefix_change"));
|
||||
}
|
||||
data.setColorEnabled(rs.getBoolean("color_enabled"));
|
||||
data.setPrefixEnabled(rs.getBoolean("prefix_enabled"));
|
||||
data.setPrefixPurchased(rs.getBoolean("prefix_purchased"));
|
||||
data.setLastColorChange(rs.getLong("last_color_change"));
|
||||
data.setLastPrefixChange(rs.getLong("last_prefix_change"));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Ошибка загрузки gradient данных: " + e.getMessage());
|
||||
|
|
|
|||
|
|
@ -25,11 +25,9 @@ public class DiscordConfig {
|
|||
|
||||
File configFile = new File(configFolder, "discord.yml");
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
java.io.InputStream in = plugin.getResource("config/discord.yml");
|
||||
try (java.io.InputStream in = plugin.getResource("config/discord.yml")) {
|
||||
if (in != null) {
|
||||
java.nio.file.Files.copy(in, configFile.toPath());
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to copy config/discord.yml: " + e.getMessage());
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import org.bukkit.inventory.ItemStack;
|
|||
* Слушатель событий игрока
|
||||
*/
|
||||
public class PlayerEventListener implements Listener {
|
||||
private final LoChat plugin;
|
||||
private final PlayerService playerService;
|
||||
private final MessagingService messagingService;
|
||||
private final NickService nickService;
|
||||
|
|
@ -32,7 +31,6 @@ public class PlayerEventListener implements Listener {
|
|||
|
||||
public PlayerEventListener(LoChat plugin, PlayerService playerService, MessagingService messagingService,
|
||||
NickService nickService, AdvancedMessageFilter advancedFilter) {
|
||||
this.plugin = plugin;
|
||||
this.playerService = playerService;
|
||||
this.messagingService = messagingService;
|
||||
this.nickService = nickService;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import java.io.File;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class CustomCommandManager {
|
||||
|
||||
|
|
@ -101,8 +102,7 @@ public class CustomCommandManager {
|
|||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe("Ошибка регистрации команды " + data.name() + ": " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().log(Level.WARNING, "Ошибка регистрации команды " + data.name() + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public final class PlayerUtil {
|
|||
* @param name имя игрока
|
||||
* @return UUID игрока или null если не найден
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static UUID findPlayerUUID(String name) {
|
||||
// Сначала ищем онлайн игрока
|
||||
Player onlinePlayer = Bukkit.getPlayer(name);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void isIgnoring_notIgnored() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> ignored = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -39,6 +40,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void addIgnore_thenIsIgnoring() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -49,6 +51,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void addIgnore_duplicateReturnsFalse() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -59,6 +62,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void removeIgnore() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -70,6 +74,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void removeIgnore_notIgnored() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
assertFalse(ignoreService.removeIgnore(UUID.randomUUID(), UUID.randomUUID()));
|
||||
|
|
@ -77,6 +82,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void getIgnoredCount() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -89,6 +95,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void getIgnoredPlayers_returnsSet() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -99,6 +106,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void clearIgnores() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID player = UUID.randomUUID();
|
||||
|
|
@ -109,6 +117,7 @@ class IgnoreServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"try", "PMD.UnusedLocalVariable"})
|
||||
void multiplePlayersIndepedent() {
|
||||
try (MockedStatic<com.loki.lochat.utils.platform.FoliaUtil> fu = Mockito.mockStatic(com.loki.lochat.utils.platform.FoliaUtil.class)) {
|
||||
UUID a = UUID.randomUUID();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue