diff --git a/pom.xml b/pom.xml index 173602cce489762953bb386e0be015f4ced3fcad..d63b6d07e74c7e7d354201a79b6b20a89a072b77 100644 --- a/pom.xml +++ b/pom.xml @@ -2,49 +2,54 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> - <groupId>vsb-cs-java1</groupId> - <artifactId>lab07v1</artifactId> - <version>0.0.1-SNAPHOST</version> + <groupId>cz.vsb.fei</groupId> + <artifactId>lab08v1</artifactId> + <version>0.0.1-SNAPSHOT</version> + + <name>lab08v1</name> + <packaging>jar</packaging> + <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <maven.compiler.source>21</maven.compiler.source> - <maven.compiler.target>21</maven.compiler.target> + <maven.compiler.release>21</maven.compiler.release> + <JUnit.version>5.11.0</JUnit.version> + <log4j.version>2.23.1</log4j.version> + <lombok.version>1.18.34</lombok.version> </properties> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.junit</groupId> + <artifactId>junit-bom</artifactId> + <version>${JUnit.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> - <dependency> - <groupId>org.openjfx</groupId> - <artifactId>javafx-controls</artifactId> - <version>23</version> - </dependency> - <dependency> - <groupId>org.openjfx</groupId> - <artifactId>javafx-fxml</artifactId> - <version>23</version> - </dependency> - <!-- - https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-api</artifactId> - <version>5.11.0</version> + <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> - <!-- - https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine --> <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> - <version>5.11.0</version> - <scope>test</scope> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <version>${log4j.version}</version> </dependency> - <!-- - https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params --> <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-params</artifactId> - <version>5.11.0</version> - <scope>test</scope> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <version>${log4j.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.reflections/reflections --> <dependency> @@ -54,6 +59,7 @@ <scope>test</scope> </dependency> </dependencies> + <build> <plugins> <plugin> @@ -61,9 +67,20 @@ <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> - <failOnError>false</failOnError> + <annotationProcessorPaths> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + </annotationProcessorPaths> </configuration> </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>3.5.0</version> + </plugin> </plugins> </build> + </project> diff --git a/src/main/java/cz/vsb/fei/lab/App.java b/src/main/java/cz/vsb/fei/lab/App.java new file mode 100644 index 0000000000000000000000000000000000000000..5ce92f09cf08954763d7f71ef2ba29d509b3d96d --- /dev/null +++ b/src/main/java/cz/vsb/fei/lab/App.java @@ -0,0 +1,108 @@ +package cz.vsb.fei.lab; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.Reader; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import lombok.extern.log4j.Log4j2; + +/** + * Class <b>App</b> - main class + * + * @author Java I + */ +@Log4j2 +public class App { + + public static void main(String[] args) throws FileNotFoundException { + log.info("Launching Java application."); + App app = new App(); + app.printScores(app.loadScores()); + List<Score> scores = app.generateScores(200); + app.saveScores(scores, "test.csv"); + app.saveScores(scores, "test/test.csv"); + try { + app.printScores(app.loadScoresFromStream(new InputStreamReader(App.class.getResourceAsStream("/bestScore-ok.csv")))); + app.printScores(app.loadScoresFromStream(new InputStreamReader(App.class.getResourceAsStream("/bestScores-err.csv")))); + } catch (ScoreNotLoaded e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + public List<Score> generateScores(int count) { + List<Score> scores = new ArrayList<Score>(); + for (int i = 0; i < count; i++) { + scores.add(Score.generate()); + } + return scores; + } + + public void saveScores(List<Score> scores, String file) throws FileNotFoundException { + Paths.get(file).toAbsolutePath().getParent().toFile().mkdirs(); + try (PrintWriter printWriter = new PrintWriter(file)) { + for (Score score : scores) { + printWriter.format("%s;%d%n", score.getName(), score.getPoints()); + } + } + } + + public void printScores(List<Score> scores) { + for (Score score : scores) { + System.out.println(score); + } + } + + public List<Score> loadScores() { + try { + List<Score> scores = loadScoresFromFile("bestScores.csv"); + return scores; + + } catch (ScoreNotLoaded e) { + System.out.println("Exception \"" + e.getMessage() + "\". alreaded loaded scores:" + e.getCount()); + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return Collections.emptyList(); + } + + public List<Score> loadScoresFromFile(String filename) throws ScoreNotLoaded, FileNotFoundException, IOException { + try (Reader inputReader = new FileReader(filename)) { + return loadScoresFromStream(inputReader); + } catch (ScoreNotLoaded e) { + throw new ScoreNotLoaded("Info about scores from file " + filename + "cannot be loaded.", e.getCount(), e); + } + } + + public List<Score> loadScoresFromStream(Reader inputReader) throws ScoreNotLoaded { + int count = 0; + try (BufferedReader bufferedReader = new BufferedReader(inputReader)) { + String line; + List<Score> scores = new ArrayList<>(); + while ((line = bufferedReader.readLine()) != null) { + String[] parts = line.split(";"); + try { + scores.add(new Score(parts[0], Integer.parseInt(parts[1]))); + count++; + } catch (NumberFormatException e) { + System.out.println( + String.format("WARNING: Cannot parse points for player %s. Value: %s", parts[0], parts[1])); + } + } + return scores; + } catch (Exception e) { + throw new ScoreNotLoaded("Info about scores cannot be loaded.", count, e); + } + } + +} \ No newline at end of file diff --git a/src/main/java/cz/vsb/fei/lab/Score.java b/src/main/java/cz/vsb/fei/lab/Score.java new file mode 100644 index 0000000000000000000000000000000000000000..21aeab70c290045cf13d53c948a91140ae96eeec --- /dev/null +++ b/src/main/java/cz/vsb/fei/lab/Score.java @@ -0,0 +1,38 @@ +package cz.vsb.fei.lab; + +public class Score { + + private String name; + private int points; + + public Score(String name, int points) { + this.name = name; + this.points = points; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } + + public static Score generate() { + return new Score(Utilities.getRandomNick(), Utilities.RANDOM.nextInt(20, 300)); + } + + @Override + public String toString() { + return "Score [name=" + name + ", points=" + points + "]"; + } + +} diff --git a/src/main/java/cz/vsb/fei/lab/ScoreNotLoaded.java b/src/main/java/cz/vsb/fei/lab/ScoreNotLoaded.java new file mode 100644 index 0000000000000000000000000000000000000000..7b946e70749c5d7e6d357a0bccdb6ad900aeeca3 --- /dev/null +++ b/src/main/java/cz/vsb/fei/lab/ScoreNotLoaded.java @@ -0,0 +1,23 @@ +package cz.vsb.fei.lab; + +public class ScoreNotLoaded extends Exception { + + private static final long serialVersionUID = -3234631445203246158L; + + private int count; + + public ScoreNotLoaded(String message, int count) { + super(message); + this.count = count; + } + + public ScoreNotLoaded(String message, int count, Throwable cause) { + super(message, cause); + this.count = count; + } + + public int getCount() { + return count; + } + +} diff --git a/src/main/java/cz/vsb/fei/lab/Utilities.java b/src/main/java/cz/vsb/fei/lab/Utilities.java new file mode 100644 index 0000000000000000000000000000000000000000..4cb72f393b872a495d139a785e06c3adb3499759 --- /dev/null +++ b/src/main/java/cz/vsb/fei/lab/Utilities.java @@ -0,0 +1,28 @@ +package cz.vsb.fei.lab; + +import java.util.Random; + +public class Utilities { + public static final Random RANDOM = new Random(); + public static final String[] niks = { "CyberSurfer", "PixelPioneer", "SocialSavvy", "DigitalDynamo", "ByteBuddy", "InstaGuru", + "TikTokTornado", "SnapMaster", "TweetTrendsetter", "ChatChampion", "HashtagHero", "EmojiEnthusiast", + "StoryStylist", "SelfieStar", "FilterFanatic", "VlogVirtuoso", "Memelord", "InfluencerInsider", + "StreamSupreme", "GeekyGizmo", "CodeCommander", "JavaJuggernaut", "ByteNinja", "SyntaxSamurai", + "ClassyCoder", "ObjectOmnipotent", "LoopLegend", "VariableVirtuoso", "DebugDemon", "CompilerCrusader", + "PixelProdigy", "VirtualVoyager", "AlgorithmAce", "DataDynamo", "ExceptionExpert", "BugBuster", + "SyntaxSorcerer", "CodeCrusader", "JavaJester", "NerdyNavigator", "CryptoCaptain", "SocialButterfly", + "AppArchitect", "WebWizard", "FunctionFreak", "PixelArtist", "CyberPhantom", "HackHero", "CacheChampion", + "ScreenSage", "WebWeaver", "LogicLover", "BitBlazer", "NetworkNomad", "ProtocolPioneer", "BinaryBoss", + "StackSultan", "SocialScribe", "RenderRuler", "ScriptSorcerer", "HTMLHero", "PixelProwler", "FrameFreak", + "DataDreamer", "BotBuilder", "ByteBishop", "KeyboardKnight", "DesignDaredevil", "JavaJuggler", + "SyntaxStrategist", "TechTactician", "ProgramProdigy", "BinaryBard", "PixelPoet", "GigabyteGuru", + "TechTrekker", "NetworkNinja", "DataDetective", "MatrixMaster", "CodeConductor", "AppAlchemist", + "ServerSage", "ClusterChampion", "ScriptSensei", "KeyboardKicker", "CacheCrafter", "SocialSpark", + "BinaryBeast", "CodeConnoisseur", "BitBrain", "VirtualVanguard", "SystemSculptor", "RenderRogue", + "CryptoConqueror", "MachineMonarch", "PixelPal", "CompilerCaptain", "BitBuilder", "TechTitan", + "CloudConqueror", "EchoExplorer", "FunctionFanatic", "RobotRanger" }; + + public static String getRandomNick() { + return niks[RANDOM.nextInt(niks.length)]; + } +} diff --git a/src/main/java/lab/App.java b/src/main/java/lab/App.java deleted file mode 100644 index 9543b11402f10c5e733e14fb53c490df31336adf..0000000000000000000000000000000000000000 --- a/src/main/java/lab/App.java +++ /dev/null @@ -1,54 +0,0 @@ -package lab; - -import javafx.application.Application; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.stage.Stage; -import javafx.stage.WindowEvent; - -/** - * Class <b>App</b> - extends class Application and it is an entry point of the - * program - * - * @author Java I - */ -public class App extends Application { - - static { - System.out.println("aaa"); - } - private GameController gameController; - public static void main(String[] args) { - launch(args); - } - - @Override - public void start(Stage primaryStage) { - try { - // Construct a main window with a canvas. - FXMLLoader gameLoader = new FXMLLoader(getClass().getResource("/lab/gameWindow.fxml")); - Parent root = gameLoader.load(); - GameController gameController = gameLoader.getController(); - Scene scene = new Scene(root); - primaryStage.setScene(scene); - primaryStage.resizableProperty().set(false); - primaryStage.setTitle("Java 1 - 1th laboratory"); - primaryStage.show(); - // Exit program when main window is closed - primaryStage.setOnCloseRequest(this::exitProgram); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void stop() throws Exception { - gameController.stop(); - super.stop(); - } - - private void exitProgram(WindowEvent evt) { - System.exit(0); - } -} \ No newline at end of file diff --git a/src/main/java/lab/Bullet.java b/src/main/java/lab/Bullet.java deleted file mode 100644 index 76f904f6b74c1fe996b0cd26d10764a8e66e549b..0000000000000000000000000000000000000000 --- a/src/main/java/lab/Bullet.java +++ /dev/null @@ -1,51 +0,0 @@ -package lab; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.paint.Color; - -public class Bullet extends WorldEntity implements Collisionable{ - private static final double SIZE = 20; - - protected final Point2D acceleration; - protected Point2D velocity; - - public Bullet(World world, Point2D position, Point2D velocity, Point2D acceleration) { - super(world, position); - this.velocity = velocity; - this.acceleration = acceleration; - } - - @Override - public void drawInternal(GraphicsContext gc) { - gc.setFill(Color.SILVER); - gc.fillOval(position.getX(), position.getY(), SIZE, SIZE); - } - - @Override - public void simulate(double deltaT) { - position = position.add(velocity.multiply(deltaT)); - velocity = velocity.add(acceleration.multiply(deltaT)); - } - - @Override - public Rectangle2D getBoundingBox() { - return new Rectangle2D(position.getX(), position.getY(), SIZE, SIZE); - } - - @Override - public boolean intersect(Rectangle2D another) { - return getBoundingBox().intersects(another); - } - - @Override - public void hitBy(Collisionable another) { - - } - - public void setVelocity(Point2D velocity) { - this.velocity = velocity; - } - -} diff --git a/src/main/java/lab/BulletAnimated.java b/src/main/java/lab/BulletAnimated.java deleted file mode 100644 index e0de23723c455e00b19138217348e1db2687c929..0000000000000000000000000000000000000000 --- a/src/main/java/lab/BulletAnimated.java +++ /dev/null @@ -1,59 +0,0 @@ -package lab; - -import java.util.ArrayList; -import java.util.List; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.image.Image; - -public class BulletAnimated extends Bullet { - - private static final double SIZE = 40; - private final Point2D initVelocity; - private Cannon cannon; - private Image image = new Image(this.getClass().getResourceAsStream("fireball-transparent.gif")); - private List<HitListener> hitListeners = - new ArrayList<>(); - - public BulletAnimated(World world, Cannon cannon, Point2D position, Point2D velocity, Point2D acceleration) { - super(world, position, velocity, acceleration); - this.initVelocity = velocity; - this.cannon = cannon; - } - - @Override - public void drawInternal(GraphicsContext gc) { - gc.drawImage(image, getPosition().getX(), getPosition().getY(), SIZE, SIZE); - gc.strokeRect(position.getX(), position.getY(), SIZE, SIZE); - } - - @Override - public void hitBy(Collisionable another) { - if (another instanceof Ufo) { - world.remove(this); - fireUfoDestroyed(); - } - } - - public void reload() { - position = cannon.getPosition(); - velocity = new Point2D(0, 0); - } - - public boolean addHitListener(HitListener e) { - return hitListeners.add(e); - } - - public boolean removeHitListener(HitListener o) { - return hitListeners.remove(o); - } - - private void fireUfoDestroyed() { - for (HitListener hitListener : hitListeners) { - hitListener.ufoDestroyed(); - } - } - -} \ No newline at end of file diff --git a/src/main/java/lab/Cannon.java b/src/main/java/lab/Cannon.java deleted file mode 100644 index e31f1ed50c344dda08b5421ef53f25ee2421489b..0000000000000000000000000000000000000000 --- a/src/main/java/lab/Cannon.java +++ /dev/null @@ -1,44 +0,0 @@ -package lab; - -import javafx.geometry.Point2D; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.paint.Color; -import javafx.scene.transform.Affine; -import javafx.scene.transform.Transform; - -public class Cannon extends WorldEntity{ - - private static final double LENGTH = 60; - private static final double WIDTH = 15; - private double angle; - private double angleDelta = -25; - - public Cannon(World world, Point2D position, double angle) { - super(world, position); - this.angle = angle; - } - - @Override - public void drawInternal(GraphicsContext gc) { - gc.transform(new Affine(Transform.rotate(angle, position.getX(), position.getY() + WIDTH / 2))); - gc.setFill(Color.BROWN); - gc.fillRect(position.getX(), position.getY(), LENGTH, WIDTH); - } - - @Override - public void simulate(double deltaT) { -// angle += angleDelta * deltaT; -// if (angle >= 0 || angle <= -90) { -// angleDelta = -angleDelta; -// } - } - - public double getAngle() { - return angle; - } - - public void setAngle(double angle) { - this.angle = -angle; - } - -} diff --git a/src/main/java/lab/Collisionable.java b/src/main/java/lab/Collisionable.java deleted file mode 100644 index 40a81570906acfe0a433fcda9f2bd47757b7cdf6..0000000000000000000000000000000000000000 --- a/src/main/java/lab/Collisionable.java +++ /dev/null @@ -1,13 +0,0 @@ -package lab; - -import javafx.geometry.Rectangle2D; - -public interface Collisionable { - - Rectangle2D getBoundingBox(); - - boolean intersect(Rectangle2D another); - - void hitBy(Collisionable another); - -} diff --git a/src/main/java/lab/DrawableSimulable.java b/src/main/java/lab/DrawableSimulable.java deleted file mode 100644 index d5b5d45871e5124a9aa526115a50d5e2e64fb401..0000000000000000000000000000000000000000 --- a/src/main/java/lab/DrawableSimulable.java +++ /dev/null @@ -1,9 +0,0 @@ -package lab; - -import javafx.scene.canvas.GraphicsContext; - -public interface DrawableSimulable { - void draw(GraphicsContext gc); - - void simulate(double deltaT); -} diff --git a/src/main/java/lab/DrawingThread.java b/src/main/java/lab/DrawingThread.java deleted file mode 100644 index 8c0f65f38b384960527c515f15e4d21163ad4527..0000000000000000000000000000000000000000 --- a/src/main/java/lab/DrawingThread.java +++ /dev/null @@ -1,38 +0,0 @@ -package lab; - -import javafx.animation.AnimationTimer; -import javafx.scene.canvas.Canvas; -import javafx.scene.canvas.GraphicsContext; - -public class DrawingThread extends AnimationTimer { - - private final Canvas canvas; - private final GraphicsContext gc; - private final World world; - private long lastTime; - - public DrawingThread(Canvas canvas) { - this.canvas = canvas; - this.gc = canvas.getGraphicsContext2D(); - world = new World(canvas.getWidth(), canvas.getHeight()); - lastTime = System.nanoTime(); - } - - /** - * Draws objects into the canvas. Put you code here. - */ - @Override - public void handle(long now) { - double deltaT = (now - lastTime) / 1e9; - // call draw on world - this.world.draw(gc); - // call simulate on world - this.world.simulate(deltaT); - lastTime = now; - } - - public World getWorld() { - return world; - } - -} diff --git a/src/main/java/lab/GameController.java b/src/main/java/lab/GameController.java deleted file mode 100644 index 35211711b0769e81d4f543db4d9eb0d147efd3ce..0000000000000000000000000000000000000000 --- a/src/main/java/lab/GameController.java +++ /dev/null @@ -1,70 +0,0 @@ -package lab; - -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.geometry.Point2D; -import javafx.scene.canvas.Canvas; -import javafx.scene.control.Label; -import javafx.scene.control.Slider; - -public class GameController { - - @FXML - private Slider angle; - - @FXML - private Slider speed; - - @FXML - private Canvas canvas; - - private DrawingThread timer; - - @FXML - private Label hits; - private int hitcount = 0; - @FXML - void fire(ActionEvent event) { - double angle = timer.getWorld().getCannon().getAngle(); - double angleRad = Math.toRadians(angle); - double speedValue = speed.getValue(); - Point2D velocity = new Point2D( - Math.cos(angleRad)*speedValue, - Math.sin(angleRad)*speedValue); - BulletAnimated bulletAnimated = new BulletAnimated( - timer.getWorld(), - timer.getWorld().getCannon(), - timer.getWorld().getCannon().getPosition(), - velocity, World.GRAVITY); - timer.getWorld().add(bulletAnimated); - bulletAnimated.addHitListener(this::increaseHits); - bulletAnimated.addHitListener( - () -> System.out.println("au!!!!")); - } - - private void updateHits() { - hits.setText(String.format("Hit count: %03d", hitcount)); - } - - private void increaseHits() { - hitcount++; - updateHits(); - } - - @FXML - void initialize() { - assert angle != null : "fx:id=\"angle\" was not injected: check your FXML file 'gameWindow.fxml'."; - assert canvas != null : "fx:id=\"canvas\" was not injected: check your FXML file 'gameWindow.fxml'."; - assert speed != null : "fx:id=\"speed\" was not injected: check your FXML file 'gameWindow.fxml'."; - timer = new DrawingThread(canvas); - timer.start(); - angle.valueProperty().addListener( - (observable, oldValue, newValue) -> - timer.getWorld().getCannon().setAngle(newValue.doubleValue())); - } - - public void stop() { - timer.stop(); - } - -} diff --git a/src/main/java/lab/HitListener.java b/src/main/java/lab/HitListener.java deleted file mode 100644 index 833d7e3e5af31946fafc4f7883eab795287ed765..0000000000000000000000000000000000000000 --- a/src/main/java/lab/HitListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package lab; - -@FunctionalInterface -public interface HitListener { - void ufoDestroyed(); -} diff --git a/src/main/java/lab/Routines.java b/src/main/java/lab/Routines.java deleted file mode 100644 index 89fcce7f1e20229e95fbdc50c69e2b0bb695f060..0000000000000000000000000000000000000000 --- a/src/main/java/lab/Routines.java +++ /dev/null @@ -1,18 +0,0 @@ -package lab; - -public class Routines { - - - - public static void sleep(int timeInMilisenonds) { - try { - Thread.sleep(timeInMilisenonds); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - public static boolean isEndOfThreadRequestedByJavaVM() { - return Thread.interrupted(); - } -} diff --git a/src/main/java/lab/Ufo.java b/src/main/java/lab/Ufo.java deleted file mode 100644 index c55bfd776d67b082e28ce5d4a79c34425fca5f5a..0000000000000000000000000000000000000000 --- a/src/main/java/lab/Ufo.java +++ /dev/null @@ -1,60 +0,0 @@ -package lab; - -import java.util.Random; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.image.Image; - -public class Ufo extends WorldEntity implements Collisionable { - - private static final Random RANDOM = new Random(); - private Image image = new Image(this.getClass().getResourceAsStream("ufo-small.gif")); - private Point2D velocity; - - public Ufo(World world) { - this(world, new Point2D(RANDOM.nextDouble(world.getWidth()), RANDOM.nextDouble(0, world.getHeight() * 0.3)), - new Point2D(RANDOM.nextDouble(70, 150), 0)); - } - - public Ufo(World world, Point2D position, Point2D velocity) { - super(world, position); - this.velocity = velocity; - } - - @Override - public void drawInternal(GraphicsContext gc) { - gc.drawImage(image, getPosition().getX(), getPosition().getY()); - } - - public void changeDirection() { - velocity = velocity.multiply(-1); - } - - @Override - public void simulate(double deltaT) { - position = position.add(velocity.multiply(deltaT)); - position = new Point2D(position.getX() % world.getWidth(), position.getY()); - if(position.getX() < -image.getWidth()) { - position = new Point2D(world.getWidth(), position.getY()); - } - } - - @Override - public Rectangle2D getBoundingBox() { - return new Rectangle2D(position.getX(), position.getY(), image.getWidth(), image.getHeight()); - } - - @Override - public boolean intersect(Rectangle2D another) { - return getBoundingBox().intersects(another); - } - - @Override - public void hitBy(Collisionable another) { - if(another instanceof BulletAnimated || another instanceof Bullet) { - world.remove(this); - } - } -} diff --git a/src/main/java/lab/World.java b/src/main/java/lab/World.java deleted file mode 100644 index d34bdf6cb2b6ca210b0e15b586322a1384ce528b..0000000000000000000000000000000000000000 --- a/src/main/java/lab/World.java +++ /dev/null @@ -1,97 +0,0 @@ -package lab; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import javafx.geometry.Point2D; -import javafx.scene.canvas.GraphicsContext; - -public class World { - - public static final Point2D GRAVITY = new Point2D(0, 9.81); - private final double width; - - private final double height; - - private List<DrawableSimulable> entities; - private Collection<DrawableSimulable> entitiesToRemove = new LinkedList<DrawableSimulable>(); - private Collection<DrawableSimulable> entitiesToAdd = new LinkedList<DrawableSimulable>(); - - private Cannon cannon; -// private BulletAnimated bulletAnimated; - - public World(double width, double height) { - this.width = width; - this.height = height; - entities = new ArrayList<>(); - cannon = new Cannon(this, new Point2D(0, height - 20), -45); -// bulletAnimated = new BulletAnimated(this, cannon, new Point2D(0, height), new Point2D(50, -80), -// GRAVITY); - entities.add(cannon); - entities.add(new Bullet(this, new Point2D(0, height), new Point2D(30, -30), new Point2D(0, 9.81))); -// entities.add(bulletAnimated); - for (int i = 0; i < 3; i++) { - entities.add(new Ufo(this)); - } - } - - public void draw(GraphicsContext gc) { - gc.clearRect(0, 0, width, height); - - gc.save(); - for (DrawableSimulable entity : entities) { - entity.draw(gc); - } - gc.restore(); - } - - public void simulate(double deltaT) { - for (DrawableSimulable entity : entities) { - entity.simulate(deltaT); - } - for (int i = 0; i < entities.size(); i++) { - if (entities.get(i) instanceof Collisionable c1) { - for (int j = i + 1; j < entities.size(); j++) { - if (entities.get(j) instanceof Collisionable c2) { - if (c1.intersect(c2.getBoundingBox())) { - c1.hitBy(c2); - c2.hitBy(c1); - } - } - } - } - } - entities.removeAll(entitiesToRemove); - entities.addAll(entitiesToAdd); - entitiesToAdd.clear(); - entitiesToRemove.clear(); - } - - public double getWidth() { - return width; - } - - public void add(DrawableSimulable entity) { - entitiesToAdd.add(entity); - } - public void remove(DrawableSimulable entity) { - entitiesToRemove.add(entity); - - } - - public double getHeight() { - return height; - } - - public Cannon getCannon() { - return cannon; - } - -// public BulletAnimated getBulletAnimated() { -// return bulletAnimated; -// } -// -} \ No newline at end of file diff --git a/src/main/java/lab/WorldEntity.java b/src/main/java/lab/WorldEntity.java deleted file mode 100644 index 83228945ad45686a47585875f8cf626578e55f68..0000000000000000000000000000000000000000 --- a/src/main/java/lab/WorldEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package lab; - -import javafx.geometry.Point2D; -import javafx.scene.canvas.GraphicsContext; - -public abstract class WorldEntity implements DrawableSimulable{ - - protected final World world; - protected Point2D position; - - public WorldEntity(World world, Point2D position) { - this.world = world; - this.position = position; - } - - @Override - public final void draw(GraphicsContext gc) { - gc.save(); - drawInternal(gc); - gc.restore(); - } - - public abstract void drawInternal(GraphicsContext gc); - - public Point2D getPosition() { - return position; - } - - -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 736971c46e3a0601a2db674231080b0e8f886cc0..9569b78a377104bc07b456fc24433f91e3709230 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,7 +1,6 @@ -module lab01 { - requires transitive javafx.controls; - requires javafx.fxml; - requires javafx.base; - opens lab to javafx.fxml; - exports lab; +module cz.vsb.fei.lab08v1 { + requires static lombok; + requires org.apache.logging.log4j; + opens cz.vsb.fei.lab; + exports cz.vsb.fei.lab; } \ No newline at end of file diff --git a/src/main/resources/bestScore-ok.csv b/src/main/resources/bestScore-ok.csv new file mode 100644 index 0000000000000000000000000000000000000000..9b2bb63cf8635b27cd9609021a0f8dcd26c6448a --- /dev/null +++ b/src/main/resources/bestScore-ok.csv @@ -0,0 +1,45 @@ +BitBlazer;292 +CodeConductor;118 +NerdyNavigator;206 +SelfieStar;113 +VlogVirtuoso;199 +KeyboardKicker;255 +CompilerCaptain;84 +KeyboardKnight;176 +CodeCommander;160 +ProtocolPioneer;157 +PixelPoet;45 +SyntaxSamurai;67 +AppArchitect;288 +ByteNinja;104 +PixelArtist;112 +RenderRuler;153 +FunctionFreak;291 +BitBuilder;77 +DataDetective;276 +SocialButterfly;210 +WebWeaver;276 +FilterFanatic;162 +GigabyteGuru;172 +StoryStylist;225 +StoryStylist;37 +WebWeaver;62 +StreamSupreme;197 +SocialScribe;36 +ProgramProdigy;135 +InstaGuru;235 +JavaJester;93 +VariableVirtuoso;120 +MatrixMaster;292 +SyntaxStrategist;230 +DesignDaredevil;163 +SocialButterfly;231 +TechTactician;121 +AppArchitect;131 +ScriptSensei;171 +ClassyCoder;115 +CacheCrafter;79 +EchoExplorer;75 +StackSultan;209 +SocialSavvy;274 +BitBuilder;167 diff --git a/src/main/resources/bestScores-err.csv b/src/main/resources/bestScores-err.csv new file mode 100644 index 0000000000000000000000000000000000000000..f0f53461ac2e20a2a00a06b47e916144bcbd7db8 --- /dev/null +++ b/src/main/resources/bestScores-err.csv @@ -0,0 +1,26 @@ +KeyboardKicker;255 +CompilerCaptain;84 +KeyboardKnight;176 +CodeCommander;160 +ProtocolPioneer;157 +PixelPoet;45 +SyntaxSamurai;67 +AppArchitect;288 +ByteNinja;104 + +RenderRuler;153 +FunctionFreak;291 +BitBuilder +DataDetective;276 +SocialButterfly;210 +WebWeaver;276 +FilterFanatic;162 +GigabyteGuru;172 +StoryStylist;225 +StoryStylist;37 +WebWeaver;62 +StreamSupreme;197 +SocialScribe;36 +ProgramProdigy;135 +InstaGuru;235 +JavaJester;93 diff --git a/src/main/resources/lab/application.css b/src/main/resources/lab/application.css deleted file mode 100644 index 83d6f3343843c65d5dfaf3fedb97b6494c19113d..0000000000000000000000000000000000000000 --- a/src/main/resources/lab/application.css +++ /dev/null @@ -1 +0,0 @@ -/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ \ No newline at end of file diff --git a/src/main/resources/lab/fireball-transparent.gif b/src/main/resources/lab/fireball-transparent.gif deleted file mode 100644 index ed734a665d6208de17057a378b4d4520126301b5..0000000000000000000000000000000000000000 Binary files a/src/main/resources/lab/fireball-transparent.gif and /dev/null differ diff --git a/src/main/resources/lab/gameWindow.fxml b/src/main/resources/lab/gameWindow.fxml deleted file mode 100644 index c2b94f192a11c3e3bd9bc79f608fae84cc19f2ed..0000000000000000000000000000000000000000 --- a/src/main/resources/lab/gameWindow.fxml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<?import javafx.geometry.Insets?> -<?import javafx.scene.Cursor?> -<?import javafx.scene.canvas.Canvas?> -<?import javafx.scene.control.Button?> -<?import javafx.scene.control.Label?> -<?import javafx.scene.control.Slider?> -<?import javafx.scene.layout.BorderPane?> -<?import javafx.scene.layout.HBox?> -<?import javafx.scene.text.Font?> - -<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController"> - <bottom> - <HBox alignment="TOP_CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER"> - <children> - <Slider fx:id="angle" majorTickUnit="15.0" max="90.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minorTickCount="5" showTickLabels="true" showTickMarks="true" HBox.hgrow="ALWAYS" /> - <Button mnemonicParsing="false" onAction="#fire" style="-fx-background-color: RED;" text="Fire" textAlignment="CENTER"> - <font> - <Font name="System Bold" size="24.0" /> - </font> - <cursor> - <Cursor fx:constant="CROSSHAIR" /> - </cursor> - <opaqueInsets> - <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> - </opaqueInsets> - <HBox.margin> - <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> - </HBox.margin> - </Button> - <Slider fx:id="speed" max="200.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="50.0" minorTickCount="5" showTickLabels="true" showTickMarks="true" value="50.0" HBox.hgrow="ALWAYS" /> - </children> - </HBox> - </bottom> - <center> - <Canvas fx:id="canvas" height="306.0" width="582.0" BorderPane.alignment="CENTER"> - <BorderPane.margin> - <Insets /> - </BorderPane.margin> - </Canvas> - </center> - <top> - <Label fx:id="hits" text="Hit count: 0" textAlignment="CENTER" BorderPane.alignment="CENTER" /> - </top> -</BorderPane> diff --git a/src/main/resources/lab/ufo-small.gif b/src/main/resources/lab/ufo-small.gif deleted file mode 100644 index a1aca24e41f2d04912a45c703663c2b607f722dd..0000000000000000000000000000000000000000 Binary files a/src/main/resources/lab/ufo-small.gif and /dev/null differ diff --git a/src/main/resources/lab/ufo.gif b/src/main/resources/lab/ufo.gif deleted file mode 100644 index d07613c8999847572bffb44d7b161cffd874ca0f..0000000000000000000000000000000000000000 Binary files a/src/main/resources/lab/ufo.gif and /dev/null differ diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..acb3514078f6fb73f4f09ffd7a172b47f184e961 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ +<Configuration> + <Appenders> + <Console name="Console"> + <PatternLayout + pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> + </Console> + </Appenders> + <Loggers> + <Root level="info"> + <AppenderRef ref="Console"></AppenderRef> + </Root> + </Loggers> +</Configuration> diff --git a/src/test/java/cz/vsb/fei/lab/AppTest.java b/src/test/java/cz/vsb/fei/lab/AppTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ff53983a87087147f7808dc92883d90507eb3418 --- /dev/null +++ b/src/test/java/cz/vsb/fei/lab/AppTest.java @@ -0,0 +1,19 @@ +package cz.vsb.fei.lab; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +class AppTest { + + /** + * Rigorous Test :-) + */ + @Test + void shouldAnswerWithTrue() { + assertTrue(true); + } +} diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java index 820053648bea210a51013245bfb28d70910cce16..b32d84b19e478d40a466e3d8ca5bccf135b8e5e1 100644 --- a/src/test/java/jez04/structure/test/ClassStructureTest.java +++ b/src/test/java/jez04/structure/test/ClassStructureTest.java @@ -1,133 +1,69 @@ package jez04.structure.test; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.reflections.Configuration; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; -import org.reflections.util.ConfigurationBuilder; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; +import cz.vsb.fei.lab.App; +import cz.vsb.fei.lab.Score; +import cz.vsb.fei.lab.ScoreNotLoaded; class ClassStructureTest { StructureHelper helper = new StructureHelper(); - + private static String className = "Score"; + @Test - void gameControllerExistenceTest() { - helper.classExist("GameController"); + void scoreExistenceTest() { +// helper.classExist(className); + Class<?> c = Score.class;//helper.getClass(className); + helper.hasProperty(c, "name", String.class, false); + helper.hasProperty(c, "points", int.class, false); + helper.hasMethod(c, "generate", Score.class); } - - @Test - void gameControllerFxmlTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasPropertyWithAnnotation(c, ".*", FXML.class); - } - @Test - void gameControllerActionMethodTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasMethodRegexp(c, ".*", void.class, ActionEvent.class); + void scoreNotLoadedExistenceTest() { +// helper.classExist(className); + Class<?> c = ScoreNotLoaded.class; //helper.getClass("cz.vsb.fei.lab.Score"); + helper.hasProperty(c, "count", int.class, false); + helper.hasExtends(c, Exception.class); } @Test - void gameControllerLambdasTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - long lamdaCount = helper.countMethodRegexp(c, "lambda\\$.*"); - long innerClasscount = helper.countClassesRegexp(".*GameController\\$.*"); - assertTrue(lamdaCount + innerClasscount >= 2, - "At least 2 inner classes or lamdas required for GameController but only " - + (lamdaCount + innerClasscount) + " found."); + void generateScoresTest() { + App app = new App(); + assertTrue(app.generateScores(10).size() == 10); } - @Test - void hitListenerExistenceTest() { - helper.classExist("HitListener"); + void loadScoresFromStreamTest() throws ScoreNotLoaded { + App app = new App(); + assertTrue(app.loadScoresFromStream(new InputStreamReader(App.class.getResourceAsStream("/bestScore-ok.csv"))).size() > 1); } - @Test - void hitListenerEventMethodTest() { - helper.classExist("HitListener"); - Class<?> c = helper.getClass("HitListener"); - helper.hasMethod(c, "ufoDestroyed"); + void loadScoresFromStreamExceptionTest() throws ScoreNotLoaded { + App app = new App(); + assertThrows(ScoreNotLoaded.class, () -> app.loadScoresFromStream(new InputStreamReader(App.class.getResourceAsStream("/bestScores-err.csv"))).size() ); } - @Test - void sceneCollectionTest() { - helper.classExist("World"); - Class<?> c = helper.getClass("World"); - long collectionCount = Arrays.asList(c.getDeclaredFields()).stream() - .filter(f -> Collection.class.isAssignableFrom(f.getType())).count(); - assertTrue(collectionCount >= 3, "lab.Scene require atleast 3 filed of type/subtype Collection, but only " - + collectionCount + " found."); + void loadScoresTest() { + App app = new App(); + app.loadScores(); } - @Test - void worldMethodAddTest() { - helper.classExist("World"); - Class<?> c = helper.getClass("World"); - helper.hasMethod(c, "add", void.class, helper.getClass("DrawableSimulable")); - ; + void saveScoresTest() throws FileNotFoundException { + App app = new App(); + app.saveScores(app.generateScores(10), "test.csv"); } - @Test - void worldMethodRemoveTest() { - helper.classExist("World"); - Class<?> c = helper.getClass("World"); - helper.hasMethod(c, "remove", void.class, helper.getClass("DrawableSimulable")); - ; - } - - @Test - void bulletAnimatedMethodAddTest() { - helper.classExist("BulletAnimated"); - Class<?> c = helper.getClass("BulletAnimated"); - Class<?> l = helper.getClass("HitListener"); - helper.hasMethodRegexp(c, "add.*", List.of(void.class, boolean.class), l); - } - - @Test - void bulletAnimatedMethodRemoveTest() { - helper.classExist("Ufo"); - Class<?> c = helper.getClass("BulletAnimated"); - Class<?> l = helper.getClass("HitListener"); - helper.hasMethodRegexp(c, "remove.*", List.of(void.class, boolean.class), l); - } - - @Test - void bulletAnimatedMethodFireTest() { - helper.classExist("BulletAnimated"); - Class<?> c = helper.getClass("BulletAnimated"); - assertTrue(helper.countMethodRegexp(c, "fire.*") > 0, "Method fire.* in LochNess not found."); + void saveScoresDirsTest() throws FileNotFoundException { + App app = new App(); + app.saveScores(app.generateScores(10), "test/test.csv"); } } diff --git a/src/test/java/jez04/structure/test/StructureHelper.java b/src/test/java/jez04/structure/test/StructureHelper.java index aa10c81e0b4ccbc5d8bd405731e00501a30f8c27..90e27b61a300ff6557a69cf264cc37fe8c1d7648 100644 --- a/src/test/java/jez04/structure/test/StructureHelper.java +++ b/src/test/java/jez04/structure/test/StructureHelper.java @@ -19,7 +19,6 @@ import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -43,6 +42,21 @@ class StructureHelper { assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Class/Interface " + name + " not found"); } + public Class<?> getClassDirectly(String name) { + try { + return Class.forName(name); + } catch (ClassNotFoundException e) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (PrintStream ps = new PrintStream(baos, true)) { + e.printStackTrace(ps); + } catch (Exception e2) { + Assertions.fail(e2.getMessage()); + } + String stackTrace = baos.toString(); + Assertions.fail("Class " + name + " not found.\n" + stackTrace); + return null; + } + } public Class<?> getClass(String name) { String className = allClasses.stream().filter(c -> c.endsWith(name)).findAny().orElse(null); if (className == null) { @@ -122,32 +136,9 @@ class StructureHelper { assertTrue(methods.stream().anyMatch(m -> m.getName().matches(methodNameRegexp)), "No method " + methodNameRegexp); assertTrue( - methods.stream().filter( - m -> - m.getName().matches(methodNameRegexp)) - .filter( - m -> - m.getReturnType().equals(returnType)) - .anyMatch(m -> - Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))), - "Method " + methodNameRegexp + " has no all parrams:" - + Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", "))); - } - - public void hasMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, Collection<Class<?>> returnTypeOnOf, - Class<?>... params) { - List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); - assertTrue(methods.stream().anyMatch(m -> m.getName().matches(methodNameRegexp)), - "No method " + methodNameRegexp); - assertTrue( - methods.stream().filter( - m -> - m.getName().matches(methodNameRegexp)) - .filter( - m -> - returnTypeOnOf.contains(m.getReturnType())) - .anyMatch(m -> - Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))), + methods.stream().filter(m -> m.getName().matches(methodNameRegexp)) + .filter(m -> m.getReturnType().equals(returnType)) + .anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))), "Method " + methodNameRegexp + " has no all parrams:" + Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", "))); } @@ -179,6 +170,11 @@ class StructureHelper { "Class " + clazz.getName() + " not extends class " + parentName); } + public void hasExtends(Class<?> clazz, Class<?> parent) { + assertTrue(clazz.getSuperclass().equals(parent), + "Class " + clazz.getName() + " not extends class " + parent.getCanonicalName()); + } + public void hasMethod(Class<?> interfaceDef, String methodName) { List<Method> methods = Arrays.asList(interfaceDef.getMethods()); assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); @@ -186,8 +182,8 @@ class StructureHelper { public Set<String> getNameOfAllClasses() { List<String> initClassesName = new ArrayList<>(); - dynamicaliFoundSomeClass(initClassesName); - initClassesName.addAll(List.of("lab.Routines", "lab.App", "lab.DrawingThread")); +// dynamicaliFoundSomeClass(initClassesName); + initClassesName.addAll(List.of("cz.vsb.fei.lab.Score", "lab.Routines", "lab.App", "lab.DrawingThread")); for (String className : initClassesName) { try { Class.forName(className); @@ -209,12 +205,12 @@ class StructureHelper { .forPackages(p.getName()); Reflections reflections = new Reflections(conf); allClasses.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> { - System.out.println(c); + System.out.println(">>> " + c); return true; }))); } for (String string : allClasses) { - System.out.println(string); + System.out.println(":::" + string); } return allClasses; } @@ -223,7 +219,10 @@ class StructureHelper { URL myClassUrl = StructureHelper.class.getResource("ClassStructureTest.class"); myClassUrl.getFile(); try { - Path classRoot = Paths.get(myClassUrl.toURI()).getParent().getParent().getParent().getParent(); + Path classRoot = Paths.get(myClassUrl.toURI()); + while(!"test-classes".equals(classRoot.getFileName().toString()) && !"classes".equals(classRoot.getFileName().toString())) { + classRoot = classRoot.getParent(); + } if ("test-classes".equals(classRoot.getFileName().toString())) { classRoot = classRoot.getParent().resolve("classes"); }