-
Notifications
You must be signed in to change notification settings - Fork 0
⚡ Fix unsafe async API usage in MedalShowCmd #12
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -66,6 +66,10 @@ | |
| <id>placeholderapi</id> | ||
| <url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url> | ||
| </repository> | ||
| <repository> | ||
| <id>helpch</id> | ||
| <url>https://repo.helpch.at/releases/</url> | ||
| </repository> | ||
| </repositories> | ||
|
|
||
| <dependencies> | ||
|
|
@@ -78,8 +82,38 @@ | |
| <dependency> | ||
| <groupId>me.clip</groupId> | ||
| <artifactId>placeholderapi</artifactId> | ||
| <version>2.11.1</version> | ||
| <version>2.11.5</version> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter</artifactId> | ||
| <version>5.9.2</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-core</artifactId> | ||
| <version>5.2.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-inline</artifactId> | ||
| <version>5.2.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>net.bytebuddy</groupId> | ||
| <artifactId>byte-buddy</artifactId> | ||
| <version>1.14.19</version> | ||
| <scope>test</scope> | ||
|
Comment on lines
+109
to
+110
|
||
| </dependency> | ||
| <dependency> | ||
| <groupId>net.bytebuddy</groupId> | ||
| <artifactId>byte-buddy-agent</artifactId> | ||
| <version>1.14.19</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,55 +10,55 @@ | |
| import org.bukkit.entity.Player; | ||
|
|
||
| public class MedalShowCmd implements CommandExecutor { | ||
| private CommandSender sender; | ||
| private String[] args; | ||
|
|
||
| private final String prefix = "§7[§6勋章墙§7]§7 "; | ||
|
|
||
| private void printHelp() { | ||
| private void printHelp(CommandSender sender) { | ||
| sender.sendMessage("§e------------帮助------------"); | ||
| sender.sendMessage("§a/medalshow all §2展示你全部的勋章(全服可见)"); | ||
| sender.sendMessage("§a/medalshow me §2展示你全部的勋章(仅自己可见)"); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { | ||
| this.sender = sender; | ||
| this.args = args; | ||
| if (!(sender instanceof Player)) { | ||
| return false; | ||
| } | ||
| if (args.length == 0) { | ||
| printHelp(); | ||
| printHelp(sender); | ||
| return true; | ||
| } | ||
| if ("all".equals(args[0])) { | ||
| showAll(); | ||
| showAll(sender); | ||
| } else if ("me".equals(args[0])) { | ||
| showMe(); | ||
| showMe(sender); | ||
| } | ||
| return false; | ||
|
Comment on lines
31
to
36
|
||
| } | ||
|
|
||
| private void showAll() { | ||
| private void showAll(CommandSender sender) { | ||
| Bukkit.getScheduler().runTaskAsynchronously(MedalCabinet.getPlugin(), () -> { | ||
| StringBuilder stringBuilder = new StringBuilder(prefix).append("§e").append(sender.getName()) | ||
| .append(" 展示了他的勋章:\n"); | ||
| for (Medal medal : SQLManager.getInstance().getPlayerMedals(sender.getName())) { | ||
| stringBuilder.append(medal).append(" "); | ||
|
Comment on lines
40
to
44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The async task still dereferences the Useful? React with 👍 / 👎. |
||
| } | ||
| MedalCabinet.getPlugin().getServer().broadcastMessage(stringBuilder.toString()); | ||
| Bukkit.getScheduler().runTask(MedalCabinet.getPlugin(), () -> { | ||
| MedalCabinet.getPlugin().getServer().broadcastMessage(stringBuilder.toString()); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| private void showMe() { | ||
| private void showMe(CommandSender sender) { | ||
| Bukkit.getScheduler().runTaskAsynchronously(MedalCabinet.getPlugin(), () -> { | ||
| StringBuilder stringBuilder = new StringBuilder(prefix).append("§e").append(sender.getName()) | ||
| .append(" 的勋章:\n"); | ||
| for (Medal medal : SQLManager.getInstance().getPlayerMedals(sender.getName())) { | ||
| stringBuilder.append(medal).append(" "); | ||
| } | ||
| sender.sendMessage(stringBuilder.toString()); | ||
| Bukkit.getScheduler().runTask(MedalCabinet.getPlugin(), () -> { | ||
| sender.sendMessage(stringBuilder.toString()); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -15,7 +15,12 @@ public static SQLManager getInstance() { | |||||
| return instance == null ? instance = new SQLManager() : instance; | ||||||
| } | ||||||
|
|
||||||
| private SQLManager() { | ||||||
| // For testing | ||||||
| public static void setInstance(SQLManager instance) { | ||||||
|
||||||
| public static void setInstance(SQLManager instance) { | |
| static void setInstance(SQLManager instance) { |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,105 @@ | ||||
| package com.mcatk.medalcabinet.command; | ||||
|
|
||||
| import com.mcatk.medalcabinet.MedalCabinet; | ||||
| import com.mcatk.medalcabinet.medal.Medal; | ||||
| import com.mcatk.medalcabinet.sql.SQLManager; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.Server; | ||||
| import org.bukkit.command.Command; | ||||
| import org.bukkit.entity.Player; | ||||
| import org.bukkit.scheduler.BukkitScheduler; | ||||
| import org.bukkit.scheduler.BukkitTask; | ||||
| import org.bukkit.plugin.Plugin; | ||||
| import org.junit.jupiter.api.AfterEach; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.mockito.ArgumentCaptor; | ||||
| import org.mockito.MockedStatic; | ||||
|
|
||||
| import java.lang.reflect.Field; | ||||
|
||||
| import java.lang.reflect.Field; |
Copilot
AI
Feb 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several imports appear to be unused in the test: Plugin (line 12), Collections (line 21). These should be removed to keep the code clean and avoid confusion.
Copilot
AI
Feb 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test uses mockStatic for SQLManager but never actually uses the setInstance method that was added in this PR. The test correctly mocks SQLManager.getInstance() to return the mocked instance, but the setInstance method (lines 19-21 in SQLManager.java) is not utilized in the test. This suggests the setInstance method may not be necessary for testing purposes, or the test could be simplified by using it directly instead of mocking the static getInstance call.
Copilot
AI
Feb 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test verifies that broadcastMessage is called on the server (mockedServer.broadcastMessage), but the actual implementation calls MedalCabinet.getPlugin().getServer().broadcastMessage(). While both should work since mockedPlugin.getServer() returns mockedServer, it would be more accurate to also verify the call on Bukkit.broadcastMessage() or document why the server's broadcastMessage is verified instead, as Bukkit.broadcastMessage() is a static convenience method that delegates to the server.
Copilot
AI
Feb 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test only covers the "all" command case (testShowAll) but does not test the "me" command case which uses sender.sendMessage() instead of broadcastMessage(). Both code paths should be tested to ensure comprehensive coverage of the async-to-sync scheduling fix. Consider adding a testShowMe() method that verifies the "me" command also properly schedules the sendMessage call on the main thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The helpch repository was added but none of the dependencies in the pom.xml appear to require it. All test dependencies (JUnit Jupiter, Mockito, Byte Buddy) are available from Maven Central (sonatype repository). Unless there's a specific reason for this repository, it should be removed to avoid unnecessary repository lookups during builds.