Finishes testing, cleanup, adds license
This commit is contained in:
9
LICENSE.txt
Normal file
9
LICENSE.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2024 <copyright holders>
|
||||
|
||||
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.
|
||||
37
README.md
37
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.
|
||||
@@ -3,6 +3,7 @@ package com.github.gtache.fxml.compiler;
|
||||
/**
|
||||
* Exception thrown when a generation error occurs
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class GenerationException extends Exception {
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -20,6 +20,7 @@ public record ControllerInfoImpl(String className, Map<String, Boolean> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<GenerationProgress, HelperProvider> helperProviderFactory) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<String, String>", "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<String> controllers) {
|
||||
private static boolean hasDuplicateControllerClass(final SourceInfo info, final Set<? super String> 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<String, String>")).append(bundleFunctionVariable).append(" = (java.util.function.Function<String, String>) 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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Float> 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<Float> 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<Float> 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<Integer> 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<Integer> 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,6 +33,7 @@ class VariableProvider {
|
||||
|
||||
/**
|
||||
* Adds a variable info
|
||||
*
|
||||
* @param id The variable id
|
||||
* @param variableInfo The variable info
|
||||
*/
|
||||
@@ -42,6 +43,7 @@ class VariableProvider {
|
||||
|
||||
/**
|
||||
* Gets the variable info
|
||||
*
|
||||
* @param id The variable id
|
||||
* @return The variable info
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,7 @@ public record ParsedDefineImpl(List<ParsedObject> children) implements ParsedDef
|
||||
|
||||
/**
|
||||
* Instantiates the define
|
||||
*
|
||||
* @param children The children
|
||||
* @throws NullPointerException If the children are null
|
||||
*/
|
||||
|
||||
@@ -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<String, ParsedProperty> attributes) implemen
|
||||
}
|
||||
|
||||
private static Map<String, ParsedProperty> createAttributes(final String source, final String resources, final String fxId) {
|
||||
requireNonNull(source);
|
||||
final var map = HashMap.<String, ParsedProperty>newHashMap(3);
|
||||
map.put(SOURCE, new ParsedPropertyImpl(SOURCE, null, source));
|
||||
if (resources != null) {
|
||||
|
||||
@@ -25,6 +25,7 @@ public record ParsedObjectImpl(String className, Map<String, ParsedProperty> att
|
||||
|
||||
/**
|
||||
* Instantiates a new object
|
||||
*
|
||||
* @param className The object class
|
||||
* @param attributes The object attributes
|
||||
* @param properties The object properties
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Object>[] 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<String, Parameter>();
|
||||
|
||||
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));
|
||||
|
||||
@@ -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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<bla>(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.<String, ParsedProperty>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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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);
|
||||
|
||||
@@ -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.List<String>stylesheets = 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.List<String>stylesheets = variable.getStyleSheets();
|
||||
stylesheets.addAll(listof(1, 2));
|
||||
""";
|
||||
assertEquals(expected, sb.toString());
|
||||
verify(objectFormatter).format(rootObject, "root");
|
||||
}
|
||||
|
||||
@@ -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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class TestWebViewFormatter {
|
||||
@Test
|
||||
void testFormatHasProperty() {
|
||||
final var properties = new LinkedHashMap<ParsedProperty, SequencedCollection<ParsedObject>>();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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.<String, ParsedProperty>of();
|
||||
assertThrows(IllegalArgumentException.class, () -> new ParsedIncludeImpl(emptyMap));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,14 +65,43 @@ 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 {
|
||||
try {
|
||||
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);
|
||||
final var fxmls = fxmlProviderFactory.create(project).getFXMLs();
|
||||
if (parallelism < 1) {
|
||||
parallelism = Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
@@ -83,12 +116,15 @@ public class FXMLCompilerMojo extends AbstractMojo {
|
||||
final var compilationInfoMapping = createCompilationInfoMapping(fxmls, controllerMapping);
|
||||
compile(compilationInfoMapping);
|
||||
}
|
||||
} catch (final RuntimeException e) {
|
||||
throw new MojoExecutionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Path, String> createControllerMapping(final Map<? extends Path, ? extends Path> fxmls) throws MojoExecutionException {
|
||||
private Map<Path, String> createControllerMapping(final Map<? extends Path, ? extends Path> fxmls) throws MojoExecutionException {
|
||||
final var mapping = new HashMap<Path, String>();
|
||||
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<Path, CompilationInfo> createCompilationInfoMapping(final Map<? extends Path, ? extends Path> fxmls,
|
||||
final Map<? extends Path, String> controllerMapping) throws MojoExecutionException {
|
||||
final var mapping = new HashMap<Path, CompilationInfo>();
|
||||
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<Path, CompilationInfo> 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<Path, String> createControllerMapping(final Map<? extends Path, ? extends Path> fxmls,
|
||||
final ExecutorService executor) {
|
||||
final var mapping = new ConcurrentHashMap<Path, String>();
|
||||
private Map<Path, String> createControllerMapping(final Map<? extends Path, ? extends Path> fxmls,
|
||||
final Executor executor) {
|
||||
final var futures = new ArrayList<CompletableFuture<ControllerMapping>>(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<Path, String>();
|
||||
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<Path, CompilationInfo> createCompilationInfoMapping(final Map<? extends Path, ? extends Path> fxmls,
|
||||
final Map<? extends Path, String> controllerMapping, final ExecutorService executor) {
|
||||
final var mapping = new ConcurrentHashMap<Path, CompilationInfo>();
|
||||
final Map<? extends Path, String> controllerMapping,
|
||||
final Executor executor) {
|
||||
final var compilationInfoProvider = compilationInfoProviderFactory.create(project, outputDirectory);
|
||||
final var futures = new ArrayList<CompletableFuture<CompilationInfoMapping>>(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<Path, CompilationInfo>();
|
||||
futures.forEach(c -> {
|
||||
final var joined = c.join();
|
||||
mapping.put(joined.fxml(), joined.info());
|
||||
});
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private void compile(final Map<Path, CompilationInfo> 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(() -> {
|
||||
try {
|
||||
Compiler.compile(p, i, mapping, parameters);
|
||||
} catch (final MojoExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
private record CompilationInfoMapping(Path fxml, CompilationInfo info) {
|
||||
|
||||
}
|
||||
}));
|
||||
|
||||
private void compile(final Map<Path, CompilationInfo> mapping, final Executor executor) {
|
||||
final var parameters = new GenerationParametersImpl(new GenerationCompatibilityImpl(targetVersion),
|
||||
useImageInputStreamConstructor, resourceMap, controllerInjectionType, fieldInjectionType,
|
||||
methodInjectionType, resourceInjectionType);
|
||||
final var futures = new ArrayList<CompletableFuture<Void>>(mapping.size());
|
||||
mapping.forEach((p, i) -> futures.add(CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
compiler.compile(p, i, mapping, parameters);
|
||||
} catch (final MojoExecutionException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
}, executor)));
|
||||
futures.forEach(CompletableFuture::join);
|
||||
project.addCompileSourceRoot(outputDirectory.toAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,25 @@ public record CompilationInfo(Path inputFile, Path outputFile, String outputClas
|
||||
String controllerClass, Set<FieldInfo> injectedFields, Set<String> injectedMethods,
|
||||
Map<String, Path> 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);
|
||||
|
||||
@@ -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<? extends Path, String> controllerMapping,
|
||||
final Path outputDirectory, final MavenProject project) throws MojoExecutionException {
|
||||
public CompilationInfo getCompilationInfo(final Path root, final Path inputPath, final Map<? extends Path, String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Path, CompilationInfo> mapping, final GenerationParameters parameters) throws MojoExecutionException {
|
||||
public void compile(final Map<Path, CompilationInfo> 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<Path, CompilationInfo> 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<Path, CompilationInfo> 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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<Path, Path> getFXMLs(final MavenProject project) throws MojoExecutionException {
|
||||
public Map<Path, Path> getFXMLs() throws MojoExecutionException {
|
||||
final var map = new HashMap<Path, Path>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,17 @@ final class GenericParser {
|
||||
}
|
||||
|
||||
List<GenericTypes> 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<GenericTypes> parseGenericTypes() throws MojoExecutionException {
|
||||
if (content.isEmpty()) {
|
||||
throw new MojoExecutionException("Empty generic types");
|
||||
}
|
||||
final var ret = new ArrayList<GenericTypes>();
|
||||
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)) {
|
||||
|
||||
@@ -32,7 +32,7 @@ final class SourceInfoProvider {
|
||||
final var requiresResourceBundle = info.requiresResourceBundle();
|
||||
final var includesMapping = new HashMap<String, SourceInfo>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, String> resourceMap;
|
||||
private final Map<Path, Path> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<FieldInfo> injectedFields;
|
||||
private final Set<String> injectedMethods;
|
||||
private final Map<String, Path> 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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Integer, ComboBox<String>> tableColumn;
|
||||
private ComboBox<Integer> 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<String>"))), 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
"<BorderPane xmlns=\"http://javafx.com/javafx/22\" xmlns:fx=\"http://javafx.com/fxml/1\"" +
|
||||
" fx:controller=\"LoadController\">" +
|
||||
"</BorderPane>\n");
|
||||
assertEquals("LoadController", ControllerProvider.getController(fxml));
|
||||
assertEquals("LoadController", controllerProvider.getController(fxml));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -32,11 +37,11 @@ class TestControllerProvider {
|
||||
Files.writeString(fxml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<BorderPane xmlns=\"http://javafx.com/javafx/22\" xmlns:fx=\"http://javafx.com/fxml/1\">" +
|
||||
"</BorderPane>\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")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("<Collection>", Map.of());
|
||||
assertThrows(MojoExecutionException.class, parser::parse);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"<String, String<String>>", " < String , String < String > > ",
|
||||
"<String,String<String>>", " <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 = {"", "<String>>", "<<String>", "<String,,String>"})
|
||||
void testInvalid(final String genericTypes) {
|
||||
final var parser = new GenericParser(genericTypes, Map.of());
|
||||
assertThrows(MojoExecutionException.class, parser::parse);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> providesParseTests() {
|
||||
return Stream.of(
|
||||
Arguments.of("<Map<String, TableView<Node, Node>>>",
|
||||
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<String, String>>",
|
||||
Map.of("Map", "java.util.Map"),
|
||||
@@ -39,10 +64,10 @@ class TestGenericParser {
|
||||
Arguments.of("<Collection<String>>",
|
||||
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("<Collection<String>>",
|
||||
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())))))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.maven.internal.InfoController">
|
||||
<bottom>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.maven.internal.InfoController">
|
||||
<bottom>
|
||||
<HBox>
|
||||
<children>
|
||||
<Button fx:id="button" onAction="#onAction" onContextMenuRequested="$controller.onContextMenuRequested"
|
||||
text="%text"/>
|
||||
<fx:include fx:id="includeView" source="includeView.fxml"/>
|
||||
</children>
|
||||
</HBox>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.maven.internal.InfoController">
|
||||
<bottom>
|
||||
<HBox>
|
||||
<children>
|
||||
<fx:include fx:id="includeView"/>
|
||||
</children>
|
||||
</HBox>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<bottom>
|
||||
<fx:include fx:id="includeView" source="includeView.fxml"/>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.maven.internal.InfoController">
|
||||
<bottom>
|
||||
<HBox>
|
||||
<children>
|
||||
<Button fx:id="button" onAction="#onAction" onContextMenuRequested="$controller.onContextMenuRequested"
|
||||
text="text"/>
|
||||
<fx:include fx:id="includeView" source="includeView.fxml"/>
|
||||
</children>
|
||||
</HBox>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.maven.internal.InfoController">
|
||||
<bottom>
|
||||
<HBox>
|
||||
<children>
|
||||
<Button fx:id="button" onAction="onAction"/>
|
||||
</children>
|
||||
</HBox>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
2
mvnw
vendored
2
mvnw
vendored
@@ -208,7 +208,7 @@ elif set_java_home; then
|
||||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
setDefault( new Downloader() );
|
||||
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Path.of( args[1] ).toAbsolutePath().normalize() );
|
||||
}
|
||||
}
|
||||
END
|
||||
|
||||
4
pom.xml
4
pom.xml
@@ -48,8 +48,8 @@
|
||||
<plugin.versions.version>2.18.0</plugin.versions.version>
|
||||
|
||||
<javafx.version>23.0.1</javafx.version>
|
||||
<junit.version>5.11.3</junit.version>
|
||||
<log4j.version>2.21.0</log4j.version>
|
||||
<junit.version>5.11.4</junit.version>
|
||||
<log4j.version>2.24.3</log4j.version>
|
||||
<mockito.version>5.14.2</mockito.version>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -202,8 +202,11 @@ public class DOMFXMLParser implements FXMLParser {
|
||||
final var objects = new ArrayList<ParsedObject>();
|
||||
final var children = node.getChildNodes();
|
||||
for (var i = 0; i < children.getLength(); i++) {
|
||||
if (children.item(i).getNodeType() == Node.ELEMENT_NODE) {
|
||||
objects.add(parseObject(children.item(i), imports));
|
||||
final var child = children.item(i);
|
||||
if (child.getNodeType() == Node.ELEMENT_NODE) {
|
||||
objects.add(parseObject(child, imports));
|
||||
} else if (child.getNodeType() == Node.TEXT_NODE && !child.getNodeValue().isBlank()) {
|
||||
objects.add(new ParsedTextImpl(child.getNodeValue().trim()));
|
||||
}
|
||||
}
|
||||
return new ComplexProperty(new ParsedPropertyImpl(sourceTypeName.name(), sourceTypeName.sourceType(), null), objects);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.gtache.fxml.compiler.parsing.xml;
|
||||
|
||||
import com.github.gtache.fxml.compiler.parsing.ParseException;
|
||||
import com.github.gtache.fxml.compiler.parsing.impl.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.EventHandler;
|
||||
@@ -12,14 +13,14 @@ import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SequencedMap;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TestDOMFXMLParser {
|
||||
|
||||
@@ -74,7 +75,13 @@ class TestDOMFXMLParser {
|
||||
)),
|
||||
new ParsedFactoryImpl(FXCollections.class.getName(), Map.of("fx:id", new ParsedPropertyImpl("fx:id", null, "define6"), "fx:factory", new ParsedPropertyImpl("fx:factory", null, "emptyObservableMap")), List.of(), List.of())))))),
|
||||
new ParsedPropertyImpl("center", null, null),
|
||||
List.of(new ParsedObjectImpl(VBox.class.getName(), newLinkedHashMap("fx:id", new ParsedPropertyImpl("fx:id", null, "vbox")), newLinkedHashMap(), List.of()))
|
||||
List.of(new ParsedObjectImpl(VBox.class.getName(), newLinkedHashMap("fx:id", new ParsedPropertyImpl("fx:id", null, "vbox"), "alignment", new ParsedPropertyImpl("alignment", null, "TOP_RIGHT")),
|
||||
newLinkedHashMap(
|
||||
new ParsedPropertyImpl("accessibleText", null, null), List.of(
|
||||
new ParsedDefineImpl(List.of(
|
||||
new ParsedObjectImpl(String.class.getName(), Map.of("value",
|
||||
new ParsedPropertyImpl("value", null, "3")), newLinkedHashMap(), List.of())
|
||||
)), new ParsedTextImpl("text"))), List.of()))
|
||||
), List.of());
|
||||
try (final var in = getClass().getResourceAsStream("loadView.fxml")) {
|
||||
assertNotNull(in);
|
||||
@@ -84,6 +91,51 @@ class TestDOMFXMLParser {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvalidDefine() throws IOException {
|
||||
try (final var in = getClass().getResourceAsStream("invalidDefine.fxml")) {
|
||||
assertNotNull(in);
|
||||
final var content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertThrows(ParseException.class, () -> parser.parse(content));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvalidFactory() throws IOException {
|
||||
try (final var in = getClass().getResourceAsStream("invalidFactory.fxml")) {
|
||||
assertNotNull(in);
|
||||
final var content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertThrows(ParseException.class, () -> parser.parse(content));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadRoot() throws IOException {
|
||||
try (final var in = getClass().getResourceAsStream("loadRoot.fxml")) {
|
||||
assertNotNull(in);
|
||||
final var content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertThrows(ParseException.class, () -> parser.parse(content));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadScript() throws IOException {
|
||||
try (final var in = getClass().getResourceAsStream("loadScript.fxml")) {
|
||||
assertNotNull(in);
|
||||
final var content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertThrows(ParseException.class, () -> parser.parse(content));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnknownClass() throws IOException {
|
||||
try (final var in = getClass().getResourceAsStream("unknownClass.fxml")) {
|
||||
assertNotNull(in);
|
||||
final var content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertThrows(ParseException.class, () -> parser.parse(content));
|
||||
}
|
||||
}
|
||||
|
||||
private static <K, V> SequencedMap<K, V> newLinkedHashMap() {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
@@ -100,12 +152,4 @@ class TestDOMFXMLParser {
|
||||
map.put(k2, v2);
|
||||
return map;
|
||||
}
|
||||
|
||||
private static <K, V> SequencedMap<K, V> newLinkedHashMap(final K k1, final V v1, final K k2, final V v2, final K k3, final V v3) {
|
||||
final var map = new LinkedHashMap<K, V>();
|
||||
map.put(k1, v1);
|
||||
map.put(k2, v2);
|
||||
map.put(k3, v3);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.parsing.xml.LoadController">
|
||||
<bottom>
|
||||
<fx:define>
|
||||
<children></children>
|
||||
</fx:define>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.parsing.xml.LoadController">
|
||||
<bottom>
|
||||
<fx:define>
|
||||
<FXCollections fx:id="define5" fx:factory="observableArrayList">
|
||||
<children></children>
|
||||
</FXCollections>
|
||||
</fx:define>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<fx:root type="javafx.scene.layout.BorderPane" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.parsing.xml.LoadController">
|
||||
</fx:root>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.parsing.xml.LoadController">
|
||||
<fx:script></fx:script>
|
||||
</BorderPane>
|
||||
@@ -60,6 +60,13 @@
|
||||
</bottom>
|
||||
<center>
|
||||
<VBox fx:id="vbox">
|
||||
<alignment>TOP_RIGHT</alignment>
|
||||
<accessibleText>
|
||||
<fx:define>
|
||||
<String value="3"/>
|
||||
</fx:define>
|
||||
text
|
||||
</accessibleText>
|
||||
</VBox>
|
||||
</center>
|
||||
</BorderPane>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<BorderPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.fxml.compiler.parsing.xml.LoadController">
|
||||
<bottom>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
Reference in New Issue
Block a user