From c5547bd265abdcc3cf6d2c0572b546985a523d67 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Fri, 20 Dec 2019 18:41:50 -0600 Subject: [PATCH] File refactors (#153) * Leave checkstyle files in, add more rules and supressions to PMD The PMD tests are deleted from the CI because a normal gradle build will run through them. * Swap of overall API of the backend from File to Path. This was for a reason which I have now forgotten. Something to do with IO errors or something? --- .travis.ubuntu.sh | 10 -- .travis.yml | 37 -------- azure-pipelines.yml | 1 - build.gradle.kts | 22 +---- pmd-ruleset.xml | 95 ++++++++++++++----- .../pathweaver/CreateProjectController.java | 9 +- .../edu/wpi/first/pathweaver/DataFormats.java | 2 +- .../pathweaver/EditWaypointController.java | 1 + .../java/edu/wpi/first/pathweaver/Field.java | 2 +- .../pathweaver/FieldDisplayController.java | 2 +- .../edu/wpi/first/pathweaver/FxUtils.java | 2 +- .../java/edu/wpi/first/pathweaver/Game.java | 4 +- .../edu/wpi/first/pathweaver/Loggers.java | 4 +- .../java/edu/wpi/first/pathweaver/Main.java | 3 +- .../wpi/first/pathweaver/MainController.java | 30 +++--- .../edu/wpi/first/pathweaver/MainIOUtil.java | 14 +-- .../edu/wpi/first/pathweaver/PathIOUtil.java | 13 +-- .../edu/wpi/first/pathweaver/PathUnits.java | 2 +- .../first/pathweaver/ProgramPreferences.java | 56 ++++++----- .../first/pathweaver/ProjectPreferences.java | 31 +++--- .../edu/wpi/first/pathweaver/SaveManager.java | 11 +-- .../edu/wpi/first/pathweaver/Waypoint.java | 4 +- .../first/pathweaver/WelcomeController.java | 1 + .../extensions/ExtensionLoader.java | 12 +-- .../extensions/ExtensionManager.java | 4 - .../pathweaver/global/CurrentSelections.java | 2 +- .../edu/wpi/first/pathweaver/path/Path.java | 8 +- .../wpi/first/pathweaver/path/PathUtil.java | 4 +- .../pathweaver/path/wpilib/WpilibPath.java | 2 +- .../wpi/first/pathweaver/spline/Spline.java | 2 +- .../wpi/first/pathweaver/SaveManagerTest.java | 12 +-- .../pathweaver/extensions/GameLoaderTest.java | 2 - 32 files changed, 186 insertions(+), 218 deletions(-) delete mode 100755 .travis.ubuntu.sh delete mode 100644 .travis.yml diff --git a/.travis.ubuntu.sh b/.travis.ubuntu.sh deleted file mode 100755 index a97bc75c..00000000 --- a/.travis.ubuntu.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -set -e -x - -Xvfb :99 & export DISPLAY=:99 - -./gradlew --version --console=plain -./gradlew check --stacktrace --console=plain -Pheadless - -#bash <(curl -s https://codecov.io/bash) diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 06b11d2a..00000000 --- a/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -sudo: required - -services: - - docker - -language: java - -matrix: - fast_finish: true - include: - - os: linux - jdk: oraclejdk10 -# - os: osx -# osx_image: xcode8 - -env: - global: - - GRADLE_CACHES="/home/travis/.gradle/" - - DOCKER_GRADLE_CACHES="/root/.gradle/" - -before_install: - - docker build -f Dockerfile -t pathweaver-devel . - -install: echo "skip 'gradle assemble' step" - -script: - # Get the code coverage environment variables to pass to docker - # https://github.com/codecov/support/wiki/Testing-with-Docker - #- ci_env=`bash <(curl -s https://codecov.io/env)` - - docker run -it $ci_env -v ${GRADLE_CACHES}:${DOCKER_GRADLE_CACHES} pathweaver-devel ./.travis.ubuntu.sh - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3d447ff6..9cf05406 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -65,7 +65,6 @@ stages: jdkArchitectureOption: x86 - task: Gradle@2 inputs: - options: '-x pmdMain -x pmdTest -PbuildServer' workingDirectory: '' gradleWrapperFile: 'gradlew' gradleOptions: '-Xmx1024m' diff --git a/build.gradle.kts b/build.gradle.kts index 76ac9381..816af293 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -134,20 +134,12 @@ dependencies { compile(group = "edu.wpi.first.wpiutil", name = "wpiutil-java", version = "2020.+") compile(group = "edu.wpi.first.wpilibj", name = "wpilibj-java", version = "2020.+") - fun junitJupiter(name: String, version: String = "5.2.0") = + fun junitJupiter(name: String, version: String = "5.5.0") = create(group = "org.junit.jupiter", name = name, version = version) - fun testFx(name: String, version: String = "4.0.13-alpha") = - create(group = "org.testfx", name = name, version = version) testCompile(junitJupiter(name = "junit-jupiter-api")) - testCompile(junitJupiter(name = "junit-jupiter-engine")) testCompile(junitJupiter(name = "junit-jupiter-params")) - testCompile(group = "com.google.guava", name = "guava-testlib", version = "23.0") - testCompile(testFx(name = "testfx-core")) - testCompile(testFx(name = "testfx-junit5")) - - testRuntime(testFx(name = "openjfx-monocle", version = "jdk-9+181")) - testRuntime(group = "org.junit.platform", name = "junit-platform-launcher", version = "1.0.0") + testRuntime(junitJupiter(name = "junit-jupiter-engine")) } tasks.withType().configureEach { @@ -162,7 +154,7 @@ jacoco { } extensions.getByType().apply { - toolVersion = "6.8.0" + toolVersion = "6.19.0" isConsoleOutput = true reportsDir = file("${project.buildDir}/reports/pmd") ruleSetFiles = files(file("$rootDir/pmd-ruleset.xml")) @@ -177,13 +169,7 @@ tasks.withType().configureEach { } tasks.withType().configureEach { - // TODO: re-enable when TestFX (or the underlying JavaFX problem) is fixed - println("UI tests will not be run due to TestFX being broken when headless on Java 10.") - println("See: https://github.com/javafxports/openjdk-jfx/issues/66") - // Link: https://github.com/javafxports/openjdk-jfx/issues/66 - useJUnitPlatform { - excludeTags("UI") - } + useJUnitPlatform() } val nativeShadowTasks = NativePlatforms.values().map { platform -> diff --git a/pmd-ruleset.xml b/pmd-ruleset.xml index 101676d3..5a16ad18 100644 --- a/pmd-ruleset.xml +++ b/pmd-ruleset.xml @@ -3,57 +3,102 @@ 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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"> + The PMD RuleSet for PathWeaver. + + + + + + + + + + + - + + - + + + + + + + + - + + + + + + + + - - - - - - + + + + - - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/edu/wpi/first/pathweaver/CreateProjectController.java b/src/main/java/edu/wpi/first/pathweaver/CreateProjectController.java index 0fb8f06b..edf55350 100644 --- a/src/main/java/edu/wpi/first/pathweaver/CreateProjectController.java +++ b/src/main/java/edu/wpi/first/pathweaver/CreateProjectController.java @@ -30,9 +30,8 @@ import javax.measure.Unit; import javax.measure.quantity.Length; -@SuppressWarnings("PMD.TooManyFields") +@SuppressWarnings("PMD") public class CreateProjectController { - @FXML private Label title; @FXML @@ -91,7 +90,7 @@ public class CreateProjectController { private boolean editing = false; @FXML - @SuppressWarnings("PMD.NcssCount") + private void initialize() { ObservableList numericFields = FXCollections.observableArrayList(timeStep, maxVelocity, maxAcceleration, maxJerk, wheelBase); @@ -102,7 +101,7 @@ private void initialize() { var outputControls = List.of(outputLabel, outputDirectory, browseOutput); var timeControls = List.of(timeLabel, timeStep, timeUnits); var velocityControls = List.of(velocityLabel, maxVelocity, velocityUnits); - var accelerationControls = List.of(accelerationLabel, maxAcceleration, accelerationUnits); // NOPMD + var accelerationControls = List.of(accelerationLabel, maxAcceleration, accelerationUnits); var jerkControls = List.of(jerkLabel, maxJerk, jerkUnits); var wheelBaseControls = List.of(wheelBaseLabel, wheelBase, wheelBaseUnits); @@ -187,7 +186,7 @@ public Unit fromString(String string) { } @FXML - @SuppressWarnings("PMD.NcssCount") + private void createProject() { String folderString = directory.getText().trim(); // create a "PathWeaver" subdirectory if not editing an existing project diff --git a/src/main/java/edu/wpi/first/pathweaver/DataFormats.java b/src/main/java/edu/wpi/first/pathweaver/DataFormats.java index 465aeba9..1d8f226d 100644 --- a/src/main/java/edu/wpi/first/pathweaver/DataFormats.java +++ b/src/main/java/edu/wpi/first/pathweaver/DataFormats.java @@ -5,7 +5,7 @@ /** * Custom data formats for PathWeaver. */ -public final class DataFormats { //NOPMD +public final class DataFormats { public static final String APP_PREFIX = "pathweaver"; diff --git a/src/main/java/edu/wpi/first/pathweaver/EditWaypointController.java b/src/main/java/edu/wpi/first/pathweaver/EditWaypointController.java index 3235a4a0..bed0411a 100644 --- a/src/main/java/edu/wpi/first/pathweaver/EditWaypointController.java +++ b/src/main/java/edu/wpi/first/pathweaver/EditWaypointController.java @@ -13,6 +13,7 @@ import javafx.scene.input.KeyEvent; import javafx.util.converter.NumberStringConverter; +@SuppressWarnings("PMD.UnusedPrivateMethod") public class EditWaypointController { @FXML private TextField xPosition; diff --git a/src/main/java/edu/wpi/first/pathweaver/Field.java b/src/main/java/edu/wpi/first/pathweaver/Field.java index 027164e3..1e84f0a3 100644 --- a/src/main/java/edu/wpi/first/pathweaver/Field.java +++ b/src/main/java/edu/wpi/first/pathweaver/Field.java @@ -120,7 +120,7 @@ private void updateCoord() { } private void updateScale() { - this.scale = ((pixelWidth / realWidth()) + (pixelLength / realLength())) / 2; //NOPMD Useless parentheses + this.scale = ((pixelWidth / realWidth()) + (pixelLength / realLength())) / 2; } public Unit getUnit() { diff --git a/src/main/java/edu/wpi/first/pathweaver/FieldDisplayController.java b/src/main/java/edu/wpi/first/pathweaver/FieldDisplayController.java index 69ec25f8..da822e17 100644 --- a/src/main/java/edu/wpi/first/pathweaver/FieldDisplayController.java +++ b/src/main/java/edu/wpi/first/pathweaver/FieldDisplayController.java @@ -21,7 +21,7 @@ import javafx.scene.layout.Pane; import javafx.scene.transform.Scale; -@SuppressWarnings("PMD.TooManyMethods") +@SuppressWarnings("PMD.UnusedPrivateMethod") public class FieldDisplayController { private static final PseudoClass SELECTED_CLASS = PseudoClass.getPseudoClass("selected"); diff --git a/src/main/java/edu/wpi/first/pathweaver/FxUtils.java b/src/main/java/edu/wpi/first/pathweaver/FxUtils.java index 1422115c..3a5f6f2d 100644 --- a/src/main/java/edu/wpi/first/pathweaver/FxUtils.java +++ b/src/main/java/edu/wpi/first/pathweaver/FxUtils.java @@ -23,7 +23,7 @@ import javafx.stage.Stage; public final class FxUtils { - private static final List SUBCHILD_SELECTORS; // NOPMD + private static final List SUBCHILD_SELECTORS; static { PseudoClass[] selectors = new PseudoClass[8]; diff --git a/src/main/java/edu/wpi/first/pathweaver/Game.java b/src/main/java/edu/wpi/first/pathweaver/Game.java index 6e2b9f50..50de38ce 100644 --- a/src/main/java/edu/wpi/first/pathweaver/Game.java +++ b/src/main/java/edu/wpi/first/pathweaver/Game.java @@ -31,10 +31,8 @@ private Game(String name, Field field) { * @param field the game field * * @return the created game - * - * @throws DuplicateGameException if a game has already been created with the given name */ - public static Game create(String name, Field field) throws DuplicateGameException { + public static Game create(String name, Field field) { if (GAMES.stream().map(Game::getName).anyMatch(name::equals)) { throw new DuplicateGameException("A game already exists with the name \"" + name + "\""); } diff --git a/src/main/java/edu/wpi/first/pathweaver/Loggers.java b/src/main/java/edu/wpi/first/pathweaver/Loggers.java index 7b0c4658..1595896a 100644 --- a/src/main/java/edu/wpi/first/pathweaver/Loggers.java +++ b/src/main/java/edu/wpi/first/pathweaver/Loggers.java @@ -17,7 +17,7 @@ /** * Helper class for setting up the application loggers. */ -@SuppressWarnings("PMD.ClassNamingConventions") + final class Loggers { private Loggers() { @@ -27,7 +27,7 @@ private Loggers() { /** * Sets up loggers to print to stdout (rather than stderr) and log to ~/PathWeaver/pathweaver.time.log */ - @SuppressWarnings("PMD.NcssCount") + public static void setupLoggers() throws IOException { //Set up the global level logger. This handles IO for all loggers. final Logger globalLogger = LogManager.getLogManager().getLogger(""); diff --git a/src/main/java/edu/wpi/first/pathweaver/Main.java b/src/main/java/edu/wpi/first/pathweaver/Main.java index c8cdb418..a3afb331 100644 --- a/src/main/java/edu/wpi/first/pathweaver/Main.java +++ b/src/main/java/edu/wpi/first/pathweaver/Main.java @@ -7,7 +7,8 @@ * reflectively access the JavaFX application launcher classes - this will fail because there is no module path; * everything is in the same, unnamed module. */ -@SuppressWarnings("PMD.UseUtilityClass") // Nope. + // Nope. +@SuppressWarnings("PMD.UseUtilityClass") public final class Main { public static void main(String[] args) { // JavaFX 11+ uses GTK3 by default, and has problems on some display servers diff --git a/src/main/java/edu/wpi/first/pathweaver/MainController.java b/src/main/java/edu/wpi/first/pathweaver/MainController.java index 73734290..87384ff9 100644 --- a/src/main/java/edu/wpi/first/pathweaver/MainController.java +++ b/src/main/java/edu/wpi/first/pathweaver/MainController.java @@ -27,20 +27,22 @@ import javafx.scene.layout.Pane; import javafx.stage.Stage; -@SuppressWarnings("PMD.TooManyMethods") + //With the creation of a project many of these functions should be moved out of here //Anything to do with the directory should be part of a Project object +@SuppressWarnings({"PMD.UnusedPrivateMethod","PMD.AvoidFieldNameMatchingMethodName"}) public class MainController { + private static final Logger LOGGER = Logger.getLogger(MainController.class.getName()); + @FXML private TreeView autons; @FXML private TreeView paths; - @FXML private Pane pathDisplay; - // Variable is auto generated as Pane name + Controller - @FXML private FieldDisplayController fieldDisplayController; //NOPMD + + @FXML private Pane fieldDisplay; + @FXML private FieldDisplayController fieldDisplayController; @FXML private GridPane editWaypoint; - // Variable is auto generated as Pane name + Controller - @FXML private EditWaypointController editWaypointController; //NOPMD + @FXML private EditWaypointController editWaypointController; private String directory = ProjectPreferences.getInstance().getDirectory(); private final String pathDirectory = directory + "/Paths/"; @@ -87,7 +89,7 @@ private void setupTreeView(TreeView treeView, TreeItem treeRoot, treeView.setShowRoot(false); // Don't show the roots "Paths" and "Autons" - cleaner appearance } - @SuppressWarnings("PMD.NcssCount") + private void setupEditable() { autons.setOnEditStart(event -> { if (event.getTreeItem().getParent() != autonRoot) { @@ -144,7 +146,7 @@ private void saveAllAutons() { } @FXML - @SuppressWarnings("PMD.NcssCount") + private void delete() { if (selected == null) { // have nothing selected @@ -233,7 +235,7 @@ public void changed(ObservableValue> observable, Tree paths.getSelectionModel().selectedItemProperty().addListener(selectionListener); } - @SuppressWarnings("PMD.NcssCount") + private void setupClickableAutons() { ChangeListener> selectionListener = new ChangeListener<>() { @Override @@ -323,7 +325,7 @@ private void createAuton() { } @FXML - @SuppressWarnings("PMD.NcssCount") + private void buildPaths() { if (!SaveManager.getInstance().promptSaveAll()) { return; @@ -346,8 +348,7 @@ private void buildPaths() { try { alert.setContentText("Paths exported to: " + output.getCanonicalPath()); } catch (IOException e) { - Logger log = Logger.getLogger(MainController.class.getName()); - log.log(Level.WARNING, "Could not export to " + output.getPath(), e); + LOGGER.log(Level.WARNING, "Could not export to " + output.getPath(), e); } alert.show(); } @@ -356,14 +357,13 @@ private void buildPaths() { private void editProject() { try { Pane root = FXMLLoader.load(getClass().getResource("createProject.fxml")); - Scene scene = pathDisplay.getScene(); + Scene scene = fieldDisplay.getScene(); Stage primaryStage = (Stage) scene.getWindow(); primaryStage.setMaximized(false); primaryStage.setResizable(false); scene.setRoot(root); } catch (IOException e) { - Logger log = Logger.getLogger(getClass().getName()); - log.log(Level.WARNING, "Couldn't load create project screen", e); + LOGGER.log(Level.WARNING, "Couldn't load create project screen", e); } } diff --git a/src/main/java/edu/wpi/first/pathweaver/MainIOUtil.java b/src/main/java/edu/wpi/first/pathweaver/MainIOUtil.java index 5fb61e12..b11cfc60 100644 --- a/src/main/java/edu/wpi/first/pathweaver/MainIOUtil.java +++ b/src/main/java/edu/wpi/first/pathweaver/MainIOUtil.java @@ -3,9 +3,9 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; @@ -138,10 +138,8 @@ public static void deleteItem(String directory, TreeItem item) { * @param root Auton treeItem to add new created items to. */ public static void loadAuton(String location, String filename, TreeItem root) { - BufferedReader reader; root.getChildren().clear(); - try { - reader = new BufferedReader(new FileReader(location + filename)); + try(BufferedReader reader = Files.newBufferedReader(Paths.get(location, filename))) { String line = reader.readLine(); while (line != null) { addChild(root, line); @@ -161,15 +159,11 @@ public static void loadAuton(String location, String filename, TreeItem * @param root Auton treeItem to save */ public static void saveAuton(String location, String filename, TreeItem root) { - BufferedWriter writer; - try { - writer = new BufferedWriter(new FileWriter(location + filename)); + try(BufferedWriter writer = Files.newBufferedWriter(Paths.get(location, filename))) { for (TreeItem item : root.getChildren()) { writer.write(item.getValue()); writer.newLine(); } - - writer.close(); } catch (IOException e) { LOGGER.log(Level.WARNING, "Could not save auton file", e); } diff --git a/src/main/java/edu/wpi/first/pathweaver/PathIOUtil.java b/src/main/java/edu/wpi/first/pathweaver/PathIOUtil.java index 6f2de8fa..8ea7458b 100644 --- a/src/main/java/edu/wpi/first/pathweaver/PathIOUtil.java +++ b/src/main/java/edu/wpi/first/pathweaver/PathIOUtil.java @@ -8,7 +8,6 @@ import org.apache.commons.csv.CSVRecord; import java.io.BufferedWriter; -import java.io.File; import java.io.IOException; import java.io.Reader; import java.nio.file.Files; @@ -66,13 +65,11 @@ public static boolean export(String fileLocation, Path path) { * @return Path object saved in Path file */ public static Path importPath(String fileLocation, String fileName) { - File file = new File(fileLocation + fileName); - try { - Reader reader = Files.newBufferedReader(file.toPath()); - CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT - .withFirstRecordAsHeader() - .withIgnoreHeaderCase() - .withTrim()); + try(Reader reader = Files.newBufferedReader(java.nio.file.Path.of(fileLocation, fileName)); + CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT + .withFirstRecordAsHeader() + .withIgnoreHeaderCase() + .withTrim())) { ArrayList waypoints = new ArrayList<>(); for (CSVRecord csvRecord : csvParser) { Point2D position = new Point2D( diff --git a/src/main/java/edu/wpi/first/pathweaver/PathUnits.java b/src/main/java/edu/wpi/first/pathweaver/PathUnits.java index 3d9f7ca2..86a47453 100644 --- a/src/main/java/edu/wpi/first/pathweaver/PathUnits.java +++ b/src/main/java/edu/wpi/first/pathweaver/PathUnits.java @@ -66,7 +66,7 @@ private static > U addUnit(U unit, String name, String label, * @return the unit represented by the string * @throws IllegalArgumentException if no such unit exists */ - public Unit length(String unit) { // NOPMD it's a giant switch statement + public Unit length(String unit) { switch (unit.toLowerCase(Locale.US)) { // Metric case "meter": diff --git a/src/main/java/edu/wpi/first/pathweaver/ProgramPreferences.java b/src/main/java/edu/wpi/first/pathweaver/ProgramPreferences.java index 39df8d73..6a508346 100644 --- a/src/main/java/edu/wpi/first/pathweaver/ProgramPreferences.java +++ b/src/main/java/edu/wpi/first/pathweaver/ProgramPreferences.java @@ -7,29 +7,29 @@ import javafx.stage.Stage; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; public class ProgramPreferences { - private static ProgramPreferences instance; - private Values values; + private static final String FILE_NAME = "pathweaver.json"; + private static final ProgramPreferences INSTANCE = new ProgramPreferences(); + private Values values; private final String directory; - private static final String FILENAME = "pathweaver.json"; private ProgramPreferences() { directory = System.getProperty("user.home") + "/PathWeaver/"; - File folder = new File(directory); - if (!folder.exists()) { - folder.mkdir(); - } - try { - BufferedReader prefs = new BufferedReader(new FileReader(directory + FILENAME)); + + try (BufferedReader prefs = Files.newBufferedReader(Paths.get(directory, FILE_NAME))) { Gson gson = new GsonBuilder().serializeNulls().create(); values = gson.fromJson(prefs, Values.class); - } catch (FileNotFoundException e) { + } catch (IOException e) { + values = new Values(); updatePrefs(); } catch (JsonParseException e) { Alert alert = new Alert(Alert.AlertType.ERROR); @@ -38,28 +38,30 @@ private ProgramPreferences() { "Preferences have been reset due to file corruption. You may reimport your projects with the 'Import Project' button"); ((Stage) alert.getDialogPane().getScene().getWindow()).setAlwaysOnTop(true); alert.show(); + + values = new Values(); updatePrefs(); } } /** * Return the singleton instance of ProgramPreferences. + * * @return Singleton instance of ProgramPreferences. */ public static ProgramPreferences getInstance() { - if (instance == null) { - instance = new ProgramPreferences(); - } - return instance; + return INSTANCE; } private void updatePrefs() { - values = new Values(); + Path dirPath = Paths.get(directory); try { + Files.createDirectories(dirPath); Gson gson = new GsonBuilder().setPrettyPrinting().create(); - FileWriter writer = new FileWriter(directory + FILENAME); - gson.toJson(values, writer); - writer.close(); + + try (BufferedWriter writer = Files.newBufferedWriter(dirPath.resolve(FILE_NAME))) { + gson.toJson(values, writer); + } } catch (IOException e) { Logger log = Logger.getLogger(getClass().getName()); log.log(Level.WARNING, "couldn't update program preferences", e); @@ -68,7 +70,9 @@ private void updatePrefs() { /** * Adds a project to the beginning of the list of recent projects. - * @param path Path to the project. + * + * @param path + * Path to the project. */ public void addProject(String path) { values.addProject(path); @@ -77,6 +81,7 @@ public void addProject(String path) { /** * Returns a list of paths of recent projects. + * * @return List of paths of recent projects. */ public List getRecentProjects() { @@ -84,8 +89,11 @@ public List getRecentProjects() { } /** - * Sets the size, position, and maximized values for the primaryStage based upon previous preferences. - * @param primaryStage The Stage to set the values for. + * Sets the size, position, and maximized values for the primaryStage based upon + * previous preferences. + * + * @param primaryStage + * The Stage to set the values for. */ public void setSizeAndPosition(Stage primaryStage) { if (values.getWidth() == 0 || values.getHeight() == 0 || values.getPosX() == 0 || values.getPosY() == 0) { @@ -102,11 +110,13 @@ public void setSizeAndPosition(Stage primaryStage) { /** * Saves the current size, position and maximized values to preferences file. - * @param primaryStage The stage to save size, position, and maximized values for. + * + * @param primaryStage + * The stage to save size, position, and maximized values for. */ public void saveSizeAndPosition(Stage primaryStage) { values.setSizeAndPosition(primaryStage.getWidth(), primaryStage.getHeight(), primaryStage.getX(), - primaryStage.getY(), primaryStage.isMaximized()); + primaryStage.getY(), primaryStage.isMaximized()); updatePrefs(); } diff --git a/src/main/java/edu/wpi/first/pathweaver/ProjectPreferences.java b/src/main/java/edu/wpi/first/pathweaver/ProjectPreferences.java index bc2f150a..734916d8 100644 --- a/src/main/java/edu/wpi/first/pathweaver/ProjectPreferences.java +++ b/src/main/java/edu/wpi/first/pathweaver/ProjectPreferences.java @@ -8,17 +8,15 @@ import javax.measure.Unit; import javax.measure.quantity.Length; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; +@SuppressWarnings("PMD.SingleMethodSingleton") public class ProjectPreferences { - private static final String FILENAME = "/pathweaver.json"; + private static final String FILE_NAME = "pathweaver.json"; private static ProjectPreferences instance; @@ -28,8 +26,7 @@ public class ProjectPreferences { private ProjectPreferences(String directory) { this.directory = directory; - try { - BufferedReader reader = new BufferedReader(new FileReader(directory + FILENAME)); + try(BufferedReader reader = Files.newBufferedReader(Paths.get(directory, FILE_NAME))) { Gson gson = new Gson(); values = gson.fromJson(reader, Values.class); } catch (JsonParseException e) { @@ -41,7 +38,7 @@ private ProjectPreferences(String directory) { alert.show(); setDefaults(); - } catch (FileNotFoundException e) { + } catch (IOException e) { setDefaults(); } } @@ -52,12 +49,13 @@ private void setDefaults() { } private void updateValues() { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); try { - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - new File(directory).mkdirs(); - FileWriter writer = new FileWriter(directory + FILENAME); - gson.toJson(values, writer); - writer.close(); + Files.createDirectories(Paths.get(directory)); + + try(BufferedWriter writer = Files.newBufferedWriter(Paths.get(directory, FILE_NAME))) { + gson.toJson(values, writer); + } } catch (IOException e) { Logger log = Logger.getLogger(getClass().getName()); log.log(Level.WARNING, "Couldn't update Project Preferences", e); @@ -83,6 +81,7 @@ public String getDirectory() { * @param folder Path to project folder. * @return Singleton instance of ProjectPreferences. */ + @SuppressWarnings("PMD.NonThreadSafeSingleton") public static ProjectPreferences getInstance(String folder) { if (instance == null || !instance.directory.equals(folder)) { instance = new ProjectPreferences(folder); @@ -100,7 +99,7 @@ public static ProjectPreferences getInstance() { } public static boolean projectExists(String folder) { - return new File(folder + FILENAME).exists(); + return Files.exists(Paths.get(folder, FILE_NAME)); } /** diff --git a/src/main/java/edu/wpi/first/pathweaver/SaveManager.java b/src/main/java/edu/wpi/first/pathweaver/SaveManager.java index dceee6d0..e4e30ccf 100644 --- a/src/main/java/edu/wpi/first/pathweaver/SaveManager.java +++ b/src/main/java/edu/wpi/first/pathweaver/SaveManager.java @@ -9,24 +9,17 @@ import javafx.scene.control.ButtonType; public final class SaveManager { - - private static SaveManager instance; + private static final SaveManager INSTANCE = new SaveManager(); private final Set paths = new HashSet<>(); - private SaveManager() { - } - /** * Return the singleton instance of SaveManager. Tracks which files have been edited so the user can be prompted to * save them upon exit. * @return Singleton instance of SaveManager. */ public static SaveManager getInstance() { - if (instance == null) { - instance = new SaveManager(); - } - return instance; + return INSTANCE; } public void addChange(Path path) { diff --git a/src/main/java/edu/wpi/first/pathweaver/Waypoint.java b/src/main/java/edu/wpi/first/pathweaver/Waypoint.java index 8b96d084..4153bae5 100644 --- a/src/main/java/edu/wpi/first/pathweaver/Waypoint.java +++ b/src/main/java/edu/wpi/first/pathweaver/Waypoint.java @@ -15,7 +15,7 @@ import javax.measure.Unit; import javax.measure.quantity.Length; -@SuppressWarnings("PMD.TooManyMethods") + public class Waypoint { private static final double SIZE = 30.0; private static final double ICON_X_OFFSET = (SIZE * 3D / 5D) / 16.5; @@ -160,7 +160,7 @@ public Point2D getCoords() { } public void setCoords(Point2D coords) { - setX(coords.getY()); + setX(coords.getX()); setY(coords.getY()); } diff --git a/src/main/java/edu/wpi/first/pathweaver/WelcomeController.java b/src/main/java/edu/wpi/first/pathweaver/WelcomeController.java index c27b8212..fd051fab 100644 --- a/src/main/java/edu/wpi/first/pathweaver/WelcomeController.java +++ b/src/main/java/edu/wpi/first/pathweaver/WelcomeController.java @@ -20,6 +20,7 @@ import javafx.scene.layout.Pane; import javafx.stage.DirectoryChooser; +@SuppressWarnings("PMD.UnusedPrivateMethod") public class WelcomeController { @FXML diff --git a/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionLoader.java b/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionLoader.java index a4e385b4..fca86c01 100644 --- a/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionLoader.java +++ b/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionLoader.java @@ -82,7 +82,7 @@ public final class ExtensionLoader { * @return tne game represented by the JSON * @throws IOException if the file could not be read */ - public Game loadFromJsonFile(Path jsonFile) throws IOException, DuplicateGameException { + public Game loadFromJsonFile(Path jsonFile) throws IOException { if (!jsonFile.getFileName().toString().endsWith(".json")) { throw new IllegalArgumentException("Not a JSON file: " + jsonFile); } @@ -110,7 +110,7 @@ private static Image loadImage(Path dir, String fileName) { * @throws IllegalArgumentException if there are no JSON files in the directory * @throws IllegalArgumentException if there are multiple JSON files in the directory and none named "game.json" */ - public Game loadFromDir(Path dir) throws IOException, DuplicateGameException { + public Game loadFromDir(Path dir) throws IOException { List possibleJsonFiles = Files.list(dir) .filter(path -> path.toString().endsWith(".json")) .collect(Collectors.toList()); @@ -145,7 +145,7 @@ public Game loadFromDir(Path dir) throws IOException, DuplicateGameException { * @throws IllegalArgumentException if there are multiple JSON files in the zip file and none named "game.json" * @see #loadFromDir(Path) */ - public Game loadFromZip(Path zipFile) throws IOException, DuplicateGameException { + public Game loadFromZip(Path zipFile) throws IOException { Path dir = Files.createTempDirectory("pathweaver-extension-" + zipFile.getFileName()); try (ZipFile zip = new ZipFile(zipFile.toFile())) { @@ -191,10 +191,8 @@ private static void deleteDir(Path dir) throws IOException { * @param json the JSON string to parse * * @return the game object defined by the JSON text - * - * @throws DuplicateGameException if a game already exists with the given name */ - public Game loadFromJsonString(Function imageProvider, String json) throws DuplicateGameException { + public Game loadFromJsonString(Function imageProvider, String json) { return new GsonBuilder() .registerTypeAdapter(Game.class, new ExtensionJsonDeserializer(imageProvider)) .create() @@ -219,7 +217,7 @@ private ExtensionJsonDeserializer(Function imageProvider) { } @Override - public Game deserialize(JsonElement element, Type t, JsonDeserializationContext c) throws JsonParseException { + public Game deserialize(JsonElement element, Type t, JsonDeserializationContext c) { var jsonObject = element.getAsJsonObject(); String imagePath = jsonObject diff --git a/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionManager.java b/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionManager.java index a371f074..119891d1 100644 --- a/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionManager.java +++ b/src/main/java/edu/wpi/first/pathweaver/extensions/ExtensionManager.java @@ -54,8 +54,6 @@ private Optional loadGameFromDir(Path dir) { LOGGER.log(Level.WARNING, "Could not load game from " + dir.toAbsolutePath(), e); } catch (DuplicateGameException e) { LOGGER.warning("Duplicate game name in " + dir.toAbsolutePath() + ": " + e.getMessage()); - } catch (RuntimeException e) { // NOPMD - LOGGER.log(Level.WARNING, "General exception when loading from " + dir.toAbsolutePath(), e); } return Optional.empty(); } @@ -67,8 +65,6 @@ private Optional loadGameFromZip(Path zip) { LOGGER.log(Level.WARNING, "Could not load game from ZIP file " + zip.toAbsolutePath(), e); } catch (DuplicateGameException e) { LOGGER.warning("Duplicate game name in ZIP file " + zip.toAbsolutePath() + ": " + e.getMessage()); - } catch (RuntimeException e) { // NOPMD - LOGGER.log(Level.WARNING, "General exception when loading from ZIP file " + zip.toAbsolutePath(), e); } return Optional.empty(); } diff --git a/src/main/java/edu/wpi/first/pathweaver/global/CurrentSelections.java b/src/main/java/edu/wpi/first/pathweaver/global/CurrentSelections.java index 2fb00fde..03197722 100644 --- a/src/main/java/edu/wpi/first/pathweaver/global/CurrentSelections.java +++ b/src/main/java/edu/wpi/first/pathweaver/global/CurrentSelections.java @@ -9,7 +9,7 @@ * Those who would like to remove this should refrain from doing so, as the * necessary plumbing is verbose and unwieldy. */ -@SuppressWarnings("PMD.ClassNamingConventions") + public final class CurrentSelections { private static SimpleObjectProperty curSplineStart = new SimpleObjectProperty<>(); private static SimpleObjectProperty curSplineEnd = new SimpleObjectProperty<>(); diff --git a/src/main/java/edu/wpi/first/pathweaver/path/Path.java b/src/main/java/edu/wpi/first/pathweaver/path/Path.java index 7668200f..ec70fb28 100644 --- a/src/main/java/edu/wpi/first/pathweaver/path/Path.java +++ b/src/main/java/edu/wpi/first/pathweaver/path/Path.java @@ -41,12 +41,12 @@ * @see CurrentSelections * @see Spline */ -@SuppressWarnings("PMD.TooManyMethods") + public abstract class Path { protected static final PseudoClass SELECTED_CLASS = PseudoClass.getPseudoClass("selected"); - protected static final double DEFAULT_SPLINE_SCALE = 6; // NOPMD - protected static final double DEFAULT_CIRCLE_SCALE = .75; // NOPMD - protected static final double DEFAULT_LINE_SCALE = 4; // NOPMD + protected static final double DEFAULT_SPLINE_SCALE = 6; + protected static final double DEFAULT_CIRCLE_SCALE = .75; + protected static final double DEFAULT_LINE_SCALE = 4; protected final Field field = ProjectPreferences.getInstance().getField(); protected final ObservableList waypoints = new ObservableListWrapper<>(new ArrayList<>()); diff --git a/src/main/java/edu/wpi/first/pathweaver/path/PathUtil.java b/src/main/java/edu/wpi/first/pathweaver/path/PathUtil.java index d0eae6ed..e1820dcd 100644 --- a/src/main/java/edu/wpi/first/pathweaver/path/PathUtil.java +++ b/src/main/java/edu/wpi/first/pathweaver/path/PathUtil.java @@ -21,9 +21,9 @@ private PathUtil() { * @param p1 the Point2d representing the coordinates of the waypoint before this one * @param p2 the Point2d representing the coordinates of this waypoint * @param p3 the Point2d representing the coordinates of the waypoint after this one - * @return a Point2d representing the components of the tangent vector of this waypoint + * @return the a Point2d representing the lengths of the tangent line of this waypoint */ - @SuppressWarnings("PMD.NcssCount") + public static Point2D rawThetaOptimization(Point2D p1, Point2D p2, Point2D p3) { Point2D p1Scaled = new Point2D(0, 0); Point2D p2Scaled = p2.subtract(p1).multiply(1 / p3.distance(p1)); diff --git a/src/main/java/edu/wpi/first/pathweaver/path/wpilib/WpilibPath.java b/src/main/java/edu/wpi/first/pathweaver/path/wpilib/WpilibPath.java index 95ee5de6..ddfe8e2b 100644 --- a/src/main/java/edu/wpi/first/pathweaver/path/wpilib/WpilibPath.java +++ b/src/main/java/edu/wpi/first/pathweaver/path/wpilib/WpilibPath.java @@ -30,7 +30,7 @@ public class WpilibPath extends Path { * @param points The list of waypoints to add * @param name The name of the path */ - @SuppressWarnings("PMD.NcssCount") + public WpilibPath(List points, String name) { super(WpilibSpline::new, name); this.waypoints.addListener((ListChangeListener) c -> { diff --git a/src/main/java/edu/wpi/first/pathweaver/spline/Spline.java b/src/main/java/edu/wpi/first/pathweaver/spline/Spline.java index 6b2693a1..d587d4ea 100644 --- a/src/main/java/edu/wpi/first/pathweaver/spline/Spline.java +++ b/src/main/java/edu/wpi/first/pathweaver/spline/Spline.java @@ -34,7 +34,7 @@ * @see edu.wpi.first.pathweaver.path.wpilib.WpilibPath * @see SplineSegment */ -@SuppressWarnings("PMD.NcssCount") + public interface Spline { /** * Updates the current spline diff --git a/src/test/java/edu/wpi/first/pathweaver/SaveManagerTest.java b/src/test/java/edu/wpi/first/pathweaver/SaveManagerTest.java index 3ce1e449..9ee619b9 100644 --- a/src/test/java/edu/wpi/first/pathweaver/SaveManagerTest.java +++ b/src/test/java/edu/wpi/first/pathweaver/SaveManagerTest.java @@ -5,9 +5,10 @@ import javafx.geometry.Point2D; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.io.TempDir; import java.io.IOException; +import java.nio.file.Files; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -18,11 +19,10 @@ public class SaveManagerTest { private String pathDirectory; @BeforeEach - public void initialize() throws IOException { - TemporaryFolder folder = new TemporaryFolder(); - folder.create(); - String projectDirectory = folder.getRoot().getAbsolutePath(); - pathDirectory = folder.newFolder("Paths").getAbsolutePath() + "/"; + public void initialize(@TempDir java.nio.file.Path temp) throws IOException { + Files.createDirectories(temp.resolve("Paths/")); + String projectDirectory = temp.toAbsolutePath().toString(); + pathDirectory = temp.resolve("Paths/").toAbsolutePath().toString(); ProjectPreferences.getInstance(projectDirectory); } diff --git a/src/test/java/edu/wpi/first/pathweaver/extensions/GameLoaderTest.java b/src/test/java/edu/wpi/first/pathweaver/extensions/GameLoaderTest.java index ea83f94a..100c630b 100644 --- a/src/test/java/edu/wpi/first/pathweaver/extensions/GameLoaderTest.java +++ b/src/test/java/edu/wpi/first/pathweaver/extensions/GameLoaderTest.java @@ -10,11 +10,9 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; -@SuppressWarnings("PMD.JUnitTestContainsTooManyAsserts") // PMD doesn't quite understand assertAll() public class GameLoaderTest { @Test - @SuppressWarnings("PMD.JUnitAssertionsShouldIncludeMessage") // False positive on the messages in the last 2 asserts public void testSimpleJson() { ExtensionLoader loader = new ExtensionLoader(); String json = "{"