From b5c38bea54cce6c1c014e3b91940bc3c223a37eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20T=C3=A2che?= Date: Sat, 28 Dec 2024 17:25:33 +0100 Subject: [PATCH] Finishes testing, cleanup, adds license --- .mvn/wrapper/maven-wrapper.properties | 38 +-- LICENSE.txt | 9 + README.md | 37 +-- .../fxml/compiler/GenerationException.java | 1 + .../fxml/compiler/parsing/ParseException.java | 1 + .../fxml/compiler/parsing/TestFXMLParser.java | 4 +- .../fxml/compiler/impl/ClassesFinder.java | 5 +- .../compiler/impl/ControllerInfoImpl.java | 1 + .../compiler/impl/GenerationRequestImpl.java | 1 + .../fxml/compiler/impl/GeneratorImpl.java | 3 +- .../fxml/compiler/impl/SourceInfoImpl.java | 1 + .../impl/internal/ControllerInjector.java | 21 +- .../compiler/impl/internal/FieldSetter.java | 26 +- .../impl/internal/GenerationHelper.java | 5 +- .../internal/InitializationFormatter.java | 15 +- .../impl/internal/ObjectFormatter.java | 2 +- .../impl/internal/PropertyFormatter.java | 2 +- .../impl/internal/SceneFormatter.java | 2 +- .../impl/internal/TriangleMeshFormatter.java | 15 +- .../compiler/impl/internal/VariableInfo.java | 1 + .../impl/internal/VariableProvider.java | 4 +- .../parsing/impl/ParsedDefineImpl.java | 1 + .../parsing/impl/ParsedIncludeImpl.java | 3 + .../parsing/impl/ParsedObjectImpl.java | 1 + .../parsing/impl/ParsedPropertyImpl.java | 4 +- .../compiler/impl/TestSourceInfoImpl.java | 3 +- .../impl/internal/TestConstructorHelper.java | 11 +- .../impl/internal/TestFontFormatter.java | 4 +- .../impl/internal/TestImageFormatter.java | 5 +- .../internal/TestLoadMethodFormatter.java | 1 - .../impl/internal/TestObjectFormatter.java | 40 +-- .../impl/internal/TestPropertyFormatter.java | 12 +- .../impl/internal/TestSceneFormatter.java | 24 +- .../internal/TestTriangleMeshFormatter.java | 4 +- .../impl/internal/TestURLFormatter.java | 4 +- .../impl/internal/TestWebViewFormatter.java | 2 +- .../parsing/impl/TestParsedIncludeImpl.java | 2 +- .../parsing/impl/TestParsedObjectImpl.java | 2 +- .../parsing/impl/TestParsedPropertyImpl.java | 2 +- .../fxml/compiler/maven/FXMLCompilerMojo.java | 149 ++++++--- .../maven/internal/CompilationInfo.java | 15 + .../internal/CompilationInfoProvider.java | 44 ++- .../compiler/maven/internal/Compiler.java | 42 ++- .../maven/internal/ControllerProvider.java | 18 +- .../compiler/maven/internal/FXMLProvider.java | 32 +- .../maven/internal/GenericParser.java | 25 +- .../maven/internal/SourceInfoProvider.java | 2 +- .../compiler/maven/TestFXMLCompilerMojo.java | 201 ++++++++++++ .../internal/TestCompilationInfoBuilder.java | 12 +- .../internal/TestCompilationInfoProvider.java | 135 ++++++++ .../compiler/maven/internal/TestCompiler.java | 72 ++--- .../internal/TestControllerInfoProvider.java | 47 ++- .../internal/TestControllerProvider.java | 13 +- .../maven/internal/TestFXMLProvider.java | 6 +- .../maven/internal/TestGenericParser.java | 33 +- .../internal/TestSourceInfoProvider.java | 41 +++ .../maven/internal/com_plex-view.fxml | 8 + .../compiler/maven/internal/infoView.fxml | 17 + .../maven/internal/missingSource.fxml | 14 + .../compiler/maven/internal/noController.fxml | 8 + .../maven/internal/noResourceBundle.fxml | 17 + .../compiler/maven/internal/unknownOn.fxml | 15 + mvnw | 2 +- mvnw.cmd | 298 +++++++++--------- pom.xml | 4 +- .../compiler/parsing/xml/DOMFXMLParser.java | 7 +- .../parsing/xml/TestDOMFXMLParser.java | 66 +++- .../compiler/parsing/xml/invalidDefine.fxml | 11 + .../compiler/parsing/xml/invalidFactory.fxml | 14 + .../fxml/compiler/parsing/xml/loadRoot.fxml | 6 + .../fxml/compiler/parsing/xml/loadScript.fxml | 7 + .../fxml/compiler/parsing/xml/loadView.fxml | 7 + .../compiler/parsing/xml/unknownClass.fxml | 7 + 73 files changed, 1259 insertions(+), 455 deletions(-) create mode 100644 LICENSE.txt create mode 100644 maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/com_plex-view.fxml create mode 100644 maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/infoView.fxml create mode 100644 maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/missingSource.fxml create mode 100644 maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/noController.fxml create mode 100644 maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/noResourceBundle.fxml create mode 100644 maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/unknownOn.fxml create mode 100644 xml/src/test/resources/com/github/gtache/fxml/compiler/parsing/xml/invalidDefine.fxml create mode 100644 xml/src/test/resources/com/github/gtache/fxml/compiler/parsing/xml/invalidFactory.fxml create mode 100644 xml/src/test/resources/com/github/gtache/fxml/compiler/parsing/xml/loadRoot.fxml create mode 100644 xml/src/test/resources/com/github/gtache/fxml/compiler/parsing/xml/loadScript.fxml create mode 100644 xml/src/test/resources/com/github/gtache/fxml/compiler/parsing/xml/unknownClass.fxml diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index b2f4fc0..d58dfb7 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,19 +1,19 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..70594cf --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,9 @@ + The MIT License (MIT) + +Copyright © 2024 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index b0da7f6..de30281 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,9 @@ Optionally add dependencies to the plugin (e.g. when using MediaView and control - `fx:script` is not supported - Possible bugs (file an issue if you see one) -- Expression binding is limited +- Expression binding is (very) limited - Probably not fully compatible with all FXML features (file an issue if you need one in specific) +- All fxml files must have a `fx:controller` attribute ## Parameters @@ -119,7 +120,7 @@ There are four ways to inject fields into a controller: - This allows the controller to have final fields. - This also forces the `controller-injection` method to be `FACTORY`. -### Method injections +### Method injection There are two ways to inject methods (meaning use them as event handlers) into a controller: @@ -133,26 +134,27 @@ There are two ways to inject methods (meaning use them as event handlers) into a ### Resource bundle injection -There are three ways to inject resource bundles into a controller: +There are five ways to inject resource bundles into a controller: - `CONSTRUCTOR`: Inject resource bundle in the view constructor - - ```java - view = new View(controller, resourceBundle); - ``` - - This is the default injection method because it is the most similar to FXMLLoader ( - `FXMLLoader.setResources(resourceBundle)`). + - `view = new View(controller, resourceBundle)` + - This is the default injection method. - `CONSTRUCTOR_FUNCTION`: Injects a function in the view constructor - `bundleFunction.apply(key)` - - The function takes a string (the key) and returns a string (the value) - - This allows using another object than a resource bundle for example + - The function takes a string (the key) and returns a string (the value). + - This allows using another object than a resource bundle for example. - `CONSTRUCTOR_NAME`: Injects the resource bundle name in the view constructor - `ResourceBundle.getBundle(bundleName)` + - Just for the convenience of not having to create the resource bundle instance outside the view. - `GETTER`: Retrieves the resource bundle using a controller getter method - `controller.resources()` - The method name (resources) was chosen because it matches the name of the field injected by FXMLLoader. - The method must be accessible from the view (e.g. package-private). + - **This ignores the `resources` attribute of fx:include.** - `GET-BUNDLE`: Retrieves the resource bundle using a resource path - The resource path is passed to the generator (see [Maven Plugin](#maven-plugin)). + - The resource path will therefore be a constant in the view class. + - **This ignores the `resources` attribute of fx:include.** ## View creation @@ -160,15 +162,13 @@ The views are generated in the same packages as the FXML files. The name of the class is generated from the name of the FXML file. The constructor of the view is generated depending on the parameters of the plugin. -The constructor will have as many arguments as the number of controllers in the FXML tree (recursive fx:include) + +The constructor will have as many arguments as the number of controllers in the FXML tree (recursive fx:include) plus potentially the resource bundle if necessary. If no resource reference (`%key.to.resource`) is found in the FXML tree or -if all the includes using references specify a resources attribute, the argument is not created. +if all the fx:includes using references specify a `resources` attribute, the argument is not created. -The type of the constructor arguments will either be the controller instance or the controller factory (a function of -fields map -> controller). +The type of the constructor arguments will either be the controller instance or the controller factory. The resource bundle argument will either be the resource bundle instance, the resource bundle name or a function of -string -> -string. +string -> string. The smallest constructor will have only one argument: The controller (or controller factory). @@ -206,8 +206,8 @@ The smallest constructor will have only one argument: The controller (or control - default: `{}` - parallelism - The number of threads to use for compilation - - default: `1` - - if `<1`, the number of cores will be used + - default: `1` (no multithreading) + - if `<1`, the number of available cores will be used ### Limitations @@ -216,4 +216,5 @@ The smallest constructor will have only one argument: The controller (or control - The controller info (fields, methods) is obtained from the source file and may therefore be inaccurate. - Custom classes instantiated in the FXML files are not available during generation and may therefore cause it to fail. + - These classes must therefore be in a separate dependency. - If the application uses e.g. WebView, the javafx-web dependency must be added to the plugin dependencies. \ No newline at end of file diff --git a/api/src/main/java/com/github/gtache/fxml/compiler/GenerationException.java b/api/src/main/java/com/github/gtache/fxml/compiler/GenerationException.java index 07c4597..002993a 100644 --- a/api/src/main/java/com/github/gtache/fxml/compiler/GenerationException.java +++ b/api/src/main/java/com/github/gtache/fxml/compiler/GenerationException.java @@ -3,6 +3,7 @@ package com.github.gtache.fxml.compiler; /** * Exception thrown when a generation error occurs */ +@SuppressWarnings("serial") public class GenerationException extends Exception { /** diff --git a/api/src/main/java/com/github/gtache/fxml/compiler/parsing/ParseException.java b/api/src/main/java/com/github/gtache/fxml/compiler/parsing/ParseException.java index 136935d..651f7b5 100644 --- a/api/src/main/java/com/github/gtache/fxml/compiler/parsing/ParseException.java +++ b/api/src/main/java/com/github/gtache/fxml/compiler/parsing/ParseException.java @@ -3,6 +3,7 @@ package com.github.gtache.fxml.compiler.parsing; /** * Exception thrown when a parsing error occurs */ +@SuppressWarnings("serial") public class ParseException extends Exception { /** diff --git a/api/src/test/java/com/github/gtache/fxml/compiler/parsing/TestFXMLParser.java b/api/src/test/java/com/github/gtache/fxml/compiler/parsing/TestFXMLParser.java index 2dabca0..33a6a09 100644 --- a/api/src/test/java/com/github/gtache/fxml/compiler/parsing/TestFXMLParser.java +++ b/api/src/test/java/com/github/gtache/fxml/compiler/parsing/TestFXMLParser.java @@ -7,7 +7,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -46,7 +46,7 @@ class TestFXMLParser { @Test void testParseIOException() throws Exception { - final var file = Paths.get("whatever"); + final var file = Path.of("whatever"); assertThrows(ParseException.class, () -> parser.parse(file)); verify(parser, never()).parse(content); } diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/ClassesFinder.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/ClassesFinder.java index 2f40f7e..df1128b 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/ClassesFinder.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/ClassesFinder.java @@ -5,7 +5,6 @@ import java.net.URI; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -43,12 +42,12 @@ public final class ClassesFinder { final var file = resource.getFile(); if (file.contains(".jar!")) { final var jarFile = file.substring(0, file.indexOf(".jar!") + 4); - try (final var fs = FileSystems.newFileSystem(Paths.get(URI.create(jarFile)), classLoader)) { + try (final var fs = FileSystems.newFileSystem(Path.of(URI.create(jarFile)), classLoader)) { classes.addAll(findClasses(fs.getPath(path), packageName)); } } else { final var filepath = START_FILE_PATTERN.matcher(file).replaceAll(""); - classes.addAll(findClasses(Paths.get(filepath), packageName)); + classes.addAll(findClasses(Path.of(filepath), packageName)); } } return classes; diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/ControllerInfoImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/ControllerInfoImpl.java index 7bbd39b..d6c1aab 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/ControllerInfoImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/ControllerInfoImpl.java @@ -20,6 +20,7 @@ public record ControllerInfoImpl(String className, Map handlerH /** * Instantiates a new controller info + * * @param className The controller class name * @param handlerHasArgument The mapping of method name to true if the method has an argument * @param fieldInfo The mapping of property name to controller field info diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/GenerationRequestImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/GenerationRequestImpl.java index 2682959..89ccb0d 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/GenerationRequestImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/GenerationRequestImpl.java @@ -22,6 +22,7 @@ public record GenerationRequestImpl(GenerationParameters parameters, ControllerI String outputClassName) implements GenerationRequest { /** * Instantiates a new request + * * @param parameters The generation parameters * @param controllerInfo The controller info * @param sourceInfo The source info diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/GeneratorImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/GeneratorImpl.java index 3a8c068..4582f5f 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/GeneratorImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/GeneratorImpl.java @@ -9,8 +9,6 @@ import com.github.gtache.fxml.compiler.impl.internal.HelperProvider; import java.util.Objects; import java.util.function.Function; -//TODO handle binding (${}) - /** * Implementation of {@link Generator} */ @@ -28,6 +26,7 @@ public class GeneratorImpl implements Generator { /** * Used for testing + * * @param helperProviderFactory The helper provider factory */ GeneratorImpl(final Function helperProviderFactory) { diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/SourceInfoImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/SourceInfoImpl.java index 950ff02..6f960aa 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/SourceInfoImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/SourceInfoImpl.java @@ -24,6 +24,7 @@ public record SourceInfoImpl(String generatedClassName, String controllerClassNa /** * Instantiates a new source info + * * @param generatedClassName The generated class name * @param controllerClassName The controller class name * @param sourceFile The source file diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ControllerInjector.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ControllerInjector.java index dc257b9..00f5396 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ControllerInjector.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ControllerInjector.java @@ -8,6 +8,7 @@ import com.github.gtache.fxml.compiler.parsing.ParsedProperty; import java.util.SequencedCollection; +import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.INDENT_8; import static java.util.Objects.requireNonNull; /** @@ -40,14 +41,15 @@ final class ControllerInjector { void injectControllerField(final String id, final String variable) { switch (fieldInjectionType) { case FACTORY -> - sb.append(" fieldMap.put(\"").append(id).append("\", ").append(variable).append(");\n"); - case ASSIGN -> sb.append(" controller.").append(id).append(" = ").append(variable).append(";\n"); + sb.append(INDENT_8).append("fieldMap.put(\"").append(id).append("\", ").append(variable).append(");\n"); + case ASSIGN -> + sb.append(INDENT_8).append("controller.").append(id).append(" = ").append(variable).append(";\n"); case SETTERS -> { final var setMethod = GenerationHelper.getSetMethod(id); - sb.append(" controller.").append(setMethod).append("(").append(variable).append(");\n"); + sb.append(INDENT_8).append("controller.").append(setMethod).append("(").append(variable).append(");\n"); } case REFLECTION -> - sb.append(" injectField(\"").append(id).append("\", ").append(variable).append(");\n"); + sb.append(INDENT_8).append("injectField(\"").append(id).append("\", ").append(variable).append(");\n"); } } @@ -98,13 +100,13 @@ final class ControllerInjector { case REFERENCE -> { final var hasArgument = controllerInfo.handlerHasArgument(controllerMethod); if (hasArgument) { - yield " " + parentVariable + "." + setMethod + "(controller::" + controllerMethod + ");\n"; + yield INDENT_8 + parentVariable + "." + setMethod + "(controller::" + controllerMethod + ");\n"; } else { - yield " " + parentVariable + "." + setMethod + "(e -> controller." + controllerMethod + "());\n"; + yield INDENT_8 + parentVariable + "." + setMethod + "(e -> controller." + controllerMethod + "());\n"; } } case REFLECTION -> - " " + parentVariable + "." + setMethod + "(e -> callEventHandlerMethod(\"" + controllerMethod + "\", e));\n"; + INDENT_8 + parentVariable + "." + setMethod + "(e -> callEventHandlerMethod(\"" + controllerMethod + "\", e));\n"; }; } @@ -120,10 +122,9 @@ final class ControllerInjector { final var setMethod = GenerationHelper.getSetMethod(property.name()); final var controllerMethod = property.value().replace("#", ""); return switch (methodInjectionType) { - case REFERENCE -> - " " + parentVariable + "." + setMethod + "(controller::" + controllerMethod + ");\n"; + case REFERENCE -> INDENT_8 + parentVariable + "." + setMethod + "(controller::" + controllerMethod + ");\n"; case REFLECTION -> - " " + parentVariable + "." + setMethod + "(e -> callCallbackMethod(\"" + controllerMethod + "\", e, " + argumentClazz + "));\n"; + INDENT_8 + parentVariable + "." + setMethod + "(e -> callCallbackMethod(\"" + controllerMethod + "\", e, " + argumentClazz + "));\n"; }; } } diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/FieldSetter.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/FieldSetter.java index 798601f..f2aa564 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/FieldSetter.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/FieldSetter.java @@ -9,6 +9,7 @@ import java.util.Objects; import java.util.SequencedCollection; import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.EXPRESSION_PREFIX; +import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.INDENT_8; import static java.util.Objects.requireNonNull; /** @@ -16,6 +17,7 @@ import static java.util.Objects.requireNonNull; */ final class FieldSetter { + private static final String CONTROLLER = "controller"; private final HelperProvider helperProvider; private final ControllerFieldInjectionType fieldInjectionType; private final StringBuilder sb; @@ -63,10 +65,10 @@ final class FieldSetter { final var value = property.value().replace(EXPRESSION_PREFIX, ""); final var split = value.split("\\."); final var holderName = split[0]; - if (Objects.equals(holderName, "controller")) { - sb.append(" ").append(parentVariable).append(".").append(methodName).append("(").append(value).append(");\n"); + if (Objects.equals(holderName, CONTROLLER)) { + sb.append(INDENT_8).append(parentVariable).append(".").append(methodName).append("(").append(value).append(");\n"); } else { - throw new GenerationException("Unexpected variable holder : " + holderName + " ; expected : controller"); + throw unexpectedHolderException(holderName); } } @@ -83,11 +85,11 @@ final class FieldSetter { final var value = property.value().replace(EXPRESSION_PREFIX, ""); final var split = value.split("\\."); final var holderName = split[0]; - if (Objects.equals(holderName, "controller")) { + if (Objects.equals(holderName, CONTROLLER)) { final var getterName = GenerationHelper.getGetMethod(split[1]); - return " " + parentVariable + "." + methodName + "(controller." + getterName + "());\n"; + return INDENT_8 + parentVariable + "." + methodName + "(" + CONTROLLER + "." + getterName + "());\n"; } else { - throw new GenerationException("Unexpected variable holder : " + holderName + " ; expected : controller"); + throw unexpectedHolderException(holderName); } } @@ -96,20 +98,24 @@ final class FieldSetter { final var value = property.value().replace(EXPRESSION_PREFIX, ""); final var split = value.split("\\."); final var holderName = split[0]; - if (Objects.equals(holderName, "controller")) { + if (Objects.equals(holderName, CONTROLLER)) { final var fieldName = split[1]; sb.append(" try {\n"); sb.append(" ").append(helperProvider.getCompatibilityHelper().getStartVar("java.lang.reflect.Field", 0)) - .append("field = controller.getClass().getDeclaredField(\"").append(fieldName).append("\");\n"); + .append("field = ").append(CONTROLLER).append(".getClass().getDeclaredField(\"").append(fieldName).append("\");\n"); sb.append(" field.setAccessible(true);\n"); - sb.append(" final var value = (").append(fieldType).append(") field.get(controller);\n"); + sb.append(" final var value = (").append(fieldType).append(") field.get(").append(CONTROLLER).append(");\n"); sb.append(" ").append(parentVariable).append(".").append(methodName).append("(value);\n"); sb.append(" } catch (final NoSuchFieldException | IllegalAccessException e) {\n"); sb.append(" throw new RuntimeException(e);\n"); sb.append(" }\n"); } else { - throw new GenerationException("Unexpected variable holder : " + holderName + " ; expected : controller"); + throw unexpectedHolderException(holderName); } } + private static GenerationException unexpectedHolderException(final String holderName) { + return new GenerationException("Unexpected variable holder : " + holderName + " ; expected : " + CONTROLLER); + } + } diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/GenerationHelper.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/GenerationHelper.java index 66cfaf8..f063f72 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/GenerationHelper.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/GenerationHelper.java @@ -3,8 +3,6 @@ package com.github.gtache.fxml.compiler.impl.internal; import com.github.gtache.fxml.compiler.impl.GeneratorImpl; import com.github.gtache.fxml.compiler.parsing.ParsedObject; import com.github.gtache.fxml.compiler.parsing.ParsedProperty; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.util.List; import java.util.Map; @@ -14,7 +12,8 @@ import java.util.Map; */ final class GenerationHelper { - private static final Logger logger = LogManager.getLogger(GenerationHelper.class); + static final String INDENT_8 = " "; + static final String INDENT_12 = " "; static final String FX_ID = "fx:id"; static final String FX_VALUE = "fx:value"; static final String VALUE = "value"; diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/InitializationFormatter.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/InitializationFormatter.java index acf5ed6..0f4155b 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/InitializationFormatter.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/InitializationFormatter.java @@ -21,6 +21,9 @@ import static java.util.Objects.requireNonNull; */ public final class InitializationFormatter { + private static final String RESOURCE_BUNDLE_TYPE = "java.util.ResourceBundle"; + private static final String RESOURCE_BUNDLE = "resourceBundle"; + private final HelperProvider helperProvider; private final GenerationRequest request; private final StringBuilder sb; @@ -106,7 +109,7 @@ public final class InitializationFormatter { private ResourceBundleInfo getResourceBundleInfo() { final var injectionType = request.parameters().resourceInjectionType(); return switch (injectionType) { - case CONSTRUCTOR -> new ResourceBundleInfo("java.util.ResourceBundle", "resourceBundle"); + case CONSTRUCTOR -> new ResourceBundleInfo(RESOURCE_BUNDLE_TYPE, RESOURCE_BUNDLE); case CONSTRUCTOR_FUNCTION -> new ResourceBundleInfo("java.util.function.Function", "resourceBundleFunction"); case CONSTRUCTOR_NAME -> new ResourceBundleInfo("String", "resourceBundleName"); @@ -140,7 +143,7 @@ public final class InitializationFormatter { return hasDuplicateControllerClass(request.sourceInfo(), set); } - private static boolean hasDuplicateControllerClass(final SourceInfo info, final Set controllers) { + private static boolean hasDuplicateControllerClass(final SourceInfo info, final Set controllers) { final var controllerClass = info.controllerClassName(); if (controllers.contains(controllerClass)) { return true; @@ -202,15 +205,15 @@ public final class InitializationFormatter { yield bundleVariable; } case CONSTRUCTOR_FUNCTION -> { - final var bundleVariable = variableProvider.getNextVariableName("resourceBundle"); - sb.append(compatibilityHelper.getStartVar("java.util.ResourceBundle")).append(bundleVariable).append(" = java.util.ResourceBundle.getBundle(\"").append(include.resources()).append("\");\n"); + final var bundleVariable = variableProvider.getNextVariableName(RESOURCE_BUNDLE); + sb.append(compatibilityHelper.getStartVar(RESOURCE_BUNDLE_TYPE)).append(bundleVariable).append(" = java.util.ResourceBundle.getBundle(\"").append(include.resources()).append("\");\n"); final var bundleFunctionVariable = variableProvider.getNextVariableName("resourceBundleFunction"); sb.append(compatibilityHelper.getStartVar("java.util.function.Function")).append(bundleFunctionVariable).append(" = (java.util.function.Function) s -> ").append(bundleVariable).append(".getString(s);\n"); yield bundleFunctionVariable; } case CONSTRUCTOR -> { - final var bundleVariable = variableProvider.getNextVariableName("resourceBundle"); - sb.append(compatibilityHelper.getStartVar("java.util.ResourceBundle")).append(bundleVariable).append(" = java.util.ResourceBundle.getBundle(\"").append(include.resources()).append("\");\n"); + final var bundleVariable = variableProvider.getNextVariableName(RESOURCE_BUNDLE); + sb.append(compatibilityHelper.getStartVar(RESOURCE_BUNDLE_TYPE)).append(bundleVariable).append(" = java.util.ResourceBundle.getBundle(\"").append(include.resources()).append("\");\n"); yield bundleVariable; } }; diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ObjectFormatter.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ObjectFormatter.java index 7daa067..6c3594d 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ObjectFormatter.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/ObjectFormatter.java @@ -325,7 +325,7 @@ final class ObjectFormatter { if (!notDefinedChildren.isEmpty()) { final var defaultProperty = ReflectionHelper.getDefaultProperty(parsedObject.className()); if (!constructorArgs.namedArgs().containsKey(defaultProperty)) { - final var property = new ParsedPropertyImpl(defaultProperty, null, ""); + final var property = new ParsedPropertyImpl(defaultProperty, null, null); helperProvider.getPropertyFormatter().formatProperty(property, notDefinedChildren, parsedObject, variableName); } } diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/PropertyFormatter.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/PropertyFormatter.java index 9124256..1d53055 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/PropertyFormatter.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/PropertyFormatter.java @@ -60,7 +60,7 @@ final class PropertyFormatter { * The values should not contain any ParsedDefine * * @param property The property to format - * @param values The property's values + * @param values The property's values * @param parent The property's parent object * @param parentVariable The parent variable * @throws GenerationException if an error occurs or if the values contain a ParsedDefine diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/SceneFormatter.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/SceneFormatter.java index 8d7546b..318733d 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/SceneFormatter.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/SceneFormatter.java @@ -22,7 +22,7 @@ import static java.util.Objects.requireNonNull; */ final class SceneFormatter { - private static final ParsedProperty ROOT_PROPERTY = new ParsedPropertyImpl("root", null, ""); + private static final ParsedProperty ROOT_PROPERTY = new ParsedPropertyImpl("root", null, null); private final HelperProvider helperProvider; private final StringBuilder sb; diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/TriangleMeshFormatter.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/TriangleMeshFormatter.java index 084ea99..eda56ba 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/TriangleMeshFormatter.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/TriangleMeshFormatter.java @@ -14,8 +14,7 @@ import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.FX_ID; -import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.getSortedAttributes; +import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.*; import static java.util.Objects.requireNonNull; /** @@ -93,37 +92,37 @@ final class TriangleMeshFormatter { private void setPoints(final String variableName, final Collection points) { if (!points.isEmpty()) { - sb.append(" ").append(variableName).append(".getPoints().setAll(new float[]{").append(formatList(points)).append("});\n"); + sb.append(INDENT_8).append(variableName).append(".getPoints().setAll(new float[]{").append(formatList(points)).append("});\n"); } } private void setTexCoords(final String variableName, final Collection texCoords) { if (!texCoords.isEmpty()) { - sb.append(" ").append(variableName).append(".getTexCoords().setAll(new float[]{").append(formatList(texCoords)).append("});\n"); + sb.append(INDENT_8).append(variableName).append(".getTexCoords().setAll(new float[]{").append(formatList(texCoords)).append("});\n"); } } private void setNormals(final String variableName, final Collection normals) { if (!normals.isEmpty()) { - sb.append(" ").append(variableName).append(".getNormals().setAll(new float[]{").append(formatList(normals)).append("});\n"); + sb.append(INDENT_8).append(variableName).append(".getNormals().setAll(new float[]{").append(formatList(normals)).append("});\n"); } } private void setFaces(final String variableName, final Collection faces) { if (!faces.isEmpty()) { - sb.append(" ").append(variableName).append(".getFaces().setAll(new int[]{").append(formatList(faces)).append("});\n"); + sb.append(INDENT_8).append(variableName).append(".getFaces().setAll(new int[]{").append(formatList(faces)).append("});\n"); } } private void setFaceSmoothingGroups(final String variableName, final Collection faceSmoothingGroups) { if (!faceSmoothingGroups.isEmpty()) { - sb.append(" ").append(variableName).append(".getFaceSmoothingGroups().setAll(new int[]{").append(formatList(faceSmoothingGroups)).append("});\n"); + sb.append(INDENT_8).append(variableName).append(".getFaceSmoothingGroups().setAll(new int[]{").append(formatList(faceSmoothingGroups)).append("});\n"); } } private void setVertexFormat(final String variableName, final VertexFormat vertexFormat) { if (vertexFormat != null) { - sb.append(" ").append(variableName).append(".setVertexFormat(javafx.scene.shape.VertexFormat.").append(vertexFormat).append(");\n"); + sb.append(INDENT_8).append(variableName).append(".setVertexFormat(javafx.scene.shape.VertexFormat.").append(vertexFormat).append(");\n"); } } diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableInfo.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableInfo.java index 10a6da7..5cefbcf 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableInfo.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableInfo.java @@ -16,6 +16,7 @@ record VariableInfo(String id, ParsedObject parsedObject, String variableName, S /** * Instantiates a new variable info + * * @param id The fx:id of the variable * @param parsedObject The parsed object of the variable * @param variableName The variable name diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableProvider.java b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableProvider.java index 089911e..5c1d50d 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableProvider.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/impl/internal/VariableProvider.java @@ -33,7 +33,8 @@ class VariableProvider { /** * Adds a variable info - * @param id The variable id + * + * @param id The variable id * @param variableInfo The variable info */ void addVariableInfo(final String id, final VariableInfo variableInfo) { @@ -42,6 +43,7 @@ class VariableProvider { /** * Gets the variable info + * * @param id The variable id * @return The variable info */ diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedDefineImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedDefineImpl.java index c6b6887..ca86371 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedDefineImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedDefineImpl.java @@ -14,6 +14,7 @@ public record ParsedDefineImpl(List children) implements ParsedDef /** * Instantiates the define + * * @param children The children * @throws NullPointerException If the children are null */ diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedIncludeImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedIncludeImpl.java index a4b2803..601a083 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedIncludeImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedIncludeImpl.java @@ -6,6 +6,8 @@ import com.github.gtache.fxml.compiler.parsing.ParsedProperty; import java.util.HashMap; import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link ParsedInclude} * @@ -42,6 +44,7 @@ public record ParsedIncludeImpl(Map attributes) implemen } private static Map createAttributes(final String source, final String resources, final String fxId) { + requireNonNull(source); final var map = HashMap.newHashMap(3); map.put(SOURCE, new ParsedPropertyImpl(SOURCE, null, source)); if (resources != null) { diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedObjectImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedObjectImpl.java index 16c3c2f..c683e3f 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedObjectImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedObjectImpl.java @@ -25,6 +25,7 @@ public record ParsedObjectImpl(String className, Map att /** * Instantiates a new object + * * @param className The object class * @param attributes The object attributes * @param properties The object properties diff --git a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedPropertyImpl.java b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedPropertyImpl.java index 6907691..16ac170 100644 --- a/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedPropertyImpl.java +++ b/core/src/main/java/com/github/gtache/fxml/compiler/parsing/impl/ParsedPropertyImpl.java @@ -15,13 +15,13 @@ public record ParsedPropertyImpl(String name, String sourceType, String value) i /** * Instantiates a property + * * @param name The property name * @param sourceType The property source type * @param value The property value - * @throws NullPointerException If the name or value is null + * @throws NullPointerException If the name is null */ public ParsedPropertyImpl { requireNonNull(name); - requireNonNull(value); } } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/TestSourceInfoImpl.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/TestSourceInfoImpl.java index 727396a..42eb597 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/TestSourceInfoImpl.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/TestSourceInfoImpl.java @@ -7,7 +7,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -30,7 +29,7 @@ class TestSourceInfoImpl { TestSourceInfoImpl(@Mock final SourceInfo subInfo) { this.generatedClassName = "class"; this.controllerClassName = "controller"; - this.sourceFile = Paths.get("path"); + this.sourceFile = Path.of("path"); this.includedSources = new ArrayList<>(List.of(subInfo)); this.sourceToSourceInfo = new HashMap<>(Map.of("source", subInfo)); this.requiresResourceBundle = false; diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestConstructorHelper.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestConstructorHelper.java index f4e12d3..d2a77c5 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestConstructorHelper.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestConstructorHelper.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class TestConstructorHelper { + private static final Annotation[][] EMPTY_ANNOTATIONS = new Annotation[0][]; private final ConstructorArgs args; private final Constructor[] constructors; private final ParsedObject parsedObject; @@ -83,7 +84,7 @@ class TestConstructorHelper { namedArgs.put("p1", new Parameter("p1", int.class, "0")); namedArgs.put("p2", new Parameter("p2", String.class, "value2")); - when(constructors[0].getParameterAnnotations()).thenReturn(new Annotation[0][]); + when(constructors[0].getParameterAnnotations()).thenReturn(EMPTY_ANNOTATIONS); when(constructors[1].getParameterAnnotations()).thenReturn(new Annotation[][]{{new NamedArgImpl("p1", "")}, { new NamedArgImpl("p2", "value2")}}); when(constructors[1].getParameterTypes()).thenReturn(new Class[]{int.class, String.class}); @@ -95,8 +96,8 @@ class TestConstructorHelper { void testGetMatchingConstructorArgsEmpty() { final var namedArgs = new LinkedHashMap(); - when(constructors[0].getParameterAnnotations()).thenReturn(new Annotation[0][]); - when(constructors[1].getParameterAnnotations()).thenReturn(new Annotation[0][]); + when(constructors[0].getParameterAnnotations()).thenReturn(EMPTY_ANNOTATIONS); + when(constructors[1].getParameterAnnotations()).thenReturn(EMPTY_ANNOTATIONS); when(constructors[0].getParameterCount()).thenReturn(0); when(constructors[1].getParameterCount()).thenReturn(1); final var expectedArgs = new ConstructorArgs(constructors[0], namedArgs); @@ -105,8 +106,8 @@ class TestConstructorHelper { @Test void testGetMatchingConstructorArgsNull() { - when(constructors[0].getParameterAnnotations()).thenReturn(new Annotation[0][]); - when(constructors[1].getParameterAnnotations()).thenReturn(new Annotation[0][]); + when(constructors[0].getParameterAnnotations()).thenReturn(EMPTY_ANNOTATIONS); + when(constructors[1].getParameterAnnotations()).thenReturn(EMPTY_ANNOTATIONS); when(constructors[0].getParameterCount()).thenReturn(1); when(constructors[1].getParameterCount()).thenReturn(1); assertNull(ConstructorHelper.getMatchingConstructorArgs(constructors, propertyNames)); diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestFontFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestFontFormatter.java index 1592421..8f7f335 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestFontFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestFontFormatter.java @@ -50,7 +50,7 @@ class TestFontFormatter { } @BeforeEach - void beforeEach() throws GenerationException { + void beforeEach() { when(helperProvider.getCompatibilityHelper()).thenReturn(compatibilityHelper); when(helperProvider.getURLFormatter()).thenReturn(urlFormatter); when(parsedObject.attributes()).thenReturn(attributes); @@ -70,7 +70,7 @@ class TestFontFormatter { @Test void testHasProperties() { final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("str", null, ""), List.of(parsedObject)); + properties.put(new ParsedPropertyImpl("str", null, null), List.of(parsedObject)); when(parsedObject.properties()).thenReturn(properties); assertThrows(GenerationException.class, () -> fontFormatter.formatFont(parsedObject, variableName)); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestImageFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestImageFormatter.java index 441ed69..c75f888 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestImageFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestImageFormatter.java @@ -19,7 +19,6 @@ import java.util.SequencedCollection; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -50,7 +49,7 @@ class TestImageFormatter { } @BeforeEach - void beforeEach() throws GenerationException { + void beforeEach() { when(helperProvider.getCompatibilityHelper()).thenReturn(compatibilityHelper); when(helperProvider.getURLFormatter()).thenReturn(urlFormatter); when(helperProvider.getVariableProvider()).thenReturn(variableProvider); @@ -72,7 +71,7 @@ class TestImageFormatter { @Test void testHasProperties() { final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("str", null, ""), List.of(parsedObject)); + properties.put(new ParsedPropertyImpl("str", null, null), List.of(parsedObject)); when(parsedObject.properties()).thenReturn(properties); assertThrows(GenerationException.class, () -> imageFormatter.formatImage(parsedObject, variableName)); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestLoadMethodFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestLoadMethodFormatter.java index 45c970d..9582226 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestLoadMethodFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestLoadMethodFormatter.java @@ -22,7 +22,6 @@ import java.util.Objects; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestObjectFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestObjectFormatter.java index 6aeae94..0e89922 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestObjectFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestObjectFormatter.java @@ -28,8 +28,6 @@ import java.util.SequencedCollection; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -146,49 +144,49 @@ class TestObjectFormatter { } @Test - void testHandleIdPropertyTooManyChildren(@Mock final ControllerFieldInfo fieldInfo, @Mock PropertyFormatter propertyFormatter) { + void testHandleIdPropertyTooManyChildren(@Mock final ControllerFieldInfo fieldInfo, @Mock final PropertyFormatter propertyFormatter) { when(helperProvider.getPropertyFormatter()).thenReturn(propertyFormatter); final var className = "javafx.scene.control.Label"; final var value = "id"; final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("fx:id", null, ""), List.of(new ParsedTextImpl("value"), new ParsedTextImpl("value2"))); + properties.put(new ParsedPropertyImpl("fx:id", null, null), List.of(new ParsedTextImpl("value"), new ParsedTextImpl("value2"))); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); when(controllerInfo.fieldInfo(value)).thenReturn(fieldInfo); assertThrows(GenerationException.class, () -> objectFormatter.format(parsedObject, variableName)); } @Test - void testHandleIdPropertyNoChildren(@Mock final ControllerFieldInfo fieldInfo, @Mock PropertyFormatter propertyFormatter) { + void testHandleIdPropertyNoChildren(@Mock final ControllerFieldInfo fieldInfo, @Mock final PropertyFormatter propertyFormatter) { when(helperProvider.getPropertyFormatter()).thenReturn(propertyFormatter); final var className = "javafx.scene.control.Label"; final var value = "id"; final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("fx:id", null, ""), List.of()); + properties.put(new ParsedPropertyImpl("fx:id", null, null), List.of()); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); when(controllerInfo.fieldInfo(value)).thenReturn(fieldInfo); assertThrows(GenerationException.class, () -> objectFormatter.format(parsedObject, variableName)); } @Test - void testHandleIdPropertyNotText(@Mock final ControllerFieldInfo fieldInfo, @Mock PropertyFormatter propertyFormatter) { + void testHandleIdPropertyNotText(@Mock final ControllerFieldInfo fieldInfo, @Mock final PropertyFormatter propertyFormatter) { when(helperProvider.getPropertyFormatter()).thenReturn(propertyFormatter); final var className = "javafx.scene.control.Label"; final var value = "id"; final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("fx:id", null, ""), List.of(mock(ParsedObject.class))); + properties.put(new ParsedPropertyImpl("fx:id", null, null), List.of(mock(ParsedObject.class))); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); when(controllerInfo.fieldInfo(value)).thenReturn(fieldInfo); assertThrows(GenerationException.class, () -> objectFormatter.format(parsedObject, variableName)); } @Test - void testHandleIdProperty(@Mock final ControllerFieldInfo fieldInfo, @Mock PropertyFormatter propertyFormatter) throws GenerationException { + void testHandleIdProperty(@Mock final ControllerFieldInfo fieldInfo, @Mock final PropertyFormatter propertyFormatter) throws GenerationException { when(helperProvider.getPropertyFormatter()).thenReturn(propertyFormatter); final var className = "javafx.scene.control.Label"; final var value = "id"; final var properties = new LinkedHashMap>(); final var define = mock(ParsedDefine.class); - properties.put(new ParsedPropertyImpl("fx:id", null, ""), List.of(define, new ParsedTextImpl(value))); + properties.put(new ParsedPropertyImpl("fx:id", null, null), List.of(define, new ParsedTextImpl(value))); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); when(controllerInfo.fieldInfo(value)).thenReturn(fieldInfo); doNothing().when(objectFormatter).format(define, "define"); @@ -317,8 +315,10 @@ class TestObjectFormatter { when(sourceInfo.sourceToSourceInfo()).thenReturn(sourceToSourceInfo); final var include = new ParsedIncludeImpl("source", "resources", "id"); objectFormatter.format(include, variableName); - final var expected = "include(source, resources) final javafx.scene.Parent variable = view.load();\n" + - "controllerClassNamecontroller = view.controller();\n"; + final var expected = """ + include(source, resources) final javafx.scene.Parent variable = view.load(); + controllerClassNamecontroller = view.controller(); + """; assertEquals(expected, sb.toString()); verify(initializationFormatter).formatSubViewConstructorCall(include); } @@ -334,8 +334,10 @@ class TestObjectFormatter { when(sourceInfo.sourceToSourceInfo()).thenReturn(sourceToSourceInfo); final var include = new ParsedIncludeImpl(source, "resources", "id"); objectFormatter.format(include, variableName); - final var expected = "include(source, resources) final javafx.scene.Parent variable = view.load();\n" + - "controllerClassNamecontroller = view.controller();\ninject(idController, controller)inject(id, variable)"; + final var expected = """ + include(source, resources) final javafx.scene.Parent variable = view.load(); + controllerClassNamecontroller = view.controller(); + inject(idController, controller)inject(id, variable)"""; assertEquals(expected, sb.toString()); verify(initializationFormatter).formatSubViewConstructorCall(include); verify(controllerInjector).injectControllerField("id", "variable"); @@ -441,7 +443,7 @@ class TestObjectFormatter { @Test void testFormatSimpleClassProperties() { final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("str", null, ""), List.of(mock(ParsedObject.class))); + properties.put(new ParsedPropertyImpl("str", null, null), List.of(mock(ParsedObject.class))); final var parsedObject = new ParsedObjectImpl("java.lang.String", Map.of(), properties, List.of()); assertThrows(GenerationException.class, () -> objectFormatter.format(parsedObject, variableName)); } @@ -568,7 +570,7 @@ class TestObjectFormatter { "initialValue", new ParsedPropertyImpl("initialValue", null, "3")); final var label = new ParsedObjectImpl("javafx.scene.control.Label", Map.of(), new LinkedHashMap<>(), List.of()); final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("childrenUnmodifiable", null, ""), List.of(label)); + properties.put(new ParsedPropertyImpl("childrenUnmodifiable", null, null), List.of(label)); final var define = mock(ParsedDefine.class); doAnswer(i -> sb.append("define")).when(objectFormatter).format(define, "define"); final var parsedObject = new ParsedObjectImpl(className, attributes, properties, List.of(define)); @@ -577,7 +579,7 @@ class TestObjectFormatter { final var expected = "definestartVarvariable = new javafx.scene.control.Spinner(1, 2, 3);\nproperty"; assertEquals(expected, sb.toString()); verify(propertyFormatter).formatProperty(new ParsedPropertyImpl("editable", null, "false"), parsedObject, variableName); - verify(propertyFormatter).formatProperty(new ParsedPropertyImpl("childrenUnmodifiable", null, ""), List.of(label), parsedObject, variableName); + verify(propertyFormatter).formatProperty(new ParsedPropertyImpl("childrenUnmodifiable", null, null), List.of(label), parsedObject, variableName); verify(objectFormatter).format(define, "define"); verify(compatibilityHelper).getStartVar(parsedObject); verify(reflectionHelper).getGenericTypes(parsedObject); @@ -591,7 +593,7 @@ class TestObjectFormatter { final var className = "javafx.scene.control.Spinner"; final var attributes = Map.of(); final var label = new ParsedObjectImpl("javafx.scene.control.Label", Map.of(), new LinkedHashMap<>(), List.of()); - final var property = new ParsedPropertyImpl("childrenUnmodifiable", null, ""); + final var property = new ParsedPropertyImpl("childrenUnmodifiable", null, null); final var properties = new LinkedHashMap>(); properties.put(property, List.of(label, label)); final var parsedObject = new ParsedObjectImpl(className, attributes, properties, List.of()); @@ -617,7 +619,7 @@ class TestObjectFormatter { objectFormatter.format(parsedObject, variableName); final var expected = "startVarvariable = new javafx.scene.layout.StackPane();\nproperty"; assertEquals(expected, sb.toString()); - verify(propertyFormatter).formatProperty(new ParsedPropertyImpl("children", null, ""), children, parsedObject, variableName); + verify(propertyFormatter).formatProperty(new ParsedPropertyImpl("children", null, null), children, parsedObject, variableName); verify(compatibilityHelper).getStartVar(parsedObject); verify(reflectionHelper).getGenericTypes(parsedObject); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestPropertyFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestPropertyFormatter.java index 06376d3..6657fc3 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestPropertyFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestPropertyFormatter.java @@ -28,8 +28,6 @@ import java.util.Objects; import java.util.SequencedCollection; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -211,7 +209,7 @@ class TestPropertyFormatter { void testFormatListSingleValue() throws GenerationException { final var text = new ParsedTextImpl("text"); final var values = List.of(text); - final var emptyProperty = new ParsedPropertyImpl("name", null, ""); + final var emptyProperty = new ParsedPropertyImpl("name", null, null); final var newProperty = new ParsedPropertyImpl("name", null, text.text()); doNothing().when(propertyFormatter).formatProperty(newProperty, rootObject, variableName); propertyFormatter.formatProperty(emptyProperty, values, rootObject, variableName); @@ -222,7 +220,7 @@ class TestPropertyFormatter { void testFormatListSingleValueStatic() throws GenerationException { final var text = new ParsedTextImpl("text"); final var values = List.of(text); - final var emptyProperty = new ParsedPropertyImpl("name", String.class.getName(), ""); + final var emptyProperty = new ParsedPropertyImpl("name", String.class.getName(), null); final var newProperty = new ParsedPropertyImpl("name", String.class.getName(), text.text()); doNothing().when(propertyFormatter).formatProperty(newProperty, rootObject, variableName); propertyFormatter.formatProperty(emptyProperty, values, rootObject, variableName); @@ -267,7 +265,7 @@ class TestPropertyFormatter { final var className = "javafx.scene.layout.BorderPane"; final var properties = new LinkedHashMap>(); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); - when(property.name()).thenReturn("blabla"); + when(property.name()).thenReturn("abc"); final var child = new ParsedObjectImpl("javafx.scene.control.Label", Map.of(), new LinkedHashMap<>(), List.of()); final var objects = List.of(child); assertThrows(GenerationException.class, () -> propertyFormatter.formatProperty(property, objects, parsedObject, variableName)); @@ -296,7 +294,7 @@ class TestPropertyFormatter { final var className = "javafx.scene.layout.HBox"; final var properties = new LinkedHashMap>(); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); - when(property.name()).thenReturn("blabla"); + when(property.name()).thenReturn("abc"); final var child = new ParsedObjectImpl("javafx.scene.control.Label", Map.of(), new LinkedHashMap<>(), List.of()); final var objects = List.of(child, child); assertThrows(GenerationException.class, () -> propertyFormatter.formatProperty(property, objects, parsedObject, variableName)); @@ -326,7 +324,7 @@ class TestPropertyFormatter { final var className = "javafx.scene.layout.BorderPane"; final var properties = new LinkedHashMap>(); final var parsedObject = new ParsedObjectImpl(className, Map.of(), properties, List.of()); - when(property.name()).thenReturn("blabla"); + when(property.name()).thenReturn("abc"); when(property.sourceType()).thenReturn("javafx.scene.layout.GridPane"); final var child = new ParsedObjectImpl("javafx.scene.control.Label", Map.of(), new LinkedHashMap<>(), List.of()); final var objects = List.of(child); diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestSceneFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestSceneFormatter.java index 790ed51..f6d3f6b 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestSceneFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestSceneFormatter.java @@ -22,8 +22,6 @@ import java.util.SequencedMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -81,33 +79,33 @@ class TestSceneFormatter { @Test void testUnknownAttribute() { - properties.put(new ParsedPropertyImpl("root", null, ""), List.of(parsedObject)); + properties.put(new ParsedPropertyImpl("root", null, null), List.of(parsedObject)); attributes.put("unknown", new ParsedPropertyImpl("unknown", null, "value")); assertThrows(GenerationException.class, () -> sceneFormatter.formatScene(parsedObject, variableName)); } @Test void testNonRootProperty() { - properties.put(new ParsedPropertyImpl("property", null, ""), List.of(parsedObject)); + properties.put(new ParsedPropertyImpl("property", null, null), List.of(parsedObject)); assertThrows(GenerationException.class, () -> sceneFormatter.formatScene(parsedObject, variableName)); } @Test void testRootPropertyNonEmptyChildren() { - properties.put(new ParsedPropertyImpl("root", null, ""), List.of(parsedObject)); + properties.put(new ParsedPropertyImpl("root", null, null), List.of(parsedObject)); children.add(parsedObject); assertThrows(GenerationException.class, () -> sceneFormatter.formatScene(parsedObject, variableName)); } @Test void testRootPropertyEmptyChild() { - properties.put(new ParsedPropertyImpl("root", null, ""), List.of()); + properties.put(new ParsedPropertyImpl("root", null, null), List.of()); assertThrows(GenerationException.class, () -> sceneFormatter.formatScene(parsedObject, variableName)); } @Test void testRootPropertyNonOneChild() { - properties.put(new ParsedPropertyImpl("root", null, ""), List.of(parsedObject, parsedObject)); + properties.put(new ParsedPropertyImpl("root", null, null), List.of(parsedObject, parsedObject)); assertThrows(GenerationException.class, () -> sceneFormatter.formatScene(parsedObject, variableName)); } @@ -127,7 +125,7 @@ class TestSceneFormatter { void testDefaultAttributesProperty() throws GenerationException { final var rootObject = mock(ParsedObject.class); final var define = mock(ParsedDefine.class); - properties.put(new ParsedPropertyImpl("root", null, ""), List.of(define, rootObject)); + properties.put(new ParsedPropertyImpl("root", null, null), List.of(define, rootObject)); sceneFormatter.formatScene(parsedObject, variableName); final var expected = "definerootjavafx.scene.Scenevariable = new javafx.scene.Scene(root, -1.0, -1.0, javafx.scene.paint.Color.valueOf(\"0xffffffff\"));\n"; assertEquals(expected, sb.toString()); @@ -151,15 +149,17 @@ class TestSceneFormatter { @Test void testAllAttributesProperty() throws GenerationException { final var rootObject = mock(ParsedObject.class); - properties.put(new ParsedPropertyImpl("root", null, ""), List.of(rootObject)); + properties.put(new ParsedPropertyImpl("root", null, null), List.of(rootObject)); attributes.put("width", new ParsedPropertyImpl("width", null, "100")); attributes.put("height", new ParsedPropertyImpl("height", null, "200")); attributes.put("fill", new ParsedPropertyImpl("fill", null, "#FF0000")); attributes.put("stylesheets", new ParsedPropertyImpl("stylesheets", null, "style.css")); sceneFormatter.formatScene(parsedObject, variableName); - final var expected = "rootjavafx.scene.Scenevariable = new javafx.scene.Scene(root, 100.0, 200.0, javafx.scene.paint.Color.valueOf(\"#FF0000\"));\n" + - "style.cssjava.util.Liststylesheets = variable.getStyleSheets();\n" + - " stylesheets.addAll(listof(1, 2));\n"; + final var expected = """ + rootjavafx.scene.Scenevariable = new javafx.scene.Scene(root, 100.0, 200.0, javafx.scene.paint.Color.valueOf("#FF0000")); + style.cssjava.util.Liststylesheets = variable.getStyleSheets(); + stylesheets.addAll(listof(1, 2)); + """; assertEquals(expected, sb.toString()); verify(objectFormatter).format(rootObject, "root"); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestTriangleMeshFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestTriangleMeshFormatter.java index df22a2c..b966a71 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestTriangleMeshFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestTriangleMeshFormatter.java @@ -45,7 +45,7 @@ class TestTriangleMeshFormatter { } @BeforeEach - void beforeEach() throws GenerationException { + void beforeEach() { when(helperProvider.getCompatibilityHelper()).thenReturn(compatibilityHelper); when(parsedObject.attributes()).thenReturn(attributes); when(parsedObject.children()).thenReturn(List.of()); @@ -62,7 +62,7 @@ class TestTriangleMeshFormatter { @Test void testFormatProperties() { final var map = new LinkedHashMap>(); - map.put(new ParsedPropertyImpl("str", null, ""), List.of()); + map.put(new ParsedPropertyImpl("str", null, null), List.of()); when(parsedObject.properties()).thenReturn(map); assertThrows(GenerationException.class, () -> triangleMeshFormatter.formatTriangleMesh(parsedObject, variableName)); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestURLFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestURLFormatter.java index a6af9cb..0d01524 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestURLFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestURLFormatter.java @@ -44,7 +44,7 @@ class TestURLFormatter { } @BeforeEach - void beforeEach() throws GenerationException { + void beforeEach() { when(helperProvider.getCompatibilityHelper()).thenReturn(compatibilityHelper); when(helperProvider.getVariableProvider()).thenReturn(variableProvider); when(variableProvider.getNextVariableName("url")).thenReturn("url1", "url2"); @@ -78,7 +78,7 @@ class TestURLFormatter { @Test void testFormatURLObjectProperties() { final var map = new LinkedHashMap>(); - map.put(new ParsedPropertyImpl("str", null, ""), List.of()); + map.put(new ParsedPropertyImpl("str", null, null), List.of()); when(parsedObject.properties()).thenReturn(map); assertThrows(GenerationException.class, () -> urlFormatter.formatURL(parsedObject, variableName)); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestWebViewFormatter.java b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestWebViewFormatter.java index 4bca54f..e98f4c4 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestWebViewFormatter.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/impl/internal/TestWebViewFormatter.java @@ -84,7 +84,7 @@ class TestWebViewFormatter { @Test void testFormatHasProperty() { final var properties = new LinkedHashMap>(); - properties.put(new ParsedPropertyImpl("str", null, ""), List.of(parsedObject)); + properties.put(new ParsedPropertyImpl("str", null, null), List.of(parsedObject)); when(parsedObject.properties()).thenReturn(properties); assertThrows(GenerationException.class, () -> webViewFormatter.formatWebView(parsedObject, variableName)); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedIncludeImpl.java b/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedIncludeImpl.java index 25670d1..2e6895d 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedIncludeImpl.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedIncludeImpl.java @@ -58,7 +58,7 @@ class TestParsedIncludeImpl { @Test void testIllegal() { assertThrows(NullPointerException.class, () -> new ParsedIncludeImpl(null)); - assertThrows(NullPointerException.class, () -> new ParsedIncludeImpl(null, "", "")); + assertThrows(NullPointerException.class, () -> new ParsedIncludeImpl(null, "", null)); assertDoesNotThrow(() -> new ParsedIncludeImpl("", null, null)); final var emptyMap = Map.of(); assertThrows(IllegalArgumentException.class, () -> new ParsedIncludeImpl(emptyMap)); diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedObjectImpl.java b/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedObjectImpl.java index 0afd9b3..2b4695d 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedObjectImpl.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedObjectImpl.java @@ -31,7 +31,7 @@ class TestParsedObjectImpl { this.attributes = new LinkedHashMap<>(); this.attributes.put("name", property); this.properties = new LinkedHashMap<>(); - this.properties.put(new ParsedPropertyImpl("property", null, ""), List.of(object)); + this.properties.put(new ParsedPropertyImpl("property", null, null), List.of(object)); this.objects = new ArrayList<>(List.of(define)); this.parsedObject = new ParsedObjectImpl(clazz, attributes, properties, objects); } diff --git a/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedPropertyImpl.java b/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedPropertyImpl.java index 0bd441e..09884df 100644 --- a/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedPropertyImpl.java +++ b/core/src/test/java/com/github/gtache/fxml/compiler/parsing/impl/TestParsedPropertyImpl.java @@ -30,6 +30,6 @@ class TestParsedPropertyImpl { void testIllegal() { assertThrows(NullPointerException.class, () -> new ParsedPropertyImpl(null, sourceType, value)); assertDoesNotThrow(() -> new ParsedPropertyImpl(name, null, value)); - assertThrows(NullPointerException.class, () -> new ParsedPropertyImpl(name, sourceType, null)); + assertDoesNotThrow(() -> new ParsedPropertyImpl(name, sourceType, null)); } } diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/FXMLCompilerMojo.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/FXMLCompilerMojo.java index 58af699..07ceac6 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/FXMLCompilerMojo.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/FXMLCompilerMojo.java @@ -19,12 +19,16 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import static java.util.Objects.requireNonNull; + /** * Main mojo for FXML compiler */ @@ -61,34 +65,66 @@ public class FXMLCompilerMojo extends AbstractMojo { @Parameter(property = "parallelism", defaultValue = "1", required = true) private int parallelism; + private final Compiler compiler; + private final CompilationInfoProvider.Factory compilationInfoProviderFactory; + private final ControllerProvider controllerProvider; + private final FXMLProvider.Factory fxmlProviderFactory; + + /** + * Instantiates a new MOJO with the given helpers (used for testing) + * + * @param compiler The compiler + * @param compilationInfoProviderFactory The compilation info provider + * @param controllerProvider The controller provider + * @param fxmlProviderFactory The FXML provider factory + * @throws NullPointerException If any parameter is null + */ + FXMLCompilerMojo(final Compiler compiler, final CompilationInfoProvider.Factory compilationInfoProviderFactory, + final ControllerProvider controllerProvider, final FXMLProvider.Factory fxmlProviderFactory) { + this.compiler = requireNonNull(compiler); + this.compilationInfoProviderFactory = requireNonNull(compilationInfoProviderFactory); + this.controllerProvider = requireNonNull(controllerProvider); + this.fxmlProviderFactory = requireNonNull(fxmlProviderFactory); + } + + /** + * Instantiates a new MOJO + */ + FXMLCompilerMojo() { + this(new Compiler(), CompilationInfoProvider::new, new ControllerProvider(), FXMLProvider::new); + } @Override public void execute() throws MojoExecutionException { - if (fieldInjectionType == ControllerFieldInjectionType.FACTORY && controllerInjectionType != ControllerInjectionType.FACTORY) { - getLog().warn("Field injection is set to FACTORY : Forcing controller injection to FACTORY"); - controllerInjectionType = ControllerInjectionType.FACTORY; - } - final var fxmls = FXMLProvider.getFXMLs(project); - if (parallelism < 1) { - parallelism = Runtime.getRuntime().availableProcessors(); - } - if (parallelism > 1) { - try (final var executor = Executors.newFixedThreadPool(parallelism)) { - final var controllerMapping = createControllerMapping(fxmls, executor); - final var compilationInfoMapping = createCompilationInfoMapping(fxmls, controllerMapping, executor); - compile(compilationInfoMapping, executor); + try { + if (fieldInjectionType == ControllerFieldInjectionType.FACTORY && controllerInjectionType != ControllerInjectionType.FACTORY) { + getLog().warn("Field injection is set to FACTORY : Forcing controller injection to FACTORY"); + controllerInjectionType = ControllerInjectionType.FACTORY; } - } else { - final var controllerMapping = createControllerMapping(fxmls); - final var compilationInfoMapping = createCompilationInfoMapping(fxmls, controllerMapping); - compile(compilationInfoMapping); + final var fxmls = fxmlProviderFactory.create(project).getFXMLs(); + if (parallelism < 1) { + parallelism = Runtime.getRuntime().availableProcessors(); + } + if (parallelism > 1) { + try (final var executor = Executors.newFixedThreadPool(parallelism)) { + final var controllerMapping = createControllerMapping(fxmls, executor); + final var compilationInfoMapping = createCompilationInfoMapping(fxmls, controllerMapping, executor); + compile(compilationInfoMapping, executor); + } + } else { + final var controllerMapping = createControllerMapping(fxmls); + final var compilationInfoMapping = createCompilationInfoMapping(fxmls, controllerMapping); + compile(compilationInfoMapping); + } + } catch (final RuntimeException e) { + throw new MojoExecutionException(e); } } - private static Map createControllerMapping(final Map fxmls) throws MojoExecutionException { + private Map createControllerMapping(final Map fxmls) throws MojoExecutionException { final var mapping = new HashMap(); for (final var fxml : fxmls.keySet()) { - mapping.put(fxml, ControllerProvider.getController(fxml)); + mapping.put(fxml, controllerProvider.getController(fxml)); } return mapping; } @@ -96,8 +132,9 @@ public class FXMLCompilerMojo extends AbstractMojo { private Map createCompilationInfoMapping(final Map fxmls, final Map controllerMapping) throws MojoExecutionException { final var mapping = new HashMap(); + final var compilationInfoProvider = compilationInfoProviderFactory.create(project, outputDirectory); for (final var entry : fxmls.entrySet()) { - final var info = CompilationInfoProvider.getCompilationInfo(entry.getValue(), entry.getKey(), controllerMapping, outputDirectory, project); + final var info = compilationInfoProvider.getCompilationInfo(entry.getValue(), entry.getKey(), controllerMapping); mapping.put(entry.getKey(), info); } return mapping; @@ -106,51 +143,75 @@ public class FXMLCompilerMojo extends AbstractMojo { private void compile(final Map mapping) throws MojoExecutionException { final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion), useImageInputStreamConstructor, resourceMap, controllerInjectionType, fieldInjectionType, methodInjectionType, resourceInjectionType); - Compiler.compile(mapping, parameters); + compiler.compile(mapping, parameters); project.addCompileSourceRoot(outputDirectory.toAbsolutePath().toString()); } - private static Map createControllerMapping(final Map fxmls, - final ExecutorService executor) { - final var mapping = new ConcurrentHashMap(); + private Map createControllerMapping(final Map fxmls, + final Executor executor) { + final var futures = new ArrayList>(fxmls.size()); for (final var fxml : fxmls.keySet()) { - executor.submit(() -> { + futures.add(CompletableFuture.supplyAsync(() -> { try { - mapping.put(fxml, ControllerProvider.getController(fxml)); + final var controller = controllerProvider.getController(fxml); + return new ControllerMapping(fxml, controller); } catch (final MojoExecutionException e) { - throw new RuntimeException(e); + throw new CompletionException(e); } - }); + }, executor)); } + final var mapping = new HashMap(); + futures.forEach(c -> { + final var joined = c.join(); + mapping.put(joined.fxml(), joined.controller()); + }); return mapping; } + private record ControllerMapping(Path fxml, String controller) { + } + private Map createCompilationInfoMapping(final Map fxmls, - final Map controllerMapping, final ExecutorService executor) { - final var mapping = new ConcurrentHashMap(); + final Map controllerMapping, + final Executor executor) { + final var compilationInfoProvider = compilationInfoProviderFactory.create(project, outputDirectory); + final var futures = new ArrayList>(fxmls.size()); for (final var entry : fxmls.entrySet()) { - executor.submit(() -> { + futures.add(CompletableFuture.supplyAsync(() -> { try { - final var info = CompilationInfoProvider.getCompilationInfo(entry.getValue(), entry.getKey(), controllerMapping, outputDirectory, project); - mapping.put(entry.getKey(), info); + final var info = compilationInfoProvider.getCompilationInfo(entry.getValue(), entry.getKey(), + controllerMapping); + return new CompilationInfoMapping(entry.getKey(), info); } catch (final MojoExecutionException e) { - throw new RuntimeException(e); + throw new CompletionException(e); } - }); + }, executor)); } + final var mapping = new HashMap(); + futures.forEach(c -> { + final var joined = c.join(); + mapping.put(joined.fxml(), joined.info()); + }); return mapping; } - private void compile(final Map mapping, final ExecutorService executor) throws MojoExecutionException { - final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion), useImageInputStreamConstructor, resourceMap, - controllerInjectionType, fieldInjectionType, methodInjectionType, resourceInjectionType); - mapping.forEach((p, i) -> executor.submit(() -> { + private record CompilationInfoMapping(Path fxml, CompilationInfo info) { + + } + + private void compile(final Map mapping, final Executor executor) { + final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion), + useImageInputStreamConstructor, resourceMap, controllerInjectionType, fieldInjectionType, + methodInjectionType, resourceInjectionType); + final var futures = new ArrayList>(mapping.size()); + mapping.forEach((p, i) -> futures.add(CompletableFuture.runAsync(() -> { try { - Compiler.compile(p, i, mapping, parameters); + compiler.compile(p, i, mapping, parameters); } catch (final MojoExecutionException e) { - throw new RuntimeException(e); + throw new CompletionException(e); } - })); + }, executor))); + futures.forEach(CompletableFuture::join); project.addCompileSourceRoot(outputDirectory.toAbsolutePath().toString()); } } diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfo.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfo.java index df59848..13d7a52 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfo.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfo.java @@ -24,10 +24,25 @@ public record CompilationInfo(Path inputFile, Path outputFile, String outputClas String controllerClass, Set injectedFields, Set injectedMethods, Map includes, boolean requiresResourceBundle) { + /** + * Instantiates a new info + * + * @param inputFile The input file + * @param outputFile The output file + * @param outputClass The output class name + * @param controllerFile The controller file + * @param controllerClass The controller class name + * @param injectedFields The injected fields + * @param injectedMethods The injected methods + * @param includes The FXML inclusions + * @param requiresResourceBundle True if the file requires a resource bundle + * @throws NullPointerException if any parameter is null + */ public CompilationInfo { Objects.requireNonNull(inputFile); Objects.requireNonNull(outputFile); Objects.requireNonNull(outputClass); + Objects.requireNonNull(controllerClass); Objects.requireNonNull(controllerFile); injectedFields = Set.copyOf(injectedFields); injectedMethods = Set.copyOf(injectedMethods); diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfoProvider.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfoProvider.java index 745a7a2..41e555e 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfoProvider.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/CompilationInfoProvider.java @@ -15,10 +15,11 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Map; import java.util.regex.Pattern; +import static java.util.Objects.requireNonNull; + /** * Helper class for {@link FXMLCompilerMojo} to provides {@link CompilationInfo} */ @@ -28,22 +29,31 @@ public final class CompilationInfoProvider { private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); private static final Pattern START_DOT_PATTERN = Pattern.compile("^\\."); - private CompilationInfoProvider() { + private final MavenProject project; + private final Path outputDirectory; + + /** + * Instantiates the provider + * + * @param project The Maven project + * @param outputDirectory The output directory + * @throws NullPointerException If any parameter is null + */ + public CompilationInfoProvider(final MavenProject project, final Path outputDirectory) { + this.project = requireNonNull(project); + this.outputDirectory = requireNonNull(outputDirectory); } /** * Gets the compilation info for the given input * - * @param root The root path + * @param root The root path for the input * @param inputPath The input path * @param controllerMapping The controller mapping - * @param outputDirectory The output directory - * @param project The Maven project * @return The compilation info * @throws MojoExecutionException If an error occurs */ - public static CompilationInfo getCompilationInfo(final Path root, final Path inputPath, final Map controllerMapping, - final Path outputDirectory, final MavenProject project) throws MojoExecutionException { + public CompilationInfo getCompilationInfo(final Path root, final Path inputPath, final Map controllerMapping) throws MojoExecutionException { logger.info("Parsing {}", inputPath); try { final var documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder(); @@ -55,7 +65,7 @@ public final class CompilationInfoProvider { final var outputFilename = getOutputFilename(inputFilename); final var outputClass = getOutputClass(root, inputPath, outputFilename); final var replacedPrefixPath = inputPath.toString().replace(root.toString(), outputDirectory.toString()); - final var targetPath = Paths.get(replacedPrefixPath.replace(inputFilename, outputFilename)); + final var targetPath = Path.of(replacedPrefixPath.replace(inputFilename, outputFilename)); builder.outputFile(targetPath); builder.outputClass(outputClass); handleNode(document.getDocumentElement(), builder, controllerMapping, project); @@ -170,7 +180,7 @@ public final class CompilationInfoProvider { private static void handleController(final String controllerClass, final CompilationInfo.Builder builder, final MavenProject project) throws MojoExecutionException { final var subPath = controllerClass.replace(".", "/") + ".java"; final var path = project.getCompileSourceRoots().stream() - .map(s -> Paths.get(s).resolve(subPath)) + .map(s -> Path.of(s).resolve(subPath)) .filter(Files::exists) .findFirst() .orElseThrow(() -> new MojoExecutionException("Cannot find controller " + controllerClass)); @@ -178,4 +188,20 @@ public final class CompilationInfoProvider { builder.controllerFile(path); builder.controllerClass(controllerClass); } + + /** + * Factory for {@link CompilationInfoProvider} + */ + @FunctionalInterface + public interface Factory { + + /** + * Creates a new compilation info provider + * + * @param project The Maven project + * @param outputDirectory The output directory + * @return The compilation info provider + */ + CompilationInfoProvider create(final MavenProject project, final Path outputDirectory); + } } diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/Compiler.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/Compiler.java index e30c9ce..23028a2 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/Compiler.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/Compiler.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; +import java.util.Objects; /** * Creates compiled Java code @@ -24,10 +25,26 @@ public final class Compiler { private static final Logger logger = LogManager.getLogger(Compiler.class); - private static final FXMLParser PARSER = new DOMFXMLParser(); - private static final Generator GENERATOR = new GeneratorImpl(); + private final FXMLParser parser; + private final Generator generator; - private Compiler() { + /** + * Instantiates a new compiler + * + * @param parser The parser to use + * @param generator The generator to use + * @throws NullPointerException If any parameter is null + */ + Compiler(final FXMLParser parser, final Generator generator) { + this.parser = Objects.requireNonNull(parser); + this.generator = Objects.requireNonNull(generator); + } + + /** + * Instantiates a new compiler + */ + public Compiler() { + this(new DOMFXMLParser(), new GeneratorImpl()); } /** @@ -37,22 +54,31 @@ public final class Compiler { * @param parameters The generation parameters * @throws MojoExecutionException If an error occurs */ - public static void compile(final Map mapping, final GenerationParameters parameters) throws MojoExecutionException { + public void compile(final Map mapping, final GenerationParameters parameters) throws MojoExecutionException { for (final var entry : mapping.entrySet()) { compile(entry.getKey(), entry.getValue(), mapping, parameters); } } - public static void compile(final Path inputPath, final CompilationInfo info, final Map mapping, final GenerationParameters parameters) throws MojoExecutionException { + /** + * Compiles the given file + * + * @param inputPath The input path + * @param info The compilation info + * @param mapping The mapping of file to compile to compilation info + * @param parameters The generation parameters + * @throws MojoExecutionException If an error occurs + */ + public void compile(final Path inputPath, final CompilationInfo info, final Map mapping, final GenerationParameters parameters) throws MojoExecutionException { try { - logger.info("Parsing {} with {}", inputPath, PARSER.getClass().getSimpleName()); - final var root = PARSER.parse(inputPath); + logger.info("Parsing {} with {}", inputPath, parser.getClass().getSimpleName()); + final var root = parser.parse(inputPath); final var controllerInfo = ControllerInfoProvider.getControllerInfo(info); final var output = info.outputFile(); final var sourceInfo = SourceInfoProvider.getSourceInfo(info, mapping); final var request = new GenerationRequestImpl(parameters, controllerInfo, sourceInfo, root, info.outputClass()); logger.info("Compiling {}", inputPath); - final var content = GENERATOR.generate(request); + final var content = generator.generate(request); final var outputDir = output.getParent(); Files.createDirectories(outputDir); Files.writeString(output, content); diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/ControllerProvider.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/ControllerProvider.java index d0358c0..6da38aa 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/ControllerProvider.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/ControllerProvider.java @@ -13,19 +13,21 @@ import java.nio.file.Path; * Extracts controller class from FXMLs */ public final class ControllerProvider { - private static final DocumentBuilder DOCUMENT_BUILDER; - static { + private final DocumentBuilder documentBuilder; + + /** + * Instantiates a new provider + */ + public ControllerProvider() { + final var factory = DocumentBuilderFactory.newInstance(); try { - DOCUMENT_BUILDER = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + this.documentBuilder = factory.newDocumentBuilder(); } catch (final ParserConfigurationException e) { throw new RuntimeException(e); } } - private ControllerProvider() { - } - /** * Gets the controller class for the given FXML * @@ -33,9 +35,9 @@ public final class ControllerProvider { * @return The controller class * @throws MojoExecutionException If an error occurs */ - public static String getController(final Path fxml) throws MojoExecutionException { + public String getController(final Path fxml) throws MojoExecutionException { try { - final var document = DOCUMENT_BUILDER.parse(fxml.toFile()); + final var document = documentBuilder.parse(fxml.toFile()); document.getDocumentElement().normalize(); final var controller = document.getDocumentElement().getAttribute("fx:controller"); diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/FXMLProvider.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/FXMLProvider.java index 8509150..d6cd373 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/FXMLProvider.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/FXMLProvider.java @@ -9,9 +9,9 @@ import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * Extracts FXML paths from Maven project @@ -19,20 +19,28 @@ import java.util.Map; public final class FXMLProvider { private static final Logger logger = LogManager.getLogger(FXMLProvider.class); - private FXMLProvider() { + private final MavenProject project; + + /** + * Instantiates a new provider + * + * @param project The Maven project + * @throws NullPointerException If the project is null + */ + public FXMLProvider(final MavenProject project) { + this.project = Objects.requireNonNull(project); } /** * Returns all the FXML files in the project's resources * - * @param project The Maven project * @return A mapping of file to resource directory * @throws MojoExecutionException If an error occurs */ - public static Map getFXMLs(final MavenProject project) throws MojoExecutionException { + public Map getFXMLs() throws MojoExecutionException { final var map = new HashMap(); for (final var resource : project.getResources()) { - final var path = Paths.get(resource.getDirectory()); + final var path = Path.of(resource.getDirectory()); if (Files.isDirectory(path)) { try (final var stream = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.toString().endsWith(".fxml"), FileVisitOption.FOLLOW_LINKS)) { final var curList = stream.toList(); @@ -49,4 +57,18 @@ public final class FXMLProvider { } return map; } + + /** + * Factory for {@link FXMLProvider} + */ + @FunctionalInterface + public interface Factory { + /** + * Creates a new provider + * + * @param project The Maven project + * @return The provider + */ + FXMLProvider create(final MavenProject project); + } } diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/GenericParser.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/GenericParser.java index 1ec1f1c..79c881d 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/GenericParser.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/GenericParser.java @@ -38,10 +38,17 @@ final class GenericParser { } List parse() throws MojoExecutionException { - return parseGenericTypes(); + final var parsed = parseGenericTypes(); + if (index < content.length()) { + throw new MojoExecutionException("Expected EOF at " + index + " in " + content); + } + return parsed; } private List parseGenericTypes() throws MojoExecutionException { + if (content.isEmpty()) { + throw new MojoExecutionException("Empty generic types"); + } final var ret = new ArrayList(); eatSpaces(); eat('<'); @@ -52,12 +59,16 @@ final class GenericParser { if (peek() == '<') { final var genericTypes = parseGenericTypes(); ret.add(new GenericTypesImpl(type, genericTypes)); + } else { + ret.add(new GenericTypesImpl(type, List.of())); + } + eatSpaces(); + if (peek() == ',') { + eat(','); } else if (peek() == '>') { eat('>'); + eatSpaces(); return ret; - } else if (peek() == ',') { - eat(','); - ret.add(new GenericTypesImpl(type, List.of())); } } while (index < content.length()); return ret; @@ -72,17 +83,17 @@ final class GenericParser { } private void eatSpaces() { - while (peek() == ' ') { + while (index < content.length() && peek() == ' ') { read(); } } private String parseType() throws MojoExecutionException { final var sb = new StringBuilder(); - while (peek() != '<' && index < content.length()) { + while (peek() != '<' && peek() != '>' && peek() != ',' && index < content.length()) { sb.append(read()); } - final var type = sb.toString(); + final var type = sb.toString().trim(); if (type.contains(".") || JAVA_LANG_CLASSES.contains(type)) { return type; } else if (imports.containsKey(type)) { diff --git a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/SourceInfoProvider.java b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/SourceInfoProvider.java index 766a059..d39d9e8 100644 --- a/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/SourceInfoProvider.java +++ b/maven-plugin/src/main/java/com/github/gtache/fxml/compiler/maven/internal/SourceInfoProvider.java @@ -32,7 +32,7 @@ final class SourceInfoProvider { final var requiresResourceBundle = info.requiresResourceBundle(); final var includesMapping = new HashMap(); includes.forEach((k, v) -> includesMapping.put(k, getSourceInfo(mapping.get(v), mapping))); - //FIXME mutliple includes + //FIXME mutliple same includes return new SourceInfoImpl(outputClass, controllerClass, inputFile, List.copyOf(includesMapping.values()), includesMapping, requiresResourceBundle); } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/TestFXMLCompilerMojo.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/TestFXMLCompilerMojo.java index aefe4df..9573616 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/TestFXMLCompilerMojo.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/TestFXMLCompilerMojo.java @@ -1,8 +1,209 @@ package com.github.gtache.fxml.compiler.maven; +import com.github.gtache.fxml.compiler.ControllerFieldInjectionType; +import com.github.gtache.fxml.compiler.ControllerInjectionType; +import com.github.gtache.fxml.compiler.ControllerMethodsInjectionType; +import com.github.gtache.fxml.compiler.ResourceBundleInjectionType; +import com.github.gtache.fxml.compiler.compatibility.impl.GenerationCompatibilityImpl; +import com.github.gtache.fxml.compiler.impl.GenerationParametersImpl; +import com.github.gtache.fxml.compiler.maven.internal.CompilationInfo; +import com.github.gtache.fxml.compiler.maven.internal.CompilationInfoProvider; +import com.github.gtache.fxml.compiler.maven.internal.Compiler; +import com.github.gtache.fxml.compiler.maven.internal.ControllerProvider; +import com.github.gtache.fxml.compiler.maven.internal.FXMLProvider; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; + @ExtendWith(MockitoExtension.class) class TestFXMLCompilerMojo { + + private final Compiler compiler; + private final CompilationInfoProvider compilationInfoProvider; + private final ControllerProvider controllerProvider; + private final FXMLProvider fxmlProvider; + private final MavenProject mavenProject; + private final Path outputDirectory; + private final int targetVersion; + private final boolean useImageInputStreamConstructor; + private final ControllerInjectionType controllerInjectionType; + private final ControllerFieldInjectionType controllerFieldInjectionType; + private final ControllerMethodsInjectionType controllerMethodsInjectionType; + private final ResourceBundleInjectionType resourceBundleInjectionType; + private final Map resourceMap; + private final Map fxmls; + private final CompilationInfo compilationInfo; + private final FXMLCompilerMojo mojo; + + TestFXMLCompilerMojo(@Mock final Compiler compiler, @Mock final CompilationInfoProvider compilationInfoProvider, + @Mock final ControllerProvider controllerProvider, @Mock final FXMLProvider fxmlProvider, + @Mock final MavenProject mavenProject, + @Mock final ControllerInjectionType controllerInjectionType, + @Mock final ControllerFieldInjectionType controllerFieldInjectionType, + @Mock final ControllerMethodsInjectionType controllerMethodsInjectionType, + @Mock final ResourceBundleInjectionType resourceBundleInjectionType, + @Mock final CompilationInfo compilationInfo) { + this.compiler = Objects.requireNonNull(compiler); + this.compilationInfoProvider = Objects.requireNonNull(compilationInfoProvider); + this.controllerProvider = Objects.requireNonNull(controllerProvider); + this.fxmlProvider = Objects.requireNonNull(fxmlProvider); + this.mavenProject = Objects.requireNonNull(mavenProject); + this.outputDirectory = Path.of("output"); + this.targetVersion = 11; + this.useImageInputStreamConstructor = true; + this.controllerInjectionType = Objects.requireNonNull(controllerInjectionType); + this.controllerFieldInjectionType = Objects.requireNonNull(controllerFieldInjectionType); + this.controllerMethodsInjectionType = Objects.requireNonNull(controllerMethodsInjectionType); + this.resourceBundleInjectionType = Objects.requireNonNull(resourceBundleInjectionType); + this.resourceMap = Map.of("a", "b", "c", "d"); + this.compilationInfo = Objects.requireNonNull(compilationInfo); + this.fxmls = new HashMap<>(); + this.mojo = new FXMLCompilerMojo(compiler, (p, o) -> compilationInfoProvider, controllerProvider, + p -> fxmlProvider); + } + + @BeforeEach + void beforeEach() throws Exception { + setValue("project", mavenProject); + setValue("outputDirectory", outputDirectory); + setIntValue("targetVersion", targetVersion); + setBooleanValue("useImageInputStreamConstructor", useImageInputStreamConstructor); + setValue("controllerInjectionType", controllerInjectionType); + setValue("fieldInjectionType", controllerFieldInjectionType); + setValue("methodInjectionType", controllerMethodsInjectionType); + setValue("resourceInjectionType", resourceBundleInjectionType); + setValue("resourceMap", resourceMap); + when(fxmlProvider.getFXMLs()).thenReturn(fxmls); + when(controllerProvider.getController(any())).then(i -> ((Path) i.getArgument(0)).toString()); + when(compilationInfoProvider.getCompilationInfo(any(), any(), anyMap())).thenReturn(compilationInfo); + fxmls.put(Path.of("a"), Path.of("b")); + fxmls.put(Path.of("c"), Path.of("d")); + } + + @Test + void testExecuteParallel() throws Exception { + final var pathA = Path.of("a"); + final var pathC = Path.of("c"); + setIntValue("parallelism", 4); + mojo.execute(); + for (final var p : fxmls.keySet()) { + verify(controllerProvider).getController(p); + } + final var controllerMapping = Map.of(pathA, "a", pathC, "c"); + for (final var e : fxmls.entrySet()) { + verify(compilationInfoProvider).getCompilationInfo(e.getValue(), e.getKey(), controllerMapping); + } + final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion), useImageInputStreamConstructor, resourceMap, + controllerInjectionType, controllerFieldInjectionType, controllerMethodsInjectionType, resourceBundleInjectionType); + final var compilationInfoMapping = Map.of(pathA, compilationInfo, pathC, compilationInfo); + for (final var entry : compilationInfoMapping.entrySet()) { + verify(compiler).compile(entry.getKey(), entry.getValue(), compilationInfoMapping, parameters); + } + } + + @Test + void testExecuteDefaultCores() throws Exception { + final var pathA = Path.of("a"); + final var pathC = Path.of("c"); + setIntValue("parallelism", 0); + mojo.execute(); + assertEquals(Runtime.getRuntime().availableProcessors(), getValue("parallelism")); + for (final var p : fxmls.keySet()) { + verify(controllerProvider).getController(p); + } + final var controllerMapping = Map.of(pathA, "a", pathC, "c"); + for (final var e : fxmls.entrySet()) { + verify(compilationInfoProvider).getCompilationInfo(e.getValue(), e.getKey(), controllerMapping); + } + final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion), useImageInputStreamConstructor, resourceMap, + controllerInjectionType, controllerFieldInjectionType, controllerMethodsInjectionType, resourceBundleInjectionType); + final var compilationInfoMapping = Map.of(pathA, compilationInfo, pathC, compilationInfo); + for (final var entry : compilationInfoMapping.entrySet()) { + verify(compiler).compile(entry.getKey(), entry.getValue(), compilationInfoMapping, parameters); + } + } + + @Test + void testControllerProviderException() throws Exception { + setIntValue("parallelism", 4); + doThrow(MojoExecutionException.class).when(controllerProvider).getController(any()); + assertThrows(MojoExecutionException.class, mojo::execute); + } + + @Test + void testCompilationInfoProviderException() throws Exception { + setIntValue("parallelism", 4); + doThrow(MojoExecutionException.class).when(compilationInfoProvider).getCompilationInfo(any(), any(), anyMap()); + assertThrows(MojoExecutionException.class, mojo::execute); + } + + @Test + void testCompilerException() throws Exception { + setIntValue("parallelism", 4); + doThrow(MojoExecutionException.class).when(compiler).compile(any(), any(), anyMap(), any()); + assertThrows(MojoExecutionException.class, mojo::execute); + } + + @Test + void testExecuteSingleCore() throws Exception { + final var pathA = Path.of("a"); + final var pathC = Path.of("c"); + setIntValue("parallelism", 1); + mojo.execute(); + for (final var p : fxmls.keySet()) { + verify(controllerProvider).getController(p); + } + final var controllerMapping = Map.of(pathA, "a", pathC, "c"); + for (final var e : fxmls.entrySet()) { + verify(compilationInfoProvider).getCompilationInfo(e.getValue(), e.getKey(), controllerMapping); + } + final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion), useImageInputStreamConstructor, resourceMap, + controllerInjectionType, controllerFieldInjectionType, controllerMethodsInjectionType, resourceBundleInjectionType); + final var compilationInfoMapping = Map.of(pathA, compilationInfo, pathC, compilationInfo); + verify(compiler).compile(compilationInfoMapping, parameters); + } + + @Test + void testOverrideControllerInjectionType() throws Exception { + setValue("fieldInjectionType", ControllerFieldInjectionType.FACTORY); + mojo.execute(); + assertEquals(ControllerInjectionType.FACTORY, getValue("controllerInjectionType")); + } + + private Object getValue(final String name) throws Exception { + final var field = FXMLCompilerMojo.class.getDeclaredField(name); + field.setAccessible(true); + return field.get(mojo); + } + + private void setBooleanValue(final String name, final boolean value) throws Exception { + final var field = FXMLCompilerMojo.class.getDeclaredField(name); + field.setAccessible(true); + field.setBoolean(mojo, value); + } + + private void setIntValue(final String name, final int value) throws Exception { + final var field = FXMLCompilerMojo.class.getDeclaredField(name); + field.setAccessible(true); + field.setInt(mojo, value); + } + + private void setValue(final String name, final Object value) throws Exception { + final var field = FXMLCompilerMojo.class.getDeclaredField(name); + field.setAccessible(true); + field.set(mojo, value); + } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoBuilder.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoBuilder.java index e2436e9..a775974 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoBuilder.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoBuilder.java @@ -6,8 +6,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.nio.file.Path; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -24,7 +22,6 @@ class TestCompilationInfoBuilder { private final Set injectedFields; private final Set injectedMethods; private final Map includes; - private final boolean requiresResourceBundle; private final CompilationInfo info; TestCompilationInfoBuilder(@Mock final Path inputFile, @Mock final Path outputFile, @Mock final Path controllerFile, @Mock final FieldInfo fieldInfo) { @@ -33,11 +30,10 @@ class TestCompilationInfoBuilder { this.outputClass = "outputClass"; this.controllerFile = Objects.requireNonNull(controllerFile); this.controllerClass = "controllerClass"; - this.injectedFields = new HashSet<>(Set.of(fieldInfo)); - this.injectedMethods = new HashSet<>(Set.of("one", "two")); - this.includes = new HashMap<>(Map.of("one", Objects.requireNonNull(inputFile))); - this.requiresResourceBundle = true; - this.info = new CompilationInfo(inputFile, outputFile, outputClass, controllerFile, controllerClass, injectedFields, injectedMethods, includes, requiresResourceBundle); + this.injectedFields = Set.of(new FieldInfo("type", "name")); + this.injectedMethods = Set.of("one", "two"); + this.includes = Map.of("one", Objects.requireNonNull(inputFile)); + this.info = new CompilationInfo(inputFile, outputFile, outputClass, controllerFile, controllerClass, injectedFields, injectedMethods, includes, true); } @Test diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoProvider.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoProvider.java index 790e882..26bdee2 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoProvider.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompilationInfoProvider.java @@ -1,8 +1,143 @@ package com.github.gtache.fxml.compiler.maven.internal; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + @ExtendWith(MockitoExtension.class) class TestCompilationInfoProvider { + + private final MavenProject project; + + TestCompilationInfoProvider(@Mock final MavenProject project) { + this.project = Objects.requireNonNull(project); + } + + @Test + void testCompleteExample(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("infoView.fxml", tempDir); + final var includedPath = path.getParent().resolve("includeView.fxml"); + final var controllerPath = path.getParent().resolve("InfoController.java"); + final var controllerClass = "com.github.gtache.fxml.compiler.maven.internal.InfoController"; + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var expected = new CompilationInfo(path, path.getParent().resolve("InfoView.java"), + "com.github.gtache.fxml.compiler.maven.internal.InfoView", controllerPath, controllerClass, + Set.of(new FieldInfo("javafx.event.EventHandler", "onContextMenuRequested"), new FieldInfo("Button", "button"), + new FieldInfo("com.github.gtache.fxml.compiler.maven.internal.IncludeController", "includeViewController")), + Set.of("onAction"), Map.of("includeView.fxml", path.getParent().resolve("includeView.fxml")), true); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + final var actual = compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of(includedPath, "com.github.gtache.fxml.compiler.maven.internal.IncludeController")); + assertEquals(expected, actual); + } + + @Test + void testComplexFilename(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("com_plex-view.fxml", tempDir); + final var controllerPath = path.getParent().resolve("InfoController.java"); + final var controllerClass = "com.github.gtache.fxml.compiler.maven.internal.InfoController"; + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var expected = new CompilationInfo(path, path.getParent().resolve("ComPlexView.java"), + "com.github.gtache.fxml.compiler.maven.internal.ComPlexView", controllerPath, controllerClass, + Set.of(), Set.of(), Map.of(), false); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + final var actual = compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of()); + assertEquals(expected, actual); + } + + @Test + void testNoController(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("noController.fxml", tempDir); + final var controllerPath = path.getParent().resolve("InfoController.java"); + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + assertThrows(MojoExecutionException.class, () -> compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of())); + } + + @Test + void testIncludeNoSource(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("missingSource.fxml", tempDir); + final var includedPath = path.getParent().resolve("includeView.fxml"); + final var controllerPath = path.getParent().resolve("InfoController.java"); + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + assertThrows(MojoExecutionException.class, () -> compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of(includedPath, "com.github.gtache.fxml.compiler.maven.internal.IncludeController"))); + } + + @Test + void testCantFindControllerFile(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("infoView.fxml", tempDir); + final var includedPath = path.getParent().resolve("includeView.fxml"); + final var controllerPath = path.getParent().resolve("InfoController.java"); + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of()); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + assertThrows(MojoExecutionException.class, () -> compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of(includedPath, "com.github.gtache.fxml.compiler.maven.internal.IncludeController"))); + } + + @Test + void testCantFindIncludedControllerClass(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("infoView.fxml", tempDir); + final var controllerPath = path.getParent().resolve("InfoController.java"); + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + assertThrows(MojoExecutionException.class, () -> compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of())); + } + + @Test + void testNoResourceBundle(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("noResourceBundle.fxml", tempDir); + final var includedPath = path.getParent().resolve("includeView.fxml"); + final var controllerPath = path.getParent().resolve("InfoController.java"); + final var controllerClass = "com.github.gtache.fxml.compiler.maven.internal.InfoController"; + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var expected = new CompilationInfo(path, path.getParent().resolve("NoResourceBundle.java"), + "com.github.gtache.fxml.compiler.maven.internal.NoResourceBundle", controllerPath, controllerClass, + Set.of(new FieldInfo("javafx.event.EventHandler", "onContextMenuRequested"), new FieldInfo("Button", "button"), + new FieldInfo("com.github.gtache.fxml.compiler.maven.internal.IncludeController", "includeViewController")), + Set.of("onAction"), Map.of("includeView.fxml", path.getParent().resolve("includeView.fxml")), false); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + final var actual = compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of(includedPath, "com.github.gtache.fxml.compiler.maven.internal.IncludeController")); + assertEquals(expected, actual); + } + + @Test + void testUnknownOn(@TempDir final Path tempDir) throws Exception { + final var path = copyFile("unknownOn.fxml", tempDir); + final var controllerPath = path.getParent().resolve("InfoController.java"); + Files.createFile(controllerPath); + when(project.getCompileSourceRoots()).thenReturn(List.of(tempDir.toString())); + final var compilationInfoProvider = new CompilationInfoProvider(project, tempDir); + assertThrows(MojoExecutionException.class, () -> compilationInfoProvider.getCompilationInfo(tempDir, path, Map.of())); + } + + private Path copyFile(final String source, final Path tempDir) throws IOException { + final var out = tempDir.resolve("com").resolve("github").resolve("gtache").resolve("fxml").resolve("compiler").resolve("maven").resolve("internal").resolve(source); + Files.createDirectories(out.getParent()); + try (final var in = getClass().getResourceAsStream(source)) { + assertNotNull(in); + Files.copy(in, out); + } + return out; + } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompiler.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompiler.java index e8ef95f..2e9ba94 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompiler.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestCompiler.java @@ -1,16 +1,15 @@ package com.github.gtache.fxml.compiler.maven.internal; -import com.github.gtache.fxml.compiler.ControllerInfo; import com.github.gtache.fxml.compiler.GenerationException; import com.github.gtache.fxml.compiler.GenerationParameters; import com.github.gtache.fxml.compiler.Generator; -import com.github.gtache.fxml.compiler.SourceInfo; import com.github.gtache.fxml.compiler.impl.GenerationRequestImpl; import com.github.gtache.fxml.compiler.parsing.FXMLParser; import com.github.gtache.fxml.compiler.parsing.ParseException; import com.github.gtache.fxml.compiler.parsing.ParsedObject; import org.apache.maven.plugin.MojoExecutionException; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; @@ -19,7 +18,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Map; import java.util.Objects; @@ -30,88 +28,88 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class TestCompiler { - private final ControllerInfoProvider controllerInfoProvider; - private final SourceInfoProvider sourceInfoProvider; private final FXMLParser fxmlParser; private final Generator generator; private final CompilationInfo compilationInfo; private final ParsedObject object; - private final ControllerInfo controllerInfo; - private final SourceInfo sourceInfo; private final String content; private final GenerationParameters parameters; + private final Compiler compiler; - TestCompiler(@Mock final ControllerInfoProvider controllerInfoProvider, @Mock final SourceInfoProvider sourceInfoProvider, - @Mock final FXMLParser fxmlParser, @Mock final CompilationInfo compilationInfo, @Mock final ParsedObject object, - @Mock final ControllerInfo controllerInfo, @Mock final SourceInfo sourceInfo, + TestCompiler(@Mock final FXMLParser fxmlParser, @Mock final CompilationInfo compilationInfo, @Mock final ParsedObject object, @Mock final GenerationParameters parameters, @Mock final Generator generator) { - this.controllerInfoProvider = Objects.requireNonNull(controllerInfoProvider); - this.sourceInfoProvider = Objects.requireNonNull(sourceInfoProvider); this.fxmlParser = Objects.requireNonNull(fxmlParser); this.compilationInfo = Objects.requireNonNull(compilationInfo); this.object = Objects.requireNonNull(object); - this.controllerInfo = Objects.requireNonNull(controllerInfo); - this.sourceInfo = Objects.requireNonNull(sourceInfo); this.content = "content"; this.parameters = Objects.requireNonNull(parameters); this.generator = Objects.requireNonNull(generator); + this.compiler = new Compiler(fxmlParser, generator); } @BeforeEach - void beforeEach() throws MojoExecutionException, GenerationException, ParseException { + void beforeEach() throws GenerationException, ParseException { when(fxmlParser.parse((Path) any())).thenReturn(object); - when(ControllerInfoProvider.getControllerInfo(compilationInfo)).thenReturn(controllerInfo); - when(SourceInfoProvider.getSourceInfo(eq(compilationInfo), anyMap())).thenReturn(sourceInfo); when(generator.generate(any())).thenReturn(content); + when(compilationInfo.outputClass()).thenReturn("outputClass"); + when(compilationInfo.controllerClass()).thenReturn("controllerClass"); + when(compilationInfo.includes()).thenReturn(Map.of()); } @Test void testCompile(@TempDir final Path tempDir) throws Exception { final var path = tempDir.resolve("fxml1.fxml"); + Files.createFile(path); final var outputPath = tempDir.resolve("subFolder").resolve("fxml1.java"); final var outputClass = "outputClass"; when(compilationInfo.outputFile()).thenReturn(outputPath); - when(compilationInfo.outputClass()).thenReturn(outputClass); + when(compilationInfo.inputFile()).thenReturn(path); + when(compilationInfo.controllerFile()).thenReturn(path); + final var controllerInfo = ControllerInfoProvider.getControllerInfo(compilationInfo); + final var sourceInfo = SourceInfoProvider.getSourceInfo(compilationInfo, Map.of()); final var mapping = Map.of(path, compilationInfo); final var request = new GenerationRequestImpl(parameters, controllerInfo, sourceInfo, object, outputClass); - Compiler.compile(mapping, parameters); + compiler.compile(mapping, parameters); verify(fxmlParser).parse(path); - ControllerInfoProvider.getControllerInfo(compilationInfo); - SourceInfoProvider.getSourceInfo(compilationInfo, mapping); verify(generator).generate(request); assertEquals(content, Files.readString(outputPath)); } @Test + @Disabled("Need cross-platform unwritable path") void testCompileIOException(@TempDir final Path tempDir) throws Exception { final var path = tempDir.resolve("fxml1.fxml"); - final var outputPath = Paths.get("/whatever"); + Files.createFile(path); + final var outputPath = Path.of("/in/a/b/c/whatever"); final var outputClass = "outputClass"; when(compilationInfo.outputFile()).thenReturn(outputPath); - when(compilationInfo.outputClass()).thenReturn(outputClass); + when(compilationInfo.inputFile()).thenReturn(path); + when(compilationInfo.controllerFile()).thenReturn(path); final var mapping = Map.of(path, compilationInfo); + final var controllerInfo = ControllerInfoProvider.getControllerInfo(compilationInfo); + final var sourceInfo = SourceInfoProvider.getSourceInfo(compilationInfo, Map.of()); final var request = new GenerationRequestImpl(parameters, controllerInfo, sourceInfo, object, outputClass); - assertThrows(MojoExecutionException.class, () -> Compiler.compile(mapping, parameters)); + assertThrows(MojoExecutionException.class, () -> compiler.compile(mapping, parameters)); verify(fxmlParser).parse(path); - ControllerInfoProvider.getControllerInfo(compilationInfo); - SourceInfoProvider.getSourceInfo(compilationInfo, mapping); verify(generator).generate(request); } @Test void testCompileRuntimeException(@TempDir final Path tempDir) throws Exception { final var path = tempDir.resolve("fxml1.fxml"); + Files.createFile(path); final var outputPath = tempDir.resolve("subFolder").resolve("fxml1.java"); final var outputClass = "outputClass"; when(compilationInfo.outputFile()).thenReturn(outputPath); - when(compilationInfo.outputClass()).thenReturn(outputClass); + when(compilationInfo.inputFile()).thenReturn(path); + when(compilationInfo.controllerFile()).thenReturn(path); final var mapping = Map.of(path, compilationInfo); + final var controllerInfo = ControllerInfoProvider.getControllerInfo(compilationInfo); + final var sourceInfo = SourceInfoProvider.getSourceInfo(compilationInfo, Map.of()); final var request = new GenerationRequestImpl(parameters, controllerInfo, sourceInfo, object, outputClass); when(generator.generate(request)).thenThrow(RuntimeException.class); - assertThrows(MojoExecutionException.class, () -> Compiler.compile(mapping, parameters)); + assertThrows(MojoExecutionException.class, () -> compiler.compile(mapping, parameters)); verify(fxmlParser).parse(path); - ControllerInfoProvider.getControllerInfo(compilationInfo); - SourceInfoProvider.getSourceInfo(compilationInfo, mapping); verify(generator).generate(request); } @@ -120,25 +118,27 @@ class TestCompiler { when(fxmlParser.parse((Path) any())).thenThrow(ParseException.class); final var path = tempDir.resolve("fxml1.fxml"); final var mapping = Map.of(path, compilationInfo); - assertThrows(MojoExecutionException.class, () -> Compiler.compile(mapping, parameters)); + assertThrows(MojoExecutionException.class, () -> compiler.compile(mapping, parameters)); verify(fxmlParser).parse(path); - verifyNoInteractions(controllerInfoProvider, sourceInfoProvider, generator); + verifyNoInteractions(generator); } @Test void testCompileGenerationException(@TempDir final Path tempDir) throws Exception { final var path = tempDir.resolve("fxml1.fxml"); + Files.createFile(path); final var outputPath = tempDir.resolve("subFolder").resolve("fxml1.java"); final var outputClass = "outputClass"; when(compilationInfo.outputFile()).thenReturn(outputPath); - when(compilationInfo.outputClass()).thenReturn(outputClass); + when(compilationInfo.inputFile()).thenReturn(path); + when(compilationInfo.controllerFile()).thenReturn(path); final var mapping = Map.of(path, compilationInfo); + final var controllerInfo = ControllerInfoProvider.getControllerInfo(compilationInfo); + final var sourceInfo = SourceInfoProvider.getSourceInfo(compilationInfo, Map.of()); final var request = new GenerationRequestImpl(parameters, controllerInfo, sourceInfo, object, outputClass); when(generator.generate(request)).thenThrow(GenerationException.class); - assertThrows(MojoExecutionException.class, () -> Compiler.compile(mapping, parameters)); + assertThrows(MojoExecutionException.class, () -> compiler.compile(mapping, parameters)); verify(fxmlParser).parse(path); - ControllerInfoProvider.getControllerInfo(compilationInfo); - SourceInfoProvider.getSourceInfo(compilationInfo, mapping); verify(generator).generate(request); } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerInfoProvider.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerInfoProvider.java index 750952d..344174e 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerInfoProvider.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerInfoProvider.java @@ -2,6 +2,7 @@ package com.github.gtache.fxml.compiler.maven.internal; import com.github.gtache.fxml.compiler.impl.ControllerFieldInfoImpl; import com.github.gtache.fxml.compiler.impl.ControllerInfoImpl; +import com.github.gtache.fxml.compiler.impl.GenericTypesImpl; import org.apache.maven.plugin.MojoExecutionException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -11,10 +12,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -24,11 +25,9 @@ import static org.mockito.Mockito.when; class TestControllerInfoProvider { private final CompilationInfo compilationInfo; - private final ControllerInfoProvider controllerInfoProvider; TestControllerInfoProvider(@Mock final CompilationInfo compilationInfo) { this.compilationInfo = Objects.requireNonNull(compilationInfo); - this.controllerInfoProvider = new ControllerInfoProvider(); } @@ -49,6 +48,7 @@ class TestControllerInfoProvider { private Button button; private ComboBox rawBox; private TableColumn> tableColumn; + private ComboBox fullBox; @FXML void initialize() { @@ -64,18 +64,47 @@ class TestControllerInfoProvider { } """); when(compilationInfo.controllerFile()).thenReturn(fxml); - final var expectedInfo = new ControllerInfoImpl("com.github.gtache.fxml.compiler.maven.internal.LoadController", - Map.of("onClick", false, "onOtherClick", true), Map.of("keyEventHandler", new ControllerFieldInfoImpl("keyEventHandler", List.of()), - "comboBox", new ControllerFieldInfoImpl("comboBox", List.of("String")), "button", new ControllerFieldInfoImpl("button", List.of()), - "rawBox", new ControllerFieldInfoImpl("rawBox", List.of()), - "tableColumn", new ControllerFieldInfoImpl("tableColumn", List.of("Integer", "javafx.scene.control.ComboBox"))), true); + final var controllerClass = "com.github.gtache.fxml.compiler.maven.internal.LoadController"; + when(compilationInfo.controllerClass()).thenReturn(controllerClass); + when(compilationInfo.injectedFields()).thenReturn(Set.of(new FieldInfo("EventHandler", "keyEventHandler"), + new FieldInfo("ComboBox", "comboBox"), new FieldInfo("Button", "button"), + new FieldInfo("ComboBox", "rawBox"), new FieldInfo("TableColumn", "tableColumn"), + new FieldInfo("ComboBox", "abc"), new FieldInfo("javafx.scene.control.ComboBox", "fullBox"))); + when(compilationInfo.injectedMethods()).thenReturn(Set.of("onClick", "onOtherClick")); + final var expectedInfo = new ControllerInfoImpl(controllerClass, + Map.of("onClick", false, "onOtherClick", true), Map.of("keyEventHandler", new ControllerFieldInfoImpl("keyEventHandler", List.of(new GenericTypesImpl("javafx.event.KeyEvent", List.of()))), + "comboBox", new ControllerFieldInfoImpl("comboBox", List.of(new GenericTypesImpl("String", List.of()))), "button", new ControllerFieldInfoImpl("button", List.of()), + "rawBox", new ControllerFieldInfoImpl("rawBox", List.of()), "fullBox", new ControllerFieldInfoImpl("fullBox", List.of(new GenericTypesImpl("Integer", List.of()))), + "tableColumn", new ControllerFieldInfoImpl("tableColumn", List.of(new GenericTypesImpl("Integer", List.of()), + new GenericTypesImpl("javafx.scene.control.ComboBox", List.of(new GenericTypesImpl("String", List.of())))))), true); final var actual = ControllerInfoProvider.getControllerInfo(compilationInfo); assertEquals(expectedInfo, actual); } + @Test + void testGetControllerInfoMethodNotFound(@TempDir final Path tempDir) throws Exception { + final var fxml = tempDir.resolve("fxml.fxml"); + Files.writeString(fxml, """ + package com.github.gtache.fxml.compiler.maven.internal; + + import javafx.event.EventHandler; + import javafx.event.KeyEvent; + import javafx.scene.control.*; + + public class LoadController { + + } + """); + when(compilationInfo.controllerFile()).thenReturn(fxml); + when(compilationInfo.controllerClass()).thenReturn("com.github.gtache.fxml.compiler.maven.internal.LoadController"); + when(compilationInfo.injectedFields()).thenReturn(Set.of()); + when(compilationInfo.injectedMethods()).thenReturn(Set.of("onClick")); + assertThrows(MojoExecutionException.class, () -> ControllerInfoProvider.getControllerInfo(compilationInfo)); + } + @Test void testGetControllerInfoException() { - when(compilationInfo.controllerFile()).thenReturn(Paths.get("/whatever")); + when(compilationInfo.controllerFile()).thenReturn(Path.of("/in/a/b/c/whatever")); assertThrows(MojoExecutionException.class, () -> ControllerInfoProvider.getControllerInfo(compilationInfo)); } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerProvider.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerProvider.java index 642a3c9..fcc2db8 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerProvider.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestControllerProvider.java @@ -8,7 +8,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -16,6 +15,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ExtendWith(MockitoExtension.class) class TestControllerProvider { + private final ControllerProvider controllerProvider; + + TestControllerProvider() { + this.controllerProvider = new ControllerProvider(); + } + @Test void testGetController(@TempDir final Path tempDir) throws Exception { final var fxml = tempDir.resolve("fxml.fxml"); @@ -23,7 +28,7 @@ class TestControllerProvider { "" + "\n"); - assertEquals("LoadController", ControllerProvider.getController(fxml)); + assertEquals("LoadController", controllerProvider.getController(fxml)); } @Test @@ -32,11 +37,11 @@ class TestControllerProvider { Files.writeString(fxml, "" + "" + "\n"); - assertThrows(MojoExecutionException.class, () -> ControllerProvider.getController(fxml)); + assertThrows(MojoExecutionException.class, () -> controllerProvider.getController(fxml)); } @Test void testGetControllerError() { - assertThrows(MojoExecutionException.class, () -> ControllerProvider.getController(Paths.get("fxml.fxml"))); + assertThrows(MojoExecutionException.class, () -> controllerProvider.getController(Path.of("fxml.fxml"))); } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestFXMLProvider.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestFXMLProvider.java index 54ca98a..688d9f1 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestFXMLProvider.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestFXMLProvider.java @@ -22,20 +22,24 @@ import static org.mockito.Mockito.when; class TestFXMLProvider { private final MavenProject project; + private final FXMLProvider provider; TestFXMLProvider(@Mock final MavenProject project) { this.project = Objects.requireNonNull(project); + this.provider = new FXMLProvider(project); } @Test void testGetFXMLs(@TempDir final Path tempDir, @TempDir final Path otherTempDir) throws Exception { final var subFolder = tempDir.resolve("subFolder"); + Files.createDirectories(subFolder); Files.createFile(subFolder.resolve("subfxml1.fxml")); Files.createFile(subFolder.resolve("subfxml2.fxml")); Files.createFile(tempDir.resolve("fxml1.fxml")); Files.createFile(tempDir.resolve("fxml2.fxml")); final var otherSubFolder = otherTempDir.resolve("subFolder"); + Files.createDirectories(otherSubFolder); Files.createFile(otherSubFolder.resolve("subfxml1.fxml")); Files.createFile(otherSubFolder.resolve("subfxml2.fxml")); Files.createFile(otherTempDir.resolve("fxml1.fxml")); @@ -57,7 +61,7 @@ class TestFXMLProvider { otherTempDir.resolve("fxml1.fxml"), otherTempDir, otherTempDir.resolve("fxml2.fxml"), otherTempDir ); - final var map = FXMLProvider.getFXMLs(project); + final var map = provider.getFXMLs(); assertEquals(expected, map); } } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestGenericParser.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestGenericParser.java index 253ea19..94469cc 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestGenericParser.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestGenericParser.java @@ -2,15 +2,18 @@ package com.github.gtache.fxml.compiler.maven.internal; import com.github.gtache.fxml.compiler.impl.GenericTypesImpl; import org.apache.maven.plugin.MojoExecutionException; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import java.util.List; import java.util.Map; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class TestGenericParser { @@ -22,12 +25,34 @@ class TestGenericParser { assertEquals(expectedGenericTypes, parsed); } + @Test + void testNotFound() { + final var parser = new GenericParser("", Map.of()); + assertThrows(MojoExecutionException.class, parser::parse); + } + + @ParameterizedTest + @ValueSource(strings = {">", " < String , String < String > > ", + ">", " > "}) + void testWithSpaces(final String genericTypes) throws MojoExecutionException { + final var parser = new GenericParser(genericTypes, Map.of()); + final var expected = List.of(new GenericTypesImpl("String", List.of()), new GenericTypesImpl("String", List.of(new GenericTypesImpl("String", List.of())))); + assertEquals(expected, parser.parse()); + } + + @ParameterizedTest + @ValueSource(strings = {"", ">", "<", ""}) + void testInvalid(final String genericTypes) { + final var parser = new GenericParser(genericTypes, Map.of()); + assertThrows(MojoExecutionException.class, parser::parse); + } + private static Stream providesParseTests() { return Stream.of( Arguments.of(">>", Map.of("Map", "java.util.Map", "String", "java.lang.String", "TableView", "javafx.scene.control.TableView", "Node", "javafx.scene.Node"), List.of(new GenericTypesImpl("java.util.Map", - List.of(new GenericTypesImpl("java.lang.String", List.of()), new GenericTypesImpl("javafx.scene.control.TableView", + List.of(new GenericTypesImpl("String", List.of()), new GenericTypesImpl("javafx.scene.control.TableView", List.of(new GenericTypesImpl("javafx.scene.Node", List.of()), new GenericTypesImpl("javafx.scene.Node", List.of()))))))), Arguments.of(">", Map.of("Map", "java.util.Map"), @@ -39,10 +64,10 @@ class TestGenericParser { Arguments.of(">", Map.of("Collection", "java.util.Collection", "String", "java.lang.String"), List.of(new GenericTypesImpl("java.util.Collection", - List.of(new GenericTypesImpl("java.lang.String", List.of()))))), + List.of(new GenericTypesImpl("String", List.of()))))), Arguments.of(">", - Map.of(), - List.of(new GenericTypesImpl("Collection", + Map.of("Collection", "java.util.Collection"), + List.of(new GenericTypesImpl("java.util.Collection", List.of(new GenericTypesImpl("String", List.of()))))) ); } diff --git a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestSourceInfoProvider.java b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestSourceInfoProvider.java index 2893e2d..7e0915e 100644 --- a/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestSourceInfoProvider.java +++ b/maven-plugin/src/test/java/com/github/gtache/fxml/compiler/maven/internal/TestSourceInfoProvider.java @@ -1,8 +1,49 @@ package com.github.gtache.fxml.compiler.maven.internal; +import com.github.gtache.fxml.compiler.impl.SourceInfoImpl; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + @ExtendWith(MockitoExtension.class) class TestSourceInfoProvider { + + @Test + void testGetSourceInfo(@Mock final CompilationInfo compilationInfo) { + final var outputClass = "outputClass"; + final var controllerClass = "controllerClass"; + final var inputFile = Path.of("inputFile"); + final var includeFile = Path.of("includeFile"); + final var includes = Map.of("one", includeFile); + when(compilationInfo.outputClass()).thenReturn(outputClass); + when(compilationInfo.controllerClass()).thenReturn(controllerClass); + when(compilationInfo.inputFile()).thenReturn(inputFile); + when(compilationInfo.includes()).thenReturn(includes); + when(compilationInfo.requiresResourceBundle()).thenReturn(true); + + final var includeCompilationInfo = mock(CompilationInfo.class); + final var includeOutputClass = "includeOutputClass"; + final var includeControllerClass = "includeControllerClass"; + final var includeInputFile = Path.of("includeInputFile"); + when(includeCompilationInfo.outputClass()).thenReturn(includeOutputClass); + when(includeCompilationInfo.controllerClass()).thenReturn(includeControllerClass); + when(includeCompilationInfo.inputFile()).thenReturn(includeInputFile); + when(includeCompilationInfo.includes()).thenReturn(Map.of()); + final var mapping = Map.of(includeFile, includeCompilationInfo); + + final var expectedIncludeSourceInfo = new SourceInfoImpl(includeOutputClass, includeControllerClass, includeInputFile, List.of(), Map.of(), false); + assertEquals(expectedIncludeSourceInfo, SourceInfoProvider.getSourceInfo(includeCompilationInfo, mapping)); + final var expected = new SourceInfoImpl(outputClass, controllerClass, inputFile, List.of(expectedIncludeSourceInfo), + Map.of("one", expectedIncludeSourceInfo), true); + assertEquals(expected, SourceInfoProvider.getSourceInfo(compilationInfo, mapping)); + } } diff --git a/maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/com_plex-view.fxml b/maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/com_plex-view.fxml new file mode 100644 index 0000000..3d02a9b --- /dev/null +++ b/maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/com_plex-view.fxml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/infoView.fxml b/maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/infoView.fxml new file mode 100644 index 0000000..ffa0cf1 --- /dev/null +++ b/maven-plugin/src/test/resources/com/github/gtache/fxml/compiler/maven/internal/infoView.fxml @@ -0,0 +1,17 @@ + + + + + + + + + +