Adds HelperProvider, starts testing internal classes

This commit is contained in:
Guillaume Tâche
2024-12-14 22:02:07 +01:00
parent d63188e8ee
commit 38056c43f7
28 changed files with 1057 additions and 482 deletions

View File

@@ -3,10 +3,8 @@ package com.github.gtache.fxml.compiler.impl;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.GenerationRequest;
import com.github.gtache.fxml.compiler.Generator;
import com.github.gtache.fxml.compiler.impl.internal.ConstructorFormatter;
import com.github.gtache.fxml.compiler.impl.internal.GenerationProgress;
import com.github.gtache.fxml.compiler.impl.internal.HelperMethodsFormatter;
import com.github.gtache.fxml.compiler.impl.internal.LoadMethodFormatter;
import com.github.gtache.fxml.compiler.impl.internal.HelperProvider;
//TODO handle binding (${})
@@ -15,10 +13,10 @@ import com.github.gtache.fxml.compiler.impl.internal.LoadMethodFormatter;
*/
public class GeneratorImpl implements Generator {
@Override
public String generate(final GenerationRequest request) throws GenerationException {
final var progress = new GenerationProgress(request);
final var helperProvider = new HelperProvider(progress);
final var className = request.outputClassName();
final var pkgName = className.substring(0, className.lastIndexOf('.'));
final var simpleClassName = className.substring(className.lastIndexOf('.') + 1);
@@ -27,15 +25,15 @@ public class GeneratorImpl implements Generator {
sb.append("package ").append(pkgName).append(";\n");
sb.append("\n");
sb.append("/**\n");
sb.append(" * Generated code, not thread-safe\n");
sb.append(" * Generated code\n");
sb.append(" */\n");
sb.append("public final class ").append(simpleClassName).append(" {\n");
sb.append("\n");
ConstructorFormatter.formatFieldsAndConstructor(progress);
helperProvider.getInitializationFormatter().formatFieldsAndConstructor();
sb.append("\n");
LoadMethodFormatter.formatLoadMethod(progress);
helperProvider.getLoadMethodFormatter().formatLoadMethod();
sb.append("\n");
HelperMethodsFormatter.formatHelperMethods(progress);
helperProvider.getHelperMethodsFormatter().formatHelperMethods();
sb.append("\n");
formatControllerMethod(progress, controllerInjectionClass);
sb.append("}\n");

View File

@@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
@@ -16,7 +17,10 @@ import java.util.Set;
*/
final class ConstructorHelper {
private ConstructorHelper() {
private final HelperProvider helperProvider;
ConstructorHelper(final HelperProvider helperProvider) {
this.helperProvider = Objects.requireNonNull(helperProvider);
}
/**
@@ -27,8 +31,9 @@ final class ConstructorHelper {
* @return The list of constructor arguments
* @throws GenerationException if an error occurs
*/
static List<String> getListConstructorArgs(final ConstructorArgs constructorArgs, final ParsedObject parsedObject) throws GenerationException {
List<String> getListConstructorArgs(final ConstructorArgs constructorArgs, final ParsedObject parsedObject) throws GenerationException {
final var args = new ArrayList<String>(constructorArgs.namedArgs().size());
final var valueFormatter = helperProvider.getValueFormatter();
for (final var entry : constructorArgs.namedArgs().entrySet()) {
final var type = entry.getValue().type();
final var p = parsedObject.attributes().get(entry.getKey());
@@ -36,12 +41,12 @@ final class ConstructorHelper {
final var c = parsedObject.properties().entrySet().stream().filter(e ->
e.getKey().name().equals(entry.getKey())).findFirst().orElse(null);
if (c == null) {
args.add(ValueFormatter.toString(entry.getValue().defaultValue(), type));
args.add(valueFormatter.toString(entry.getValue().defaultValue(), type));
} else {
throw new GenerationException("Constructor using complex property not supported yet");
}
} else {
args.add(ValueFormatter.toString(p.value(), type));
args.add(valueFormatter.toString(p.value(), type));
}
}
return args;

View File

@@ -1,5 +1,6 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.ControllerInfo;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.InjectionType;
import com.github.gtache.fxml.compiler.impl.ControllerFieldInjectionTypes;
@@ -7,26 +8,39 @@ import com.github.gtache.fxml.compiler.impl.ControllerMethodsInjectionType;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
import java.util.SequencedCollection;
import static java.util.Objects.requireNonNull;
/**
* Various methods to help {@link GeneratorImpl} for injecting controllers
*/
final class ControllerInjector {
private ControllerInjector() {
private final ControllerInfo controllerInfo;
private final InjectionType fieldInjectionType;
private final InjectionType methodInjectionType;
private final StringBuilder sb;
private final SequencedCollection<String> controllerFactoryPostAction;
ControllerInjector(final ControllerInfo controllerInfo, final InjectionType fieldInjectionType, final InjectionType methodInjectionType,
final StringBuilder sb, final SequencedCollection<String> controllerFactoryPostAction) {
this.controllerInfo = controllerInfo;
this.fieldInjectionType = requireNonNull(fieldInjectionType);
this.methodInjectionType = requireNonNull(methodInjectionType);
this.sb = requireNonNull(sb);
this.controllerFactoryPostAction = requireNonNull(controllerFactoryPostAction);
}
/**
* Injects the given variable into the controller
*
* @param progress The generation progress
* @param id The object id
* @param variable The object variable
* @throws GenerationException if an error occurs
*/
static void injectControllerField(final GenerationProgress progress, final String id, final String variable) throws GenerationException {
final var fieldInjectionType = progress.request().parameters().fieldInjectionType();
void injectControllerField(final String id, final String variable) throws GenerationException {
if (fieldInjectionType instanceof final ControllerFieldInjectionTypes types) {
final var sb = progress.stringBuilder();
switch (types) {
case FACTORY ->
sb.append(" fieldMap.put(\"").append(id).append("\", ").append(variable).append(");\n");
@@ -46,41 +60,37 @@ final class ControllerInjector {
/**
* Injects an event handler controller method
*
* @param progress The generation progress
* @param property The property to inject
* @param parentVariable The parent variable
* @throws GenerationException if an error occurs
*/
static void injectEventHandlerControllerMethod(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) throws GenerationException {
injectControllerMethod(progress, getEventHandlerMethodInjection(progress, property, parentVariable));
void injectEventHandlerControllerMethod(final ParsedProperty property, final String parentVariable) throws GenerationException {
injectControllerMethod(getEventHandlerMethodInjection(property, parentVariable));
}
/**
* Injects a callback controller method
*
* @param progress The generation progress
* @param property The property to inject
* @param parentVariable The parent variable
* @param argumentClazz The argument class
* @throws GenerationException if an error occurs
*/
static void injectCallbackControllerMethod(final GenerationProgress progress, final ParsedProperty property, final String parentVariable, final String argumentClazz) throws GenerationException {
injectControllerMethod(progress, getCallbackMethodInjection(progress, property, parentVariable, argumentClazz));
void injectCallbackControllerMethod(final ParsedProperty property, final String parentVariable, final String argumentClazz) throws GenerationException {
injectControllerMethod(getCallbackMethodInjection(property, parentVariable, argumentClazz));
}
/**
* Injects a controller method
*
* @param progress The generation progress
* @param methodInjection The method injection
* @throws GenerationException if an error occurs
*/
private static void injectControllerMethod(final GenerationProgress progress, final String methodInjection) throws GenerationException {
final var fieldInjectionType = progress.request().parameters().fieldInjectionType();
private void injectControllerMethod(final String methodInjection) throws GenerationException {
if (fieldInjectionType instanceof final ControllerFieldInjectionTypes fieldTypes) {
switch (fieldTypes) {
case FACTORY -> progress.controllerFactoryPostAction().add(methodInjection);
case ASSIGN, SETTERS, REFLECTION -> progress.stringBuilder().append(methodInjection);
case FACTORY -> controllerFactoryPostAction.add(methodInjection);
case ASSIGN, SETTERS, REFLECTION -> sb.append(methodInjection);
}
} else {
throw getUnknownInjectionException(fieldInjectionType);
@@ -90,20 +100,18 @@ final class ControllerInjector {
/**
* Computes the method injection for event handler
*
* @param progress The generation progress
* @param property The property
* @param parentVariable The parent variable
* @return The method injection
* @throws GenerationException if an error occurs
*/
private static String getEventHandlerMethodInjection(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) throws GenerationException {
private String getEventHandlerMethodInjection(final ParsedProperty property, final String parentVariable) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property.name());
final var methodInjectionType = progress.request().parameters().methodInjectionType();
final var controllerMethod = property.value().replace("#", "");
if (methodInjectionType instanceof final ControllerMethodsInjectionType methodTypes) {
return switch (methodTypes) {
case REFERENCE -> {
final var hasArgument = progress.request().controllerInfo().handlerHasArgument(controllerMethod);
final var hasArgument = controllerInfo.handlerHasArgument(controllerMethod);
if (hasArgument) {
yield " " + parentVariable + "." + setMethod + "(controller::" + controllerMethod + ");\n";
} else {
@@ -121,16 +129,14 @@ final class ControllerInjector {
/**
* Computes the method injection for callback
*
* @param progress The generation progress
* @param property The property
* @param parentVariable The parent variable
* @param argumentClazz The argument class
* @return The method injection
* @throws GenerationException if an error occurs
*/
private static String getCallbackMethodInjection(final GenerationProgress progress, final ParsedProperty property, final String parentVariable, final String argumentClazz) throws GenerationException {
private String getCallbackMethodInjection(final ParsedProperty property, final String parentVariable, final String argumentClazz) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property.name());
final var methodInjectionType = progress.request().parameters().methodInjectionType();
final var controllerMethod = property.value().replace("#", "");
if (methodInjectionType instanceof final ControllerMethodsInjectionType methodTypes) {
return switch (methodTypes) {

View File

@@ -1,68 +1,79 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.InjectionType;
import com.github.gtache.fxml.compiler.impl.ControllerFieldInjectionTypes;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
import java.util.SequencedCollection;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.EXPRESSION_PREFIX;
import static java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to set fields
*/
final class FieldSetter {
private FieldSetter() {
private final HelperProvider helperProvider;
private final InjectionType fieldInjectionType;
private final StringBuilder sb;
private final SequencedCollection<String> controllerFactoryPostAction;
FieldSetter(final HelperProvider helperProvider, final InjectionType fieldInjectionType,
final StringBuilder sb, final SequencedCollection<String> controllerFactoryPostAction) {
this.helperProvider = requireNonNull(helperProvider);
this.fieldInjectionType = requireNonNull(fieldInjectionType);
this.sb = requireNonNull(sb);
this.controllerFactoryPostAction = requireNonNull(controllerFactoryPostAction);
}
/**
* Sets an event handler field
*
* @param progress The generation progress
* @param property The property to inject
* @param parentVariable The parent variable
* @throws GenerationException if an error occurs@
*/
static void setEventHandler(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) throws GenerationException {
setField(progress, property, parentVariable, "javafx.event.EventHandler");
void setEventHandler(final ParsedProperty property, final String parentVariable) throws GenerationException {
setField(property, parentVariable, "javafx.event.EventHandler");
}
/**
* Sets a field
*
* @param progress The generation progress
* @param property The property to inject
* @param parentVariable The parent variable
* @param fieldType The field type
* @throws GenerationException if an error occurs
*/
static void setField(final GenerationProgress progress, final ParsedProperty property, final String parentVariable, final String fieldType) throws GenerationException {
final var fieldInjectionType = progress.request().parameters().fieldInjectionType();
void setField(final ParsedProperty property, final String parentVariable, final String fieldType) throws GenerationException {
if (fieldInjectionType instanceof final ControllerFieldInjectionTypes fieldTypes) {
switch (fieldTypes) {
case ASSIGN -> setAssign(progress, property, parentVariable);
case FACTORY -> setFactory(progress, property, parentVariable);
case SETTERS -> setSetter(progress, property, parentVariable);
case REFLECTION -> setReflection(progress, property, parentVariable, fieldType);
case ASSIGN -> setAssign(property, parentVariable);
case FACTORY -> setFactory(property, parentVariable);
case SETTERS -> setSetter(property, parentVariable);
case REFLECTION -> setReflection(property, parentVariable, fieldType);
}
} else {
throw new GenerationException("Unknown injection type : " + fieldInjectionType);
}
}
private static void setAssign(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) {
private void setAssign(final ParsedProperty property, final String parentVariable) {
final var methodName = GenerationHelper.getSetMethod(property);
final var value = property.value().replace(EXPRESSION_PREFIX, "");
progress.stringBuilder().append(" ").append(parentVariable).append(".").append(methodName).append("(").append(value).append(");\n");
sb.append(" ").append(parentVariable).append(".").append(methodName).append("(").append(value).append(");\n");
}
private static void setFactory(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) {
progress.controllerFactoryPostAction().add(getSetString(property, parentVariable));
private void setFactory(final ParsedProperty property, final String parentVariable) {
controllerFactoryPostAction.add(getSetString(property, parentVariable));
}
private static void setSetter(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) {
progress.stringBuilder().append(getSetString(property, parentVariable));
private void setSetter(final ParsedProperty property, final String parentVariable) {
sb.append(getSetString(property, parentVariable));
}
private static String getSetString(final ParsedProperty property, final String parentVariable) {
@@ -73,14 +84,14 @@ final class FieldSetter {
return " " + parentVariable + "." + methodName + "(" + split[0] + "." + getterName + ");\n";
}
private static void setReflection(final GenerationProgress progress, final ParsedProperty property, final String parentVariable, final String fieldType) {
private void setReflection(final ParsedProperty property, final String parentVariable, final String fieldType) {
final var methodName = GenerationHelper.getSetMethod(property);
final var value = property.value().replace(EXPRESSION_PREFIX, "");
final var split = value.split("\\.");
final var fieldName = split[1];
final var sb = progress.stringBuilder();
sb.append(" try {\n");
sb.append(" ").append(GenerationCompatibilityHelper.getStartVar(progress, "java.lang.reflect.Field", 0)).append("field = controller.getClass().getDeclaredField(\"").append(fieldName).append("\");\n");
sb.append(" ").append(helperProvider.getCompatibilityHelper().getStartVar("java.lang.reflect.Field", 0))
.append("field = controller.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(" ").append(parentVariable).append(".").append(methodName).append("(value);\n");

View File

@@ -11,6 +11,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Objects;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.FX_ID;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.getSortedAttributes;
@@ -20,15 +21,19 @@ import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.get
*/
final class FontFormatter {
private FontFormatter() {
private final HelperProvider helperProvider;
private final StringBuilder sb;
FontFormatter(final HelperProvider helperProvider, final StringBuilder sb) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.sb = Objects.requireNonNull(sb);
}
private static String getStartFont(final GenerationProgress progress) {
return GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.text.Font");
private String getStartFont() {
return helperProvider.getCompatibilityHelper().getStartVar("javafx.scene.text.Font");
}
static void formatFont(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void formatFont(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (parsedObject.children().isEmpty() && parsedObject.properties().isEmpty()) {
final var value = parseFontValue(parsedObject);
final var url = value.url();
@@ -37,37 +42,36 @@ final class FontFormatter {
final var size = value.size();
final var name = value.name();
if (url != null) {
formatURL(progress, url, size, variableName);
formatURL(url, size, variableName);
} else if (fw == null && fp == null) {
formatNoStyle(progress, name, size, variableName);
formatNoStyle(name, size, variableName);
} else {
formatStyle(progress, fw, fp, size, name, variableName);
formatStyle(fw, fp, size, name, variableName);
}
GenerationHelper.handleId(progress, parsedObject, variableName);
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
} else {
throw new GenerationException("Font cannot have children or properties : " + parsedObject);
}
}
private static void formatURL(final GenerationProgress progress, final URL url, final double size, final String variableName) {
final var urlVariableName = URLFormatter.formatURL(progress, url.toString());
final var sb = progress.stringBuilder();
private void formatURL(final URL url, final double size, final String variableName) {
final var urlVariableName = helperProvider.getURLFormatter().formatURL(url.toString());
sb.append(" final javafx.scene.text.Font ").append(variableName).append(";\n");
sb.append(" try (").append(GenerationCompatibilityHelper.getStartVar(progress, "java.io.InputStream", 0)).append(" in = ").append(urlVariableName).append(".openStream()) {\n");
sb.append(" try (").append(helperProvider.getCompatibilityHelper().getStartVar("java.io.InputStream", 0)).append(" in = ").append(urlVariableName).append(".openStream()) {\n");
sb.append(" ").append(variableName).append(" = javafx.scene.text.Font.loadFont(in, ").append(size).append(");\n");
sb.append(" } catch (final java.io.IOException e) {\n");
sb.append(" throw new RuntimeException(e);\n");
sb.append(" }\n");
}
private static void formatNoStyle(final GenerationProgress progress, final String name, final double size, final String variableName) {
progress.stringBuilder().append(getStartFont(progress)).append(variableName).append(" = new javafx.scene.text.Font(\"").append(name).append("\", ").append(size).append(");\n");
private void formatNoStyle(final String name, final double size, final String variableName) {
sb.append(getStartFont()).append(variableName).append(" = new javafx.scene.text.Font(\"").append(name).append("\", ").append(size).append(");\n");
}
private static void formatStyle(final GenerationProgress progress, final FontWeight fw, final FontPosture fp, final double size, final String name, final String variableName) {
private void formatStyle(final FontWeight fw, final FontPosture fp, final double size, final String name, final String variableName) {
final var finalFW = fw == null ? FontWeight.NORMAL : fw;
final var finalFP = fp == null ? FontPosture.REGULAR : fp;
progress.stringBuilder().append(getStartFont(progress)).append(variableName).append(" = new javafx.scene.text.Font(\"").append(name)
sb.append(getStartFont()).append(variableName).append(" = new javafx.scene.text.Font(\"").append(name)
.append("\", javafx.scene.text.FontWeight.").append(finalFW.name()).append(", javafx.scene.text.FontPosture.")
.append(finalFP.name()).append(", ").append(size).append(");\n");
}

View File

@@ -1,52 +1,59 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.compatibility.GenerationCompatibility;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import java.util.Objects;
/**
* Various helper methods for {@link GeneratorImpl} to handle compatibility with older java versions
*/
final class GenerationCompatibilityHelper {
private GenerationCompatibilityHelper() {
private final HelperProvider helperProvider;
private final GenerationCompatibility compatibility;
GenerationCompatibilityHelper(final HelperProvider helperProvider, final GenerationCompatibility compatibility) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.compatibility = Objects.requireNonNull(compatibility);
}
static String getStartVar(final GenerationProgress progress, final ParsedObject parsedObject) throws GenerationException {
return getStartVar(progress, parsedObject.className() + ReflectionHelper.getGenericTypes(progress, parsedObject));
String getStartVar(final ParsedObject parsedObject) throws GenerationException {
return getStartVar(parsedObject.className() + helperProvider.getReflectionHelper().getGenericTypes(parsedObject));
}
static String getStartVar(final GenerationProgress progress, final String className) {
return getStartVar(progress, className, 8);
String getStartVar(final String className) {
return getStartVar(className, 8);
}
static String getStartVar(final GenerationProgress progress, final String className, final int indent) {
if (progress.request().parameters().compatibility().useVar()) {
String getStartVar(final String className, final int indent) {
if (compatibility.useVar()) {
return " ".repeat(indent) + "final var ";
} else {
return " ".repeat(indent) + "final " + className + " ";
}
}
static String getToList(final GenerationProgress progress) {
return switch (progress.request().parameters().compatibility().listCollector()) {
String getToList() {
return switch (compatibility.listCollector()) {
case TO_LIST -> ".toList()";
case COLLECT_TO_UNMODIFIABLE_LIST -> ".collect(java.util.stream.Collectors.toUnmodifiableList())";
case COLLECT_TO_LIST -> ".collect(java.util.stream.Collectors.toList())";
};
}
static String getGetFirst(final GenerationProgress progress) {
if (progress.request().parameters().compatibility().useGetFirst()) {
String getGetFirst() {
if (compatibility.useGetFirst()) {
return ".getFirst()";
} else {
return ".get(0)";
}
}
static String getListOf(final GenerationProgress progress) {
if (progress.request().parameters().compatibility().useCollectionsOf()) {
String getListOf() {
if (compatibility.useCollectionsOf()) {
return "java.util.List.of(";
} else {
return "java.util.Arrays.asList(";

View File

@@ -1,5 +1,6 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.ControllerInfo;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
@@ -10,6 +11,8 @@ import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Map;
import static java.util.Objects.requireNonNull;
/**
* Various helper methods for {@link GeneratorImpl}
*/
@@ -28,35 +31,41 @@ final class GenerationHelper {
static final String BINDING_EXPRESSION_PREFIX = "${";
static final String BI_DIRECTIONAL_BINDING_PREFIX = "#{";
private final HelperProvider helperProvider;
private final ControllerInfo controllerInfo;
private final Map<String, VariableInfo> idToVariableInfo;
private GenerationHelper() {
GenerationHelper(final HelperProvider helperProvider, final ControllerInfo controllerInfo, final Map<String, VariableInfo> idToVariableInfo) {
this.helperProvider = requireNonNull(helperProvider);
this.controllerInfo = requireNonNull(controllerInfo);
this.idToVariableInfo = requireNonNull(idToVariableInfo);
}
/**
* Handles the fx:id attribute of an object
*
* @param progress The generation progress
* @param parsedObject The parsed object
* @param variableName The variable name
* @throws GenerationException if an error occurs
*/
static void handleId(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void handleId(final ParsedObject parsedObject, final String variableName) throws GenerationException {
final var id = parsedObject.attributes().get(FX_ID);
if (id != null) {
final var idValue = id.value();
final String className;
if (progress.request().controllerInfo().fieldInfo(idValue) == null) {
if (controllerInfo.fieldInfo(idValue) == null) {
className = parsedObject.className();
logger.debug("Not injecting {} because it is not found in controller", idValue);
} else {
final var reflectionHelper = helperProvider.getReflectionHelper();
if (ReflectionHelper.isGeneric(ReflectionHelper.getClass(parsedObject.className()))) {
className = parsedObject.className() + ReflectionHelper.getGenericTypes(progress, parsedObject);
className = parsedObject.className() + reflectionHelper.getGenericTypes(parsedObject);
} else {
className = parsedObject.className();
}
ControllerInjector.injectControllerField(progress, idValue, variableName);
helperProvider.getControllerInjector().injectControllerField(idValue, variableName);
}
progress.idToVariableInfo().put(idValue, new VariableInfo(idValue, parsedObject, variableName, className));
idToVariableInfo.put(idValue, new VariableInfo(idValue, parsedObject, variableName, className));
}
}

View File

@@ -64,7 +64,7 @@ public record GenerationProgress(GenerationRequest request, Map<String, Variable
* @param prefix The variable name prefix
* @return The next available variable name
*/
public String getNextVariableName(final String prefix) {
String getNextVariableName(final String prefix) {
final var counter = variableNameCounters.computeIfAbsent(prefix, k -> new AtomicInteger(0));
return prefix + counter.getAndIncrement();
}

View File

@@ -1,30 +1,37 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.InjectionType;
import com.github.gtache.fxml.compiler.impl.ControllerFieldInjectionTypes;
import com.github.gtache.fxml.compiler.impl.ControllerMethodsInjectionType;
import java.util.Objects;
/**
* Formats the helper methods for the generated code
*/
public final class HelperMethodsFormatter {
private final HelperProvider helperProvider;
private final InjectionType fieldInjectionType;
private final InjectionType methodInjectionType;
private final StringBuilder sb;
private HelperMethodsFormatter() {
HelperMethodsFormatter(final HelperProvider helperProvider, final InjectionType fieldInjectionType, final InjectionType methodInjectionType, final StringBuilder sb) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.fieldInjectionType = Objects.requireNonNull(fieldInjectionType);
this.methodInjectionType = Objects.requireNonNull(methodInjectionType);
this.sb = Objects.requireNonNull(sb);
}
/**
* Formats the helper methods for the given generation progress
*
* @param progress The generation progress
* Formats the helper methods
*/
public static void formatHelperMethods(final GenerationProgress progress) {
final var parameters = progress.request().parameters();
final var methodInjectionType = parameters.methodInjectionType();
final var sb = progress.stringBuilder();
public void formatHelperMethods() {
final var compatibilityHelper = helperProvider.getCompatibilityHelper();
if (methodInjectionType == ControllerMethodsInjectionType.REFLECTION) {
final var toList = GenerationCompatibilityHelper.getToList(progress);
final var getFirst = GenerationCompatibilityHelper.getGetFirst(progress);
final var startVariableMethodList = GenerationCompatibilityHelper.getStartVar(progress, "java.util.List<java.lang.reflect.Method>", 0);
final var toList = compatibilityHelper.getToList();
final var getFirst = compatibilityHelper.getGetFirst();
final var startVariableMethodList = compatibilityHelper.getStartVar("java.util.List<java.lang.reflect.Method>", 0);
sb.append(" private <T extends javafx.event.Event> void callEventHandlerMethod(final String methodName, final T event) {\n");
sb.append(" try {\n");
sb.append(" final java.lang.reflect.Method method;\n");
@@ -84,10 +91,10 @@ public final class HelperMethodsFormatter {
sb.append(" }\n");
sb.append(" }\n");
}
if (parameters.fieldInjectionType() == ControllerFieldInjectionTypes.REFLECTION) {
if (fieldInjectionType == ControllerFieldInjectionTypes.REFLECTION) {
sb.append(" private <T> void injectField(final String fieldName, final T object) {\n");
sb.append(" try {\n");
sb.append(" ").append(GenerationCompatibilityHelper.getStartVar(progress, "java.lang.reflect.Field", 0)).append("field = controller.getClass().getDeclaredField(fieldName);\n");
sb.append(" ").append(compatibilityHelper.getStartVar("java.lang.reflect.Field", 0)).append("field = controller.getClass().getDeclaredField(fieldName);\n");
sb.append(" field.setAccessible(true);\n");
sb.append(" field.set(controller, object);\n");
sb.append(" } catch (final NoSuchFieldException | IllegalAccessException e) {\n");

View File

@@ -0,0 +1,117 @@
package com.github.gtache.fxml.compiler.impl.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Provider of helper classes
*/
public class HelperProvider {
private final Map<Class<?>, Object> helpers;
private final GenerationProgress progress;
/**
* Instantiates a new helper provider
* @param progress The generation progress
*/
public HelperProvider(final GenerationProgress progress) {
this.progress = Objects.requireNonNull(progress);
this.helpers = new HashMap<>();
}
ConstructorHelper getConstructorHelper() {
return (ConstructorHelper) helpers.computeIfAbsent(ConstructorHelper.class, c -> new ConstructorHelper(this));
}
ControllerInjector getControllerInjector() {
final var request = progress.request();
final var controllerInfo = request.controllerInfo();
final var parameters = request.parameters();
final var fieldInjectionType = parameters.fieldInjectionType();
final var methodInjectionType = parameters.methodInjectionType();
final var sb = progress.stringBuilder();
final var controllerFactoryPostAction = progress.controllerFactoryPostAction();
return (ControllerInjector) helpers.computeIfAbsent(ControllerInjector.class, c -> new ControllerInjector(controllerInfo, fieldInjectionType, methodInjectionType, sb, controllerFactoryPostAction));
}
FieldSetter getFieldSetter() {
final var fieldInjectionType = progress.request().parameters().fieldInjectionType();
final var sb = progress.stringBuilder();
final var controllerFactoryPostAction = progress.controllerFactoryPostAction();
return (FieldSetter) helpers.computeIfAbsent(FieldSetter.class, c -> new FieldSetter(this, fieldInjectionType, sb, controllerFactoryPostAction));
}
FontFormatter getFontFormatter() {
final var sb = progress.stringBuilder();
return (FontFormatter) helpers.computeIfAbsent(FontFormatter.class, c -> new FontFormatter(this, sb));
}
GenerationCompatibilityHelper getCompatibilityHelper() {
final var compatibility = progress.request().parameters().compatibility();
return (GenerationCompatibilityHelper) helpers.computeIfAbsent(GenerationCompatibilityHelper.class, c -> new GenerationCompatibilityHelper(this, compatibility));
}
GenerationHelper getGenerationHelper() {
final var controllerInfo = progress.request().controllerInfo();
final var idToVariableInfo = progress.idToVariableInfo();
return (GenerationHelper) helpers.computeIfAbsent(GenerationHelper.class, c -> new GenerationHelper(this, controllerInfo, idToVariableInfo));
}
public HelperMethodsFormatter getHelperMethodsFormatter() {
final var parameters = progress.request().parameters();
final var fieldInjectionType = parameters.fieldInjectionType();
final var methodInjectionType = parameters.methodInjectionType();
final var sb = progress.stringBuilder();
return (HelperMethodsFormatter) helpers.computeIfAbsent(HelperMethodsFormatter.class, c -> new HelperMethodsFormatter(this, fieldInjectionType, methodInjectionType, sb));
}
ImageFormatter getImageFormatter() {
return (ImageFormatter) helpers.computeIfAbsent(ImageFormatter.class, c -> new ImageFormatter(this, progress));
}
public InitializationFormatter getInitializationFormatter() {
return (InitializationFormatter) helpers.computeIfAbsent(InitializationFormatter.class, c -> new InitializationFormatter(this, progress));
}
public LoadMethodFormatter getLoadMethodFormatter() {
return (LoadMethodFormatter) helpers.computeIfAbsent(LoadMethodFormatter.class, c -> new LoadMethodFormatter(this, progress));
}
ObjectFormatter getObjectFormatter() {
return (ObjectFormatter) helpers.computeIfAbsent(ObjectFormatter.class, c -> new ObjectFormatter(this, progress));
}
PropertyFormatter getPropertyFormatter() {
return (PropertyFormatter) helpers.computeIfAbsent(PropertyFormatter.class, c -> new PropertyFormatter(this, progress));
}
ReflectionHelper getReflectionHelper() {
final var controllerInfo = progress.request().controllerInfo();
return (ReflectionHelper) helpers.computeIfAbsent(ReflectionHelper.class, c -> new ReflectionHelper(controllerInfo));
}
SceneFormatter getSceneFormatter() {
return (SceneFormatter) helpers.computeIfAbsent(SceneFormatter.class, c -> new SceneFormatter(this, progress));
}
TriangleMeshFormatter getTriangleMeshFormatter() {
final var sb = progress.stringBuilder();
return (TriangleMeshFormatter) helpers.computeIfAbsent(TriangleMeshFormatter.class, c -> new TriangleMeshFormatter(this, sb));
}
URLFormatter getURLFormatter() {
return (URLFormatter) helpers.computeIfAbsent(URLFormatter.class, c -> new URLFormatter(this, progress));
}
ValueFormatter getValueFormatter() {
final var resourceInjectionType = progress.request().parameters().resourceInjectionType();
final var idToVariableInfo = progress.idToVariableInfo();
return (ValueFormatter) helpers.computeIfAbsent(ValueFormatter.class, c -> new ValueFormatter(resourceInjectionType, idToVariableInfo));
}
WebViewFormatter getWebViewFormatter() {
return (WebViewFormatter) helpers.computeIfAbsent(WebViewFormatter.class, c -> new WebViewFormatter(this, progress));
}
}

View File

@@ -4,6 +4,8 @@ import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import java.util.Objects;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.FX_ID;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.getSortedAttributes;
@@ -12,24 +14,28 @@ import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.get
*/
final class ImageFormatter {
private ImageFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
ImageFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.progress = Objects.requireNonNull(progress);
}
static void formatImage(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void formatImage(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (parsedObject.children().isEmpty() && parsedObject.properties().isEmpty()) {
doFormatImage(progress, parsedObject, variableName);
doFormatImage(parsedObject, variableName);
} else {
throw new GenerationException("Image cannot have children or properties : " + parsedObject);
}
}
private static void formatInputStream(final GenerationProgress progress, final String url, final double requestedWidth,
private void formatInputStream(final String url, final double requestedWidth,
final double requestedHeight, final boolean preserveRatio, final boolean smooth, final String variableName) {
final var inputStream = progress.getNextVariableName("inputStream");
final var sb = progress.stringBuilder();
sb.append(" final javafx.scene.image.Image ").append(variableName).append(";\n");
sb.append(" try (").append(GenerationCompatibilityHelper.getStartVar(progress, "java.io.InputStream", 0)).append(inputStream).append(" = ").append(url).append(".openStream()) {\n");
sb.append(" try (").append(helperProvider.getCompatibilityHelper().getStartVar("java.io.InputStream", 0)).append(inputStream).append(" = ").append(url).append(".openStream()) {\n");
sb.append(" ").append(variableName).append(" = new javafx.scene.image.Image(").append(inputStream);
sb.append(", ").append(requestedWidth).append(", ").append(requestedHeight).append(", ").append(preserveRatio).append(", ").append(smooth).append(");\n");
sb.append(" } catch (final java.io.IOException e) {\n");
@@ -37,7 +43,7 @@ final class ImageFormatter {
sb.append(" }\n");
}
private static void doFormatImage(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
private void doFormatImage(final ParsedObject parsedObject, final String variableName) throws GenerationException {
final var sortedAttributes = getSortedAttributes(parsedObject);
String url = null;
var requestedWidth = 0.0;
@@ -50,7 +56,7 @@ final class ImageFormatter {
case FX_ID -> {
//Do nothing
}
case "url" -> url = URLFormatter.formatURL(progress, property.value());
case "url" -> url = helperProvider.getURLFormatter().formatURL(property.value());
case "requestedWidth" -> requestedWidth = Double.parseDouble(property.value());
case "requestedHeight" -> requestedHeight = Double.parseDouble(property.value());
case "preserveRatio" -> preserveRatio = Boolean.parseBoolean(property.value());
@@ -61,20 +67,21 @@ final class ImageFormatter {
}
if (progress.request().parameters().useImageInputStreamConstructor()) {
formatInputStream(progress, url, requestedWidth, requestedHeight, preserveRatio, smooth, variableName);
formatInputStream(url, requestedWidth, requestedHeight, preserveRatio, smooth, variableName);
} else {
formatURL(progress, url, requestedWidth, requestedHeight, preserveRatio, smooth, backgroundLoading, variableName);
formatURL(url, requestedWidth, requestedHeight, preserveRatio, smooth, backgroundLoading, variableName);
}
GenerationHelper.handleId(progress, parsedObject, variableName);
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
}
private static void formatURL(final GenerationProgress progress, final String url, final double requestedWidth,
private void formatURL(final String url, final double requestedWidth,
final double requestedHeight, final boolean preserveRatio, final boolean smooth,
final boolean backgroundLoading, final String variableName) {
final var urlString = progress.getNextVariableName("urlStr");
final var sb = progress.stringBuilder();
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "String")).append(urlString).append(" = ").append(url).append(".toString();\n");
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.image.Image")).append(variableName).append(" = new javafx.scene.image.Image(").append(urlString)
final var compatibilityHelper = helperProvider.getCompatibilityHelper();
sb.append(compatibilityHelper.getStartVar("String")).append(urlString).append(" = ").append(url).append(".toString();\n");
sb.append(compatibilityHelper.getStartVar("javafx.scene.image.Image")).append(variableName).append(" = new javafx.scene.image.Image(").append(urlString)
.append(", ").append(requestedWidth).append(", ").append(requestedHeight).append(", ")
.append(preserveRatio).append(", ").append(smooth).append(", ").append(backgroundLoading).append(");\n");
}

View File

@@ -7,32 +7,38 @@ import com.github.gtache.fxml.compiler.impl.ResourceBundleInjectionTypes;
import com.github.gtache.fxml.compiler.parsing.ParsedInclude;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Utility class to provide the view's constructor and fields
*/
public final class ConstructorFormatter {
public final class InitializationFormatter {
private ConstructorFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
InitializationFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.progress = Objects.requireNonNull(progress);
}
public static void formatFieldsAndConstructor(final GenerationProgress progress) throws GenerationException {
public void formatFieldsAndConstructor() throws GenerationException {
final var className = progress.request().outputClassName();
final var simpleClassName = className.substring(className.lastIndexOf('.') + 1);
final var mainControllerClass = progress.request().controllerInfo().className();
final var isFactory = progress.request().parameters().controllerInjectionType() == ControllerInjectionTypes.FACTORY;
if (hasDuplicateControllerClass(progress) && !isFactory) {
if (hasDuplicateControllerClass() && !isFactory) {
throw new GenerationException("Some controllers in the view tree have the same class ; Factory field injection is required");
}
fillControllers(progress);
fillControllers();
final var sb = progress.stringBuilder();
final var controllerMap = progress.controllerClassToVariable();
controllerMap.forEach((c, v) -> sb.append(" private final ").append(c).append(" ").append(v).append(isFactory ? "Factory" : "").append(";\n"));
final var controllerArg = getVariableName("controller", isFactory);
final var controllerArgClass = getType(mainControllerClass, isFactory);
final var resourceBundleInfo = getResourceBundleInfo(progress);
final var resourceBundleInfo = getResourceBundleInfo();
final var resourceBundleType = resourceBundleInfo.type();
final var resourceBundleArg = resourceBundleInfo.variableName();
if (isFactory) {
@@ -70,7 +76,7 @@ public final class ConstructorFormatter {
sb.append(" }\n");
}
private static ResourceBundleInfo getResourceBundleInfo(final GenerationProgress progress) throws GenerationException {
private ResourceBundleInfo getResourceBundleInfo() throws GenerationException {
final var injectionType = progress.request().parameters().resourceInjectionType();
if (injectionType instanceof final ResourceBundleInjectionTypes types) {
return switch (types) {
@@ -109,7 +115,7 @@ public final class ConstructorFormatter {
return variableName + suffix;
}
private static boolean hasDuplicateControllerClass(final GenerationProgress progress) {
private boolean hasDuplicateControllerClass() {
final var set = new HashSet<String>();
return hasDuplicateControllerClass(progress.request().sourceInfo(), set);
}
@@ -122,13 +128,13 @@ public final class ConstructorFormatter {
return info.includedSources().stream().anyMatch(s -> hasDuplicateControllerClass(s, controllers));
}
private static void fillControllers(final GenerationProgress progress) {
progress.request().sourceInfo().includedSources().forEach(s -> fillControllers(progress, s));
private void fillControllers() {
progress.request().sourceInfo().includedSources().forEach(this::fillControllers);
}
private static void fillControllers(final GenerationProgress progress, final SourceInfo info) {
private void fillControllers(final SourceInfo info) {
progress.controllerClassToVariable().put(info.controllerClassName(), progress.getNextVariableName(GenerationHelper.getVariablePrefix(info.controllerClassName())));
info.includedSources().forEach(s -> fillControllers(progress, s));
info.includedSources().forEach(this::fillControllers);
}
private static void fillControllers(final SourceInfo info, final Set<? super String> controllers) {
@@ -136,7 +142,7 @@ public final class ConstructorFormatter {
info.includedSources().forEach(s -> fillControllers(s, controllers));
}
static String formatSubViewConstructorCall(final GenerationProgress progress, final ParsedInclude include) throws GenerationException {
String formatSubViewConstructorCall(final ParsedInclude include) throws GenerationException {
final var request = progress.request();
final var info = request.sourceInfo();
final var subInfo = info.sourceToSourceInfo().get(include.source());
@@ -149,17 +155,17 @@ public final class ConstructorFormatter {
final var subControllers = new HashSet<String>();
subInfo.includedSources().forEach(s -> fillControllers(s, subControllers));
final var arguments = subControllers.stream().sorted().map(c -> getVariableName(progress.controllerClassToVariable().get(c), isFactory)).collect(Collectors.joining(", "));
final var bundleVariable = subInfo.requiresResourceBundle() ? getBundleVariable(progress, include) : null;
final var bundleVariable = subInfo.requiresResourceBundle() ? getBundleVariable(include) : null;
final var argumentList = subControllerVariable + (arguments.isEmpty() ? "" : ", " + arguments) + (bundleVariable == null ? "" : ", " + bundleVariable);
final var subViewName = subInfo.generatedClassName();
final var variable = progress.getNextVariableName(GenerationHelper.getVariablePrefix(subViewName));
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, subViewName)).append(variable).append(" = new ").append(subViewName).append("(").append(argumentList).append(");\n");
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(subViewName)).append(variable).append(" = new ").append(subViewName).append("(").append(argumentList).append(");\n");
return variable;
}
}
private static String getBundleVariable(final GenerationProgress progress, final ParsedInclude include) throws GenerationException {
final var info = getResourceBundleInfo(progress);
private String getBundleVariable(final ParsedInclude include) throws GenerationException {
final var info = getResourceBundleInfo();
if (info.type() == null) {
return null;
} else if (include.resources() == null) {
@@ -167,21 +173,22 @@ public final class ConstructorFormatter {
} else {
final var sb = progress.stringBuilder();
if (progress.request().parameters().resourceInjectionType() instanceof final ResourceBundleInjectionTypes types) {
final var compatibilityHelper = helperProvider.getCompatibilityHelper();
return switch (types) {
case GETTER, GET_BUNDLE -> null;
case CONSTRUCTOR_NAME -> {
final var bundleVariable = progress.getNextVariableName("resourceBundleName");
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "String")).append(bundleVariable).append(" = \"").append(include.resources()).append("\";\n");
sb.append(compatibilityHelper.getStartVar("String")).append(bundleVariable).append(" = \"").append(include.resources()).append("\";\n");
yield bundleVariable;
}
case CONSTRUCTOR_FUNCTION -> {
final var bundleVariable = progress.getNextVariableName("resourceBundleFunction");
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "java.util.function.Function<String, String>")).append(bundleVariable).append(" = (java.util.function.Function<String, String>) s -> \"").append(include.resources()).append("\";\n");
sb.append(compatibilityHelper.getStartVar("java.util.function.Function<String, String>")).append(bundleVariable).append(" = (java.util.function.Function<String, String>) s -> \"").append(include.resources()).append("\";\n");
yield bundleVariable;
}
case CONSTRUCTOR -> {
final var bundleVariable = progress.getNextVariableName("resourceBundle");
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "java.util.ResourceBundle")).append(bundleVariable).append(" = java.util.ResourceBundle.getBundle(\"").append(include.resources()).append("\");\n");
sb.append(compatibilityHelper.getStartVar("java.util.ResourceBundle")).append(bundleVariable).append(" = java.util.ResourceBundle.getBundle(\"").append(include.resources()).append("\");\n");
yield bundleVariable;
}
};

View File

@@ -5,21 +5,27 @@ import com.github.gtache.fxml.compiler.impl.ControllerFieldInjectionTypes;
import com.github.gtache.fxml.compiler.impl.ControllerMethodsInjectionType;
import com.github.gtache.fxml.compiler.impl.ResourceBundleInjectionTypes;
import static java.util.Objects.requireNonNull;
/**
* Formats the load method for the generated code
*/
public final class LoadMethodFormatter {
private LoadMethodFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
LoadMethodFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = requireNonNull(helperProvider);
this.progress = requireNonNull(progress);
}
/**
* Formats the load method
*
* @param progress The generation progress
* @throws GenerationException if an error occurs
*/
public static void formatLoadMethod(final GenerationProgress progress) throws GenerationException {
public void formatLoadMethod() throws GenerationException {
final var request = progress.request();
final var rootObject = request.rootObject();
final var parameters = progress.request().parameters();
@@ -36,23 +42,24 @@ public final class LoadMethodFormatter {
sb.append(" throw new IllegalStateException(\"Already loaded\");\n");
sb.append(" }\n");
final var resourceBundleInjection = parameters.resourceInjectionType();
final var generationCompatibilityHelper = helperProvider.getCompatibilityHelper();
if (resourceBundleInjection == ResourceBundleInjectionTypes.CONSTRUCTOR_NAME) {
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "java.util.ResourceBundle")).append("resourceBundle = java.util.ResourceBundle.getBundle(\"resourceBundleName\");\n");
sb.append(generationCompatibilityHelper.getStartVar("java.util.ResourceBundle")).append("resourceBundle = java.util.ResourceBundle.getBundle(\"resourceBundleName\");\n");
} else if (resourceBundleInjection == ResourceBundleInjectionTypes.GET_BUNDLE && parameters.bundleMap().containsKey(controllerClass)) {
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "java.util.ResourceBundle")).append("resourceBundle = java.util.ResourceBundle.getBundle(\"").append(parameters.bundleMap().get(controllerClass)).append("\");\n");
sb.append(generationCompatibilityHelper.getStartVar("java.util.ResourceBundle")).append("resourceBundle = java.util.ResourceBundle.getBundle(\"").append(parameters.bundleMap().get(controllerClass)).append("\");\n");
}
if (controllerInjectionType == ControllerFieldInjectionTypes.FACTORY) {
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "java.util.Map<String, Object>")).append("fieldMap = new java.util.HashMap<String, Object>();\n");
sb.append(generationCompatibilityHelper.getStartVar("java.util.Map<String, Object>")).append("fieldMap = new java.util.HashMap<String, Object>();\n");
}
final var variableName = progress.getNextVariableName(GenerationHelper.getVariablePrefix(rootObject));
ObjectFormatter.format(progress, rootObject, variableName);
helperProvider.getObjectFormatter().format(rootObject, variableName);
if (controllerInjectionType == ControllerFieldInjectionTypes.FACTORY) {
sb.append(" controller = (").append(controllerClass).append(") controllerFactory.create(fieldMap);\n");
progress.controllerFactoryPostAction().forEach(sb::append);
}
if (parameters.methodInjectionType() == ControllerMethodsInjectionType.REFLECTION) {
sb.append(" try {\n");
sb.append(" ").append(GenerationCompatibilityHelper.getStartVar(progress, "java.lang.reflect.Method", 0)).append("initialize = controller.getClass().getDeclaredMethod(\"initialize\");\n");
sb.append(" ").append(generationCompatibilityHelper.getStartVar("java.lang.reflect.Method", 0)).append("initialize = controller.getClass().getDeclaredMethod(\"initialize\");\n");
sb.append(" initialize.setAccessible(true);\n");
sb.append(" initialize.invoke(controller);\n");
sb.append(" } catch (final java.lang.reflect.InvocationTargetException | IllegalAccessException e) {\n");

View File

@@ -16,6 +16,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.*;
import static java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to format properties
@@ -45,103 +46,106 @@ public final class ObjectFormatter {
"java.lang.Double"
);
private ObjectFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
ObjectFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = requireNonNull(helperProvider);
this.progress = requireNonNull(progress);
}
/**
* Formats an object
*
* @param progress The generation progress
* @param parsedObject The parsed object to format
* @param variableName The variable name for the object
* @throws GenerationException if an error occurs
*/
public static void format(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
public void format(final ParsedObject parsedObject, final String variableName) throws GenerationException {
switch (parsedObject) {
case final ParsedConstant constant -> formatConstant(progress, constant, variableName);
case final ParsedCopy copy -> formatCopy(progress, copy, variableName);
case final ParsedDefine define -> formatDefine(progress, define);
case final ParsedFactory factory -> formatFactory(progress, factory, variableName);
case final ParsedInclude include -> formatInclude(progress, include, variableName);
case final ParsedReference reference -> formatReference(progress, reference, variableName);
case final ParsedValue value -> formatValue(progress, value, variableName);
case final ParsedText text -> formatText(progress, text, variableName);
default -> formatObject(progress, parsedObject, variableName);
case final ParsedConstant constant -> formatConstant(constant, variableName);
case final ParsedCopy copy -> formatCopy(copy, variableName);
case final ParsedDefine define -> formatDefine(define);
case final ParsedFactory factory -> formatFactory(factory, variableName);
case final ParsedInclude include -> formatInclude(include, variableName);
case final ParsedReference reference -> formatReference(reference, variableName);
case final ParsedValue value -> formatValue(value, variableName);
case final ParsedText text -> formatText(text, variableName);
default -> formatObject(parsedObject, variableName);
}
}
/**
* Formats a simple text
*
* @param progress The generation progress
* @param text The parsed text
* @param variableName The variable name
*/
private static void formatText(final GenerationProgress progress, final ParsedText text, final String variableName) {
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, "String")).append(variableName).append(" = \"").append(text.text()).append("\";\n");
private void formatText(final ParsedText text, final String variableName) {
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar("String")).append(variableName).append(" = \"").append(text.text()).append("\";\n");
}
/**
* Formats a basic object
*
* @param progress The generation progress
* @param parsedObject The parsed object to format
* @param variableName The variable name for the object
*/
private static void formatObject(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
private void formatObject(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (BUILDER_CLASSES.contains(parsedObject.className())) {
formatBuilderObject(progress, parsedObject, variableName);
formatBuilderObject(parsedObject, variableName);
} else {
formatNotBuilder(progress, parsedObject, variableName);
formatNotBuilder(parsedObject, variableName);
}
}
/**
* Formats a builder object
*
* @param progress The generation progress
* @param parsedObject The parsed object
* @param variableName The variable name
*/
private static void formatBuilderObject(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
private void formatBuilderObject(final ParsedObject parsedObject, final String variableName) throws GenerationException {
final var className = parsedObject.className();
switch (className) {
case "javafx.scene.Scene" -> SceneFormatter.formatScene(progress, parsedObject, variableName);
case "javafx.scene.text.Font" -> FontFormatter.formatFont(progress, parsedObject, variableName);
case "javafx.scene.image.Image" -> ImageFormatter.formatImage(progress, parsedObject, variableName);
case "java.net.URL" -> URLFormatter.formatURL(progress, parsedObject, variableName);
case "javafx.scene.Scene" -> helperProvider.getSceneFormatter().formatScene(parsedObject, variableName);
case "javafx.scene.text.Font" -> helperProvider.getFontFormatter().formatFont(parsedObject, variableName);
case "javafx.scene.image.Image" ->
helperProvider.getImageFormatter().formatImage(parsedObject, variableName);
case "java.net.URL" -> helperProvider.getURLFormatter().formatURL(parsedObject, variableName);
case "javafx.scene.shape.TriangleMesh" ->
TriangleMeshFormatter.formatTriangleMesh(progress, parsedObject, variableName);
case "javafx.scene.web.WebView" -> WebViewFormatter.formatWebView(progress, parsedObject, variableName);
helperProvider.getTriangleMeshFormatter().formatTriangleMesh(parsedObject, variableName);
case "javafx.scene.web.WebView" ->
helperProvider.getWebViewFormatter().formatWebView(parsedObject, variableName);
default -> throw new IllegalArgumentException("Unknown builder class : " + className);
}
}
private static void formatNotBuilder(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
private void formatNotBuilder(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (isSimpleClass(parsedObject)) {
formatSimpleClass(progress, parsedObject, variableName);
formatSimpleClass(parsedObject, variableName);
} else {
formatComplexClass(progress, parsedObject, variableName);
formatComplexClass(parsedObject, variableName);
}
}
private static void formatSimpleClass(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
private void formatSimpleClass(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (!parsedObject.properties().isEmpty()) {
throw new GenerationException("Simple class cannot have properties : " + parsedObject);
}
if (parsedObject.attributes().keySet().stream().anyMatch(k -> !k.equals(FX_ID) && !k.equals(VALUE) && !k.equals(FX_VALUE))) {
throw new GenerationException("Invalid attributes for simple class : " + parsedObject);
}
final var value = getSimpleValue(progress, parsedObject);
final var valueStr = ValueFormatter.toString(value, ReflectionHelper.getClass(parsedObject.className()));
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, parsedObject)).append(variableName).append(" = ").append(valueStr).append(";\n");
GenerationHelper.handleId(progress, parsedObject, variableName);
final var value = getSimpleValue(parsedObject);
final var valueStr = helperProvider.getValueFormatter().toString(value, ReflectionHelper.getClass(parsedObject.className()));
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(parsedObject)).append(variableName).append(" = ").append(valueStr).append(";\n");
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
}
private static String getSimpleValue(final GenerationProgress progress, final ParsedObject parsedObject) throws GenerationException {
private String getSimpleValue(final ParsedObject parsedObject) throws GenerationException {
final var definedChildren = parsedObject.children().stream().filter(ParsedDefine.class::isInstance).toList();
for (final var definedChild : definedChildren) {
formatObject(progress, definedChild, progress.getNextVariableName("define"));
formatObject(definedChild, progress.getNextVariableName("define"));
}
final var notDefinedChildren = parsedObject.children().stream().filter(c -> !(c instanceof ParsedDefine)).toList();
if (parsedObject.attributes().containsKey(FX_VALUE)) {
@@ -182,7 +186,7 @@ public final class ObjectFormatter {
}
}
private static boolean isSimpleClass(final ParsedObject object) throws GenerationException {
private boolean isSimpleClass(final ParsedObject object) throws GenerationException {
final var className = object.className();
if (SIMPLE_CLASSES.contains(className)) {
return true;
@@ -192,7 +196,7 @@ public final class ObjectFormatter {
}
}
private static void formatComplexClass(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
private void formatComplexClass(final ParsedObject parsedObject, final String variableName) throws GenerationException {
final var clazz = ReflectionHelper.getClass(parsedObject.className());
final var children = parsedObject.children();
final var definedChildren = children.stream().filter(ParsedDefine.class::isInstance).toList();
@@ -202,7 +206,7 @@ public final class ObjectFormatter {
allPropertyNames.addAll(parsedObject.properties().keySet().stream().map(ParsedProperty::name).collect(Collectors.toSet()));
if (!definedChildren.isEmpty()) {
for (final var definedChild : definedChildren) {
format(progress, definedChild, progress.getNextVariableName("define"));
format(definedChild, progress.getNextVariableName("define"));
}
}
if (!notDefinedChildren.isEmpty()) {
@@ -213,31 +217,32 @@ public final class ObjectFormatter {
}
final var constructorArgs = ConstructorHelper.getMatchingConstructorArgs(constructors, allPropertyNames);
if (constructorArgs == null) {
formatNoConstructor(progress, parsedObject, variableName, allPropertyNames);
formatNoConstructor(parsedObject, variableName, allPropertyNames);
} else {
formatConstructor(progress, parsedObject, variableName, constructorArgs);
formatConstructor(parsedObject, variableName, constructorArgs);
}
}
private static void formatNoConstructor(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName, final Collection<String> allPropertyNames) throws GenerationException {
private void formatNoConstructor(final ParsedObject parsedObject, final String variableName, final Collection<String> allPropertyNames) throws GenerationException {
final var clazz = ReflectionHelper.getClass(parsedObject.className());
if (allPropertyNames.size() == 1 && allPropertyNames.iterator().next().equals("fx:constant")) {
final var property = parsedObject.attributes().get("fx:constant");
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, parsedObject)).append(variableName).append(" = ").append(clazz.getCanonicalName()).append(".").append(property.value()).append(";\n");
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(parsedObject)).append(variableName).append(" = ").append(clazz.getCanonicalName()).append(".").append(property.value()).append(";\n");
} else {
throw new GenerationException("Cannot find constructor for " + clazz.getCanonicalName());
}
}
private static void formatConstructor(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName, final ConstructorArgs constructorArgs) throws GenerationException {
final var args = ConstructorHelper.getListConstructorArgs(constructorArgs, parsedObject);
final var genericTypes = ReflectionHelper.getGenericTypes(progress, parsedObject);
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, parsedObject)).append(variableName).append(NEW_ASSIGN).append(parsedObject.className())
private void formatConstructor(final ParsedObject parsedObject, final String variableName, final ConstructorArgs constructorArgs) throws GenerationException {
final var reflectionHelper = helperProvider.getReflectionHelper();
final var args = helperProvider.getConstructorHelper().getListConstructorArgs(constructorArgs, parsedObject);
final var genericTypes = reflectionHelper.getGenericTypes(parsedObject);
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(parsedObject)).append(variableName).append(NEW_ASSIGN).append(parsedObject.className())
.append(genericTypes).append("(").append(String.join(", ", args)).append(");\n");
final var sortedAttributes = getSortedAttributes(parsedObject);
for (final var value : sortedAttributes) {
if (!constructorArgs.namedArgs().containsKey(value.name())) {
PropertyFormatter.formatProperty(progress, value, parsedObject, variableName);
helperProvider.getPropertyFormatter().formatProperty(value, parsedObject, variableName);
}
}
final var sortedProperties = parsedObject.properties().entrySet().stream().sorted(Comparator.comparing(e -> e.getKey().name())).toList();
@@ -245,7 +250,7 @@ public final class ObjectFormatter {
if (!constructorArgs.namedArgs().containsKey(e.getKey().name())) {
final var p = e.getKey();
final var o = e.getValue();
formatChild(progress, parsedObject, p, o, variableName);
formatChild(parsedObject, p, o, variableName);
}
}
final var notDefinedChildren = parsedObject.children().stream().filter(c -> !(c instanceof ParsedDefine)).toList();
@@ -253,7 +258,7 @@ public final class ObjectFormatter {
final var defaultProperty = ReflectionHelper.getDefaultProperty(parsedObject.className());
if (!constructorArgs.namedArgs().containsKey(defaultProperty)) {
final var property = new ParsedPropertyImpl(defaultProperty, null, null);
formatChild(progress, parsedObject, property, notDefinedChildren, variableName);
formatChild(parsedObject, property, notDefinedChildren, variableName);
}
}
}
@@ -261,28 +266,27 @@ public final class ObjectFormatter {
/**
* Formats an include object
*
* @param progress The generation progress
* @param include The include object
* @param subNodeName The sub node name
*/
private static void formatInclude(final GenerationProgress progress, final ParsedInclude include, final String subNodeName) throws GenerationException {
private void formatInclude(final ParsedInclude include, final String subNodeName) throws GenerationException {
final var subViewVariable = progress.getNextVariableName("view");
final var viewVariable = ConstructorFormatter.formatSubViewConstructorCall(progress, include);
final var viewVariable = helperProvider.getInitializationFormatter().formatSubViewConstructorCall(include);
progress.stringBuilder().append(" final javafx.scene.Parent ").append(subNodeName).append(" = ").append(viewVariable).append(".load();\n");
injectSubController(progress, include, subViewVariable);
injectSubController(include, subViewVariable);
}
private static void injectSubController(final GenerationProgress progress, final ParsedInclude include, final String subViewVariable) throws GenerationException {
private void injectSubController(final ParsedInclude include, final String subViewVariable) throws GenerationException {
final var id = include.controllerId();
if (id != null) {
final var subControllerVariable = progress.getNextVariableName("controller");
final var controllerClass = progress.request().sourceInfo().sourceToSourceInfo().get(include.source()).controllerClassName();
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, controllerClass)).append(subControllerVariable).append(" = ").append(subViewVariable).append(".controller();\n");
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(controllerClass)).append(subControllerVariable).append(" = ").append(subViewVariable).append(".controller();\n");
progress.idToVariableInfo().put(id, new VariableInfo(id, include, subControllerVariable, controllerClass));
if (progress.request().controllerInfo().fieldInfo(id) == null) {
logger.debug("Not injecting {} because it is not found in controller", id);
} else {
ControllerInjector.injectControllerField(progress, id, subControllerVariable);
helperProvider.getControllerInjector().injectControllerField(id, subControllerVariable);
}
}
}
@@ -290,93 +294,88 @@ public final class ObjectFormatter {
/**
* Formats a fx:define
*
* @param progress The generation progress
* @param define The parsed define
* @throws GenerationException if an error occurs
*/
private static void formatDefine(final GenerationProgress progress, final ParsedObject define) throws GenerationException {
private void formatDefine(final ParsedObject define) throws GenerationException {
for (final var child : define.children()) {
format(progress, child, progress.getNextVariableName("definedObject"));
format(child, progress.getNextVariableName("definedObject"));
}
}
/**
* Formats a fx:reference
*
* @param progress The generation progress
* @param reference The parsed reference
* @throws GenerationException if an error occurs
*/
private static void formatReference(final GenerationProgress progress, final ParsedReference reference, final String variableName) throws GenerationException {
private void formatReference(final ParsedReference reference, final String variableName) throws GenerationException {
final var id = reference.source();
final var variableInfo = progress.idToVariableInfo().get(id);
if (variableInfo == null) {
throw new GenerationException("Unknown id : " + id);
}
final var referenceName = variableInfo.variableName();
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, variableInfo.className())).append(variableName).append(" = ").append(referenceName).append(";\n");
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(variableInfo.className())).append(variableName).append(" = ").append(referenceName).append(";\n");
}
/**
* Formats a fx:copy
*
* @param progress The generation progress
* @param copy The parsed copy
* @param variableName The variable name
* @throws GenerationException if an error occurs
*/
private static void formatCopy(final GenerationProgress progress, final ParsedCopy copy, final String variableName) throws GenerationException {
private void formatCopy(final ParsedCopy copy, final String variableName) throws GenerationException {
final var id = copy.source();
final var variableInfo = progress.idToVariableInfo().get(id);
if (variableInfo == null) {
throw new GenerationException("Unknown id : " + id);
}
final var copyVariable = variableInfo.variableName();
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, variableInfo.className())).append(variableName).append(NEW_ASSIGN).append(variableInfo.className()).append("(").append(copyVariable).append(");\n");
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(variableInfo.className())).append(variableName).append(NEW_ASSIGN).append(variableInfo.className()).append("(").append(copyVariable).append(");\n");
}
/**
* Formats a constant object
*
* @param progress The generation progress
* @param constant The constant
* @param variableName The variable name
*/
private static void formatConstant(final GenerationProgress progress, final ParsedConstant constant, final String variableName) {
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, constant.className())).append(variableName).append(" = ").append(constant.className()).append(".").append(constant.constant()).append(";\n");
private void formatConstant(final ParsedConstant constant, final String variableName) throws GenerationException {
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(constant.className())).append(variableName).append(" = ").append(constant.className()).append(".").append(constant.constant()).append(";\n");
}
/**
* Formats a value object
*
* @param progress The generation progress
* @param value The value
* @param variableName The variable name
*/
private static void formatValue(final GenerationProgress progress, final ParsedValue value, final String variableName) {
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, value.className())).append(variableName).append(" = ").append(value.className()).append(".valueOf(\"").append(value.value()).append("\");\n");
private void formatValue(final ParsedValue value, final String variableName) throws GenerationException {
progress.stringBuilder().append(helperProvider.getCompatibilityHelper().getStartVar(value.className())).append(variableName).append(" = ").append(value.className()).append(".valueOf(\"").append(value.value()).append("\");\n");
}
/**
* Formats a factory object
*
* @param progress The generation progress
* @param factory The factory
* @param variableName The variable name
*/
private static void formatFactory(final GenerationProgress progress, final ParsedFactory factory, final String variableName) throws GenerationException {
private void formatFactory(final ParsedFactory factory, final String variableName) throws GenerationException {
final var variables = new ArrayList<String>();
for (final var argument : factory.arguments()) {
final var argumentVariable = progress.getNextVariableName("arg");
variables.add(argumentVariable);
format(progress, argument, argumentVariable);
format(argument, argumentVariable);
}
final var compatibilityHelper = helperProvider.getCompatibilityHelper();
if (progress.request().parameters().compatibility().useVar()) {
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, factory.className())).append(variableName).append(" = ").append(factory.className())
progress.stringBuilder().append(compatibilityHelper.getStartVar(factory.className())).append(variableName).append(" = ").append(factory.className())
.append(".").append(factory.factory()).append("(").append(String.join(", ", variables)).append(");\n");
} else {
final var returnType = ReflectionHelper.getReturnType(factory.className(), factory.factory());
progress.stringBuilder().append(GenerationCompatibilityHelper.getStartVar(progress, returnType)).append(variableName).append(" = ").append(factory.className())
progress.stringBuilder().append(compatibilityHelper.getStartVar(returnType)).append(variableName).append(" = ").append(factory.className())
.append(".").append(factory.factory()).append("(").append(String.join(", ", variables)).append(");\n");
}
}
@@ -384,45 +383,43 @@ public final class ObjectFormatter {
/**
* Formats the children objects of a property
*
* @param progress The generation progress
* @param parent The parent object
* @param property The parent property
* @param objects The child objects
* @param parentVariable The parent object variable
*/
private static void formatChild(final GenerationProgress progress, final ParsedObject parent, final ParsedProperty property,
private void formatChild(final ParsedObject parent, final ParsedProperty property,
final Iterable<? extends ParsedObject> objects, final String parentVariable) throws GenerationException {
final var propertyName = property.name();
final var variables = new ArrayList<String>();
for (final var object : objects) {
final var vn = progress.getNextVariableName(GenerationHelper.getVariablePrefix(object));
format(progress, object, vn);
final var vn = progress.getNextVariableName(getVariablePrefix(object));
format(object, vn);
if (!(object instanceof ParsedDefine)) {
variables.add(vn);
}
}
if (variables.size() > 1) {
formatMultipleChildren(progress, variables, propertyName, parent, parentVariable);
formatMultipleChildren(variables, propertyName, parent, parentVariable);
} else if (variables.size() == 1) {
final var vn = variables.getFirst();
formatSingleChild(progress, vn, property, parent, parentVariable);
formatSingleChild(vn, property, parent, parentVariable);
}
}
/**
* Formats children objects given that they are more than one
*
* @param progress The generation progress
* @param variables The children variables
* @param propertyName The property name
* @param parent The parent object
* @param parentVariable The parent object variable
*/
private static void formatMultipleChildren(final GenerationProgress progress, final Iterable<String> variables, final String propertyName, final ParsedObject parent,
private void formatMultipleChildren(final Iterable<String> variables, final String propertyName, final ParsedObject parent,
final String parentVariable) throws GenerationException {
final var getMethod = GenerationHelper.getGetMethod(propertyName);
final var getMethod = getGetMethod(propertyName);
if (ReflectionHelper.hasMethod(ReflectionHelper.getClass(parent.className()), getMethod)) {
progress.stringBuilder().append(" ").append(parentVariable).append(".").append(getMethod).append("().addAll(").append(GenerationCompatibilityHelper.getListOf(progress)).append(String.join(", ", variables)).append("));\n");
progress.stringBuilder().append(" ").append(parentVariable).append(".").append(getMethod).append("().addAll(").append(helperProvider.getCompatibilityHelper().getListOf()).append(String.join(", ", variables)).append("));\n");
} else {
throw getCannotSetException(propertyName, parent.className());
}
@@ -431,42 +428,40 @@ public final class ObjectFormatter {
/**
* Formats a single child object
*
* @param progress The generation progress
* @param variableName The child's variable name
* @param property The parent property
* @param parent The parent object
* @param parentVariable The parent object variable
*/
private static void formatSingleChild(final GenerationProgress progress, final String variableName, final ParsedProperty property, final ParsedObject parent,
private void formatSingleChild(final String variableName, final ParsedProperty property, final ParsedObject parent,
final String parentVariable) throws GenerationException {
if (property.sourceType() == null) {
formatSingleChildInstance(progress, variableName, property, parent, parentVariable);
formatSingleChildInstance(variableName, property, parent, parentVariable);
} else {
formatSingleChildStatic(progress, variableName, property, parentVariable);
formatSingleChildStatic(variableName, property, parentVariable);
}
}
/**
* Formats a single child object using an instance method on the parent object
*
* @param progress The generation progress
* @param variableName The child's variable name
* @param property The parent property
* @param parent The parent object
* @param parentVariable The parent object variable
*/
private static void formatSingleChildInstance(final GenerationProgress progress, final String variableName,
private void formatSingleChildInstance(final String variableName,
final ParsedProperty property, final ParsedObject parent,
final String parentVariable) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property);
final var getMethod = GenerationHelper.getGetMethod(property);
final var setMethod = getSetMethod(property);
final var getMethod = getGetMethod(property);
final var parentClass = ReflectionHelper.getClass(parent.className());
final var sb = progress.stringBuilder();
if (ReflectionHelper.hasMethod(parentClass, setMethod)) {
sb.append(" ").append(parentVariable).append(".").append(setMethod).append("(").append(variableName).append(");\n");
} else if (ReflectionHelper.hasMethod(parentClass, getMethod)) {
//Probably a list method that has only one element
sb.append(" ").append(parentVariable).append(".").append(getMethod).append("().addAll(").append(GenerationCompatibilityHelper.getListOf(progress)).append(variableName).append("));\n");
sb.append(" ").append(parentVariable).append(".").append(getMethod).append("().addAll(").append(helperProvider.getCompatibilityHelper().getListOf()).append(variableName).append("));\n");
} else {
throw getCannotSetException(property.name(), parent.className());
}
@@ -475,14 +470,13 @@ public final class ObjectFormatter {
/**
* Formats a child object using a static method
*
* @param progress The generation progress
* @param variableName The child's variable name
* @param property The parent property
* @param parentVariable The parent variable
*/
private static void formatSingleChildStatic(final GenerationProgress progress, final String variableName,
private void formatSingleChildStatic(final String variableName,
final ParsedProperty property, final String parentVariable) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property);
final var setMethod = getSetMethod(property);
if (ReflectionHelper.hasStaticMethod(ReflectionHelper.getClass(property.sourceType()), setMethod)) {
progress.stringBuilder().append(" ").append(property.sourceType()).append(".").append(setMethod)
.append("(").append(parentVariable).append(", ").append(variableName).append(");\n");

View File

@@ -12,107 +12,112 @@ import java.util.Objects;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.FX_ID;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.RESOURCE_KEY_PREFIX;
import static java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to format properties
*/
final class PropertyFormatter {
private PropertyFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
PropertyFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = requireNonNull(helperProvider);
this.progress = requireNonNull(progress);
}
/**
* Formats a property
*
* @param progress The generation progress
* @param property The property to format
* @param parent The property's parent object
* @param parentVariable The parent variable
* @throws GenerationException if an error occurs
*/
static void formatProperty(final GenerationProgress progress, final ParsedProperty property, final ParsedObject parent, final String parentVariable) throws GenerationException {
void formatProperty(final ParsedProperty property, final ParsedObject parent, final String parentVariable) throws GenerationException {
final var propertyName = property.name();
if (propertyName.equals(FX_ID)) {
GenerationHelper.handleId(progress, parent, parentVariable);
helperProvider.getGenerationHelper().handleId(parent, parentVariable);
} else if (propertyName.equals("fx:controller")) {
checkDuplicateController(progress, parent);
checkDuplicateController(parent);
} else if (Objects.equals(property.sourceType(), EventHandler.class.getName())) {
handleEventHandler(progress, property, parentVariable);
handleEventHandler(property, parentVariable);
} else if (property.sourceType() != null) {
handleStaticProperty(progress, property, parentVariable, propertyName);
handleStaticProperty(property, parentVariable, propertyName);
} else {
handleProperty(progress, property, parent, parentVariable);
handleProperty(property, parent, parentVariable);
}
}
private static void checkDuplicateController(final GenerationProgress progress, final ParsedObject parent) throws GenerationException {
private void checkDuplicateController(final ParsedObject parent) throws GenerationException {
if (parent != progress.request().rootObject()) {
throw new GenerationException("Invalid nested controller");
}
}
private static void handleEventHandler(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) throws GenerationException {
private void handleEventHandler(final ParsedProperty property, final String parentVariable) throws GenerationException {
if (property.value().startsWith("#")) {
ControllerInjector.injectEventHandlerControllerMethod(progress, property, parentVariable);
helperProvider.getControllerInjector().injectEventHandlerControllerMethod(property, parentVariable);
} else {
FieldSetter.setEventHandler(progress, property, parentVariable);
helperProvider.getFieldSetter().setEventHandler(property, parentVariable);
}
}
private static void handleStaticProperty(final GenerationProgress progress, final ParsedProperty property, final String parentVariable, final String propertyName) throws GenerationException {
private void handleStaticProperty(final ParsedProperty property, final String parentVariable, final String propertyName) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(propertyName);
final var propertySourceTypeClass = ReflectionHelper.getClass(property.sourceType());
if (ReflectionHelper.hasStaticMethod(propertySourceTypeClass, setMethod)) {
final var method = ReflectionHelper.getStaticMethod(propertySourceTypeClass, setMethod);
final var parameterType = method.getParameterTypes()[1];
final var arg = ValueFormatter.getArg(progress, property.value(), parameterType);
setLaterIfNeeded(progress, property, parameterType, " " + property.sourceType() + "." + setMethod + "(" + parentVariable + ", " + arg + ");\n");
final var arg = helperProvider.getValueFormatter().getArg(property.value(), parameterType);
setLaterIfNeeded(property, parameterType, " " + property.sourceType() + "." + setMethod + "(" + parentVariable + ", " + arg + ");\n");
} else {
throw new GenerationException("Cannot set " + propertyName + " on " + property.sourceType());
}
}
private static void handleProperty(final GenerationProgress progress, final ParsedProperty property, final ParsedObject parent, final String parentVariable) throws GenerationException {
private void handleProperty(final ParsedProperty property, final ParsedObject parent, final String parentVariable) throws GenerationException {
final var propertyName = property.name();
final var setMethod = GenerationHelper.getSetMethod(propertyName);
final var getMethod = GenerationHelper.getGetMethod(propertyName);
final var parentClass = ReflectionHelper.getClass(parent.className());
if (ReflectionHelper.hasMethod(parentClass, setMethod)) {
handleSetProperty(progress, property, parentClass, parentVariable);
handleSetProperty(property, parentClass, parentVariable);
} else if (ReflectionHelper.hasMethod(parentClass, getMethod)) {
handleGetProperty(progress, property, parentClass, parentVariable);
handleGetProperty(property, parentClass, parentVariable);
} else {
throw new GenerationException("Cannot set " + propertyName + " on " + parent.className());
}
}
private static void handleSetProperty(final GenerationProgress progress, final ParsedProperty property, final Class<?> parentClass, final String parentVariable) throws GenerationException {
private void handleSetProperty(final ParsedProperty property, final Class<?> parentClass, final String parentVariable) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property.name());
final var method = ReflectionHelper.getMethod(parentClass, setMethod);
final var parameterType = method.getParameterTypes()[0];
final var arg = ValueFormatter.getArg(progress, property.value(), parameterType);
setLaterIfNeeded(progress, property, parameterType, " " + parentVariable + "." + setMethod + "(" + arg + ");\n");
final var arg = helperProvider.getValueFormatter().getArg(property.value(), parameterType);
setLaterIfNeeded(property, parameterType, " " + parentVariable + "." + setMethod + "(" + arg + ");\n");
}
private static void handleGetProperty(final GenerationProgress progress, final ParsedProperty property, final Class<?> parentClass, final String parentVariable) throws GenerationException {
private void handleGetProperty(final ParsedProperty property, final Class<?> parentClass, final String parentVariable) throws GenerationException {
final var getMethod = GenerationHelper.getGetMethod(property.name());
final var method = ReflectionHelper.getMethod(parentClass, getMethod);
final var returnType = method.getReturnType();
if (ReflectionHelper.hasMethod(returnType, "addAll")) {
final var arg = ValueFormatter.getArg(progress, property.value(), String.class);
setLaterIfNeeded(progress, property, String.class, " " + parentVariable + "." + getMethod + "().addAll(" + GenerationCompatibilityHelper.getListOf(progress) + arg + "));\n");
final var arg = helperProvider.getValueFormatter().getArg(property.value(), String.class);
setLaterIfNeeded(property, String.class, " " + parentVariable + "." + getMethod + "().addAll(" + helperProvider.getCompatibilityHelper().getListOf() + arg + "));\n");
}
}
/**
* Saves the text to set after constructor creation if factory injection is used
*
* @param progress The generation progress
* @param property The property
* @param type The type
* @param arg The argument
*/
private static void setLaterIfNeeded(final GenerationProgress progress, final ParsedProperty property, final Class<?> type, final String arg) {
private void setLaterIfNeeded(final ParsedProperty property, final Class<?> type, final String arg) {
final var parameters = progress.request().parameters();
if (type == String.class && property.value().startsWith(RESOURCE_KEY_PREFIX) && parameters.resourceInjectionType() == ResourceBundleInjectionTypes.GETTER
&& parameters.fieldInjectionType() == ControllerFieldInjectionTypes.FACTORY) {

View File

@@ -1,5 +1,6 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.ControllerInfo;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.GenericTypes;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
@@ -18,6 +19,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,8 +47,10 @@ final class ReflectionHelper {
"float", float.class,
"double", double.class
);
private final ControllerInfo controllerInfo;
private ReflectionHelper() {
ReflectionHelper(final ControllerInfo controllerInfo) {
this.controllerInfo = Objects.requireNonNull(controllerInfo);
}
/**
@@ -323,12 +327,11 @@ final class ReflectionHelper {
/**
* Gets the generic types for the given object
*
* @param progress The generation progress
* @param parsedObject The parsed object
* @return The generic types
* @throws GenerationException if an error occurs
*/
static String getGenericTypes(final GenerationProgress progress, final ParsedObject parsedObject) throws GenerationException {
String getGenericTypes(final ParsedObject parsedObject) throws GenerationException {
final var clazz = getClass(parsedObject.className());
if (isGeneric(clazz)) {
final var idProperty = parsedObject.attributes().get(FX_ID);
@@ -337,7 +340,7 @@ final class ReflectionHelper {
return "";
} else {
final var id = idProperty.value();
final var fieldInfo = progress.request().controllerInfo().fieldInfo(id);
final var fieldInfo = controllerInfo.fieldInfo(id);
if (fieldInfo == null) { //Not found
logger.warn("No field found for generic class {} (id={}) ; Using raw", clazz.getName(), id);
return "";

View File

@@ -10,19 +10,25 @@ import java.util.Collection;
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 java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to format Scenes
*/
final class SceneFormatter {
private SceneFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
SceneFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = requireNonNull(helperProvider);
this.progress = requireNonNull(progress);
}
static void formatScene(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void formatScene(final ParsedObject parsedObject, final String variableName) throws GenerationException {
final var root = findRoot(parsedObject);
final var rootVariableName = progress.getNextVariableName("root");
ObjectFormatter.format(progress, root, rootVariableName);
helperProvider.getObjectFormatter().format(root, rootVariableName);
final var sortedAttributes = getSortedAttributes(parsedObject);
double width = -1;
double height = -1;
@@ -41,10 +47,10 @@ final class SceneFormatter {
}
}
final var sb = progress.stringBuilder();
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.Scene")).append(variableName).append(" = new javafx.scene.Scene(").append(rootVariableName).append(", ")
sb.append(helperProvider.getCompatibilityHelper().getStartVar("javafx.scene.Scene")).append(variableName).append(" = new javafx.scene.Scene(").append(rootVariableName).append(", ")
.append(width).append(", ").append(height).append(", javafx.scene.paint.Color.valueOf(\"").append(paint).append("\"));\n");
addStylesheets(progress, variableName, stylesheets);
GenerationHelper.handleId(progress, parsedObject, variableName);
addStylesheets(variableName, stylesheets);
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
}
private static ParsedObject findRoot(final ParsedObject parsedObject) throws GenerationException {
@@ -60,13 +66,14 @@ final class SceneFormatter {
}
}
private static void addStylesheets(final GenerationProgress progress, final String variableName, final Collection<String> stylesheets) {
private void addStylesheets(final String variableName, final Collection<String> stylesheets) throws GenerationException {
if (!stylesheets.isEmpty()) {
final var urlVariables = URLFormatter.formatURL(progress, stylesheets);
final var urlVariables = helperProvider.getURLFormatter().formatURL(stylesheets);
final var tmpVariable = progress.getNextVariableName("stylesheets");
final var sb = progress.stringBuilder();
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "java.util.List<String>")).append(tmpVariable).append(" = ").append(variableName).append(".getStyleSheets();\n");
sb.append(" ").append(tmpVariable).append(".addAll(").append(GenerationCompatibilityHelper.getListOf(progress)).append(String.join(", ", urlVariables)).append("));\n");
final var compatibilityHelper = helperProvider.getCompatibilityHelper();
sb.append(compatibilityHelper.getStartVar("java.util.List<String>")).append(tmpVariable).append(" = ").append(variableName).append(".getStyleSheets();\n");
sb.append(" ").append(tmpVariable).append(".addAll(").append(compatibilityHelper.getListOf()).append(String.join(", ", urlVariables)).append("));\n");
}
}
}

View File

@@ -16,16 +16,22 @@ 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 java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to format TriangleMeshes
*/
final class TriangleMeshFormatter {
private TriangleMeshFormatter() {
private final HelperProvider helperProvider;
private final StringBuilder sb;
TriangleMeshFormatter(final HelperProvider helperProvider, final StringBuilder sb) {
this.helperProvider = requireNonNull(helperProvider);
this.sb = requireNonNull(sb);
}
static void formatTriangleMesh(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void formatTriangleMesh(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (parsedObject.children().isEmpty() && parsedObject.properties().isEmpty()) {
final var sortedAttributes = getSortedAttributes(parsedObject);
final var points = new ArrayList<Float>();
@@ -63,15 +69,14 @@ final class TriangleMeshFormatter {
default -> throw new GenerationException("Unknown TriangleMesh attribute : " + property.name());
}
}
final var sb = progress.stringBuilder();
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.shape.TriangleMesh")).append(variableName).append(" = new javafx.scene.shape.TriangleMesh();\n");
setPoints(progress, variableName, points);
setTexCoords(progress, variableName, texCoords);
setNormals(progress, variableName, normals);
setFaces(progress, variableName, faces);
setFaceSmoothingGroups(progress, variableName, faceSmoothingGroups);
setVertexFormat(progress, variableName, vertexFormat);
GenerationHelper.handleId(progress, parsedObject, variableName);
sb.append(helperProvider.getCompatibilityHelper().getStartVar("javafx.scene.shape.TriangleMesh")).append(variableName).append(" = new javafx.scene.shape.TriangleMesh();\n");
setPoints(variableName, points);
setTexCoords(variableName, texCoords);
setNormals(variableName, normals);
setFaces(variableName, faces);
setFaceSmoothingGroups(variableName, faceSmoothingGroups);
setVertexFormat(variableName, vertexFormat);
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
} else {
throw new GenerationException("Image cannot have children or properties : " + parsedObject);
}
@@ -87,39 +92,39 @@ final class TriangleMeshFormatter {
}
}
private static void setPoints(final GenerationProgress progress, final String variableName, final Collection<Float> points) {
private void setPoints(final String variableName, final Collection<Float> points) {
if (!points.isEmpty()) {
progress.stringBuilder().append(" ").append(variableName).append(".getPoints().setAll(new float[]{").append(formatList(points)).append("});\n");
sb.append(" ").append(variableName).append(".getPoints().setAll(new float[]{").append(formatList(points)).append("});\n");
}
}
private static void setTexCoords(final GenerationProgress progress, final String variableName, final Collection<Float> texCoords) {
private void setTexCoords(final String variableName, final Collection<Float> texCoords) {
if (!texCoords.isEmpty()) {
progress.stringBuilder().append(" ").append(variableName).append(".getTexCoords().setAll(new float[]{").append(formatList(texCoords)).append("});\n");
sb.append(" ").append(variableName).append(".getTexCoords().setAll(new float[]{").append(formatList(texCoords)).append("});\n");
}
}
private static void setNormals(final GenerationProgress progress, final String variableName, final Collection<Float> normals) {
private void setNormals(final String variableName, final Collection<Float> normals) {
if (!normals.isEmpty()) {
progress.stringBuilder().append(" ").append(variableName).append(".getNormals().setAll(new float[]{").append(formatList(normals)).append("});\n");
sb.append(" ").append(variableName).append(".getNormals().setAll(new float[]{").append(formatList(normals)).append("});\n");
}
}
private static void setFaces(final GenerationProgress progress, final String variableName, final Collection<Integer> faces) {
private void setFaces(final String variableName, final Collection<Integer> faces) {
if (!faces.isEmpty()) {
progress.stringBuilder().append(" ").append(variableName).append(".getFaces().setAll(new int[]{").append(formatList(faces)).append("});\n");
sb.append(" ").append(variableName).append(".getFaces().setAll(new int[]{").append(formatList(faces)).append("});\n");
}
}
private static void setFaceSmoothingGroups(final GenerationProgress progress, final String variableName, final Collection<Integer> faceSmoothingGroups) {
private void setFaceSmoothingGroups(final String variableName, final Collection<Integer> faceSmoothingGroups) {
if (!faceSmoothingGroups.isEmpty()) {
progress.stringBuilder().append(" ").append(variableName).append(".getFaceSmoothingGroups().setAll(new int[]{").append(formatList(faceSmoothingGroups)).append("});\n");
sb.append(" ").append(variableName).append(".getFaceSmoothingGroups().setAll(new int[]{").append(formatList(faceSmoothingGroups)).append("});\n");
}
}
private static void setVertexFormat(final GenerationProgress progress, final String variableName, final VertexFormat vertexFormat) {
private void setVertexFormat(final String variableName, final VertexFormat vertexFormat) {
if (vertexFormat != null) {
progress.stringBuilder().append(" ").append(variableName).append(".setVertexFormat(javafx.scene.shape.VertexFormat.").append(vertexFormat).append(");\n");
sb.append(" ").append(variableName).append(".setVertexFormat(javafx.scene.shape.VertexFormat.").append(vertexFormat).append(");\n");
}
}
@@ -132,5 +137,4 @@ final class TriangleMeshFormatter {
final var split = splitPattern.split(value);
return Arrays.stream(split).map(parser).collect(Collectors.toList());
}
}

View File

@@ -4,10 +4,11 @@ import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.*;
import static java.util.Objects.requireNonNull;
/**
@@ -15,18 +16,27 @@ import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.*;
*/
final class URLFormatter {
private URLFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
URLFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = requireNonNull(helperProvider);
this.progress = requireNonNull(progress);
}
static List<String> formatURL(final GenerationProgress progress, final Collection<String> stylesheets) {
return stylesheets.stream().map(s -> formatURL(progress, s)).toList();
List<String> formatURL(final Iterable<String> stylesheets) {
final var ret = new ArrayList<String>();
for (final var styleSheet : stylesheets) {
ret.add(formatURL(styleSheet));
}
return ret;
}
static String formatURL(final GenerationProgress progress, final String url) {
String formatURL(final String url) {
final var variableName = progress.getNextVariableName("url");
final var sb = progress.stringBuilder();
if (url.startsWith(RELATIVE_PATH_PREFIX)) {
sb.append(getStartURL(progress)).append(variableName).append(" = getClass().getResource(\"").append(url.substring(1)).append("\");\n");
sb.append(getStartURL()).append(variableName).append(" = getClass().getResource(\"").append(url.substring(1)).append("\");\n");
} else {
sb.append(" final java.net.URL ").append(variableName).append(";\n");
sb.append(" try {\n");
@@ -38,7 +48,7 @@ final class URLFormatter {
return variableName;
}
static void formatURL(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void formatURL(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (parsedObject.children().isEmpty() && parsedObject.properties().isEmpty()) {
final var sortedAttributes = getSortedAttributes(parsedObject);
String value = null;
@@ -51,14 +61,15 @@ final class URLFormatter {
default -> throw new GenerationException("Unknown URL attribute : " + property.name());
}
}
progress.stringBuilder().append(getStartURL(progress)).append(variableName).append(" = getClass().getResource(\"").append(value).append("\");\n");
handleId(progress, parsedObject, variableName);
//FIXME only relative path (@) ?
progress.stringBuilder().append(getStartURL()).append(variableName).append(" = getClass().getResource(\"").append(value).append("\");\n");
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
} else {
throw new GenerationException("URL cannot have children or properties : " + parsedObject);
}
}
private static String getStartURL(final GenerationProgress progress) {
return GenerationCompatibilityHelper.getStartVar(progress, "java.net.URL");
private String getStartURL() {
return helperProvider.getCompatibilityHelper().getStartVar("java.net.URL");
}
}

View File

@@ -1,12 +1,15 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.InjectionType;
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
import com.github.gtache.fxml.compiler.impl.ResourceBundleInjectionTypes;
import java.util.Map;
import java.util.regex.Pattern;
import static com.github.gtache.fxml.compiler.impl.internal.GenerationHelper.*;
import static java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to format values
@@ -17,28 +20,32 @@ final class ValueFormatter {
private static final Pattern DECIMAL_PATTERN = Pattern.compile("\\d+(?:\\.\\d+)?");
private static final Pattern START_BACKSLASH_PATTERN = Pattern.compile("^\\\\");
private ValueFormatter() {
private final InjectionType resourceInjectionType;
private final Map<String, VariableInfo> idToVariableInfo;
ValueFormatter(final InjectionType resourceInjectionType, final Map<String, VariableInfo> idToVariableInfo) {
this.resourceInjectionType = requireNonNull(resourceInjectionType);
this.idToVariableInfo = requireNonNull(idToVariableInfo);
}
/**
* Formats an argument to a method
*
* @param progress The generation progress
* @param value The value
* @param parameterType The parameter type
* @return The formatted value
* @throws GenerationException if an error occurs
*/
static String getArg(final GenerationProgress progress, final String value, final Class<?> parameterType) throws GenerationException {
String getArg(final String value, final Class<?> parameterType) throws GenerationException {
if (parameterType == String.class && value.startsWith(RESOURCE_KEY_PREFIX)) {
return getBundleValue(progress, value.substring(1));
return getBundleValue(value.substring(1));
} else if (value.startsWith(RELATIVE_PATH_PREFIX)) {
final var subpath = value.substring(1);
return getResourceValue(subpath);
} else if (value.startsWith(BINDING_EXPRESSION_PREFIX)) {
throw new UnsupportedOperationException("Not implemented yet");
throw new GenerationException("Not implemented yet");
} else if (value.startsWith(EXPRESSION_PREFIX)) {
final var variable = progress.idToVariableInfo().get(value.substring(1));
final var variable = idToVariableInfo.get(value.substring(1));
if (variable == null) {
throw new GenerationException("Unknown variable : " + value.substring(1));
}
@@ -55,21 +62,19 @@ final class ValueFormatter {
/**
* Gets the resource bundle value for the given value
*
* @param progress The generation progress
* @param value The value
* @return The resource bundle value
* @throws GenerationException if an error occurs
*/
private static String getBundleValue(final GenerationProgress progress, final String value) throws GenerationException {
final var resourceBundleInjectionType = progress.request().parameters().resourceInjectionType();
if (resourceBundleInjectionType instanceof final ResourceBundleInjectionTypes types) {
private String getBundleValue(final String value) throws GenerationException {
if (resourceInjectionType instanceof final ResourceBundleInjectionTypes types) {
return switch (types) {
case CONSTRUCTOR, GET_BUNDLE, CONSTRUCTOR_NAME -> "resourceBundle.getString(\"" + value + "\")";
case GETTER -> "controller.resources().getString(\"" + value + "\")";
case CONSTRUCTOR_FUNCTION -> "resourceBundleFunction.apply(\"" + value + "\")";
};
} else {
throw new GenerationException("Unknown resource bundle injection type : " + resourceBundleInjectionType);
throw new GenerationException("Unknown resource bundle injection type : " + resourceInjectionType);
}
}
@@ -81,9 +86,10 @@ final class ValueFormatter {
* @param clazz The value class
* @return The computed string value
*/
static String toString(final String value, final Class<?> clazz) {
String toString(final String value, final Class<?> clazz) {
if (clazz == String.class) {
return "\"" + START_BACKSLASH_PATTERN.matcher(value).replaceAll("").replace("\"", "\\\"") + "\"";
return "\"" + START_BACKSLASH_PATTERN.matcher(value).replaceAll("").replace("\\", "\\\\")
.replace("\"", "\\\"") + "\"";
} else if (clazz == char.class || clazz == Character.class) {
return "'" + value + "'";
} else if (clazz == boolean.class || clazz == Boolean.class) {

View File

@@ -7,88 +7,94 @@ import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
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 java.util.Objects.requireNonNull;
/**
* Helper methods for {@link GeneratorImpl} to format WebViews
*/
final class WebViewFormatter {
private WebViewFormatter() {
private final HelperProvider helperProvider;
private final GenerationProgress progress;
WebViewFormatter(final HelperProvider helperProvider, final GenerationProgress progress) {
this.helperProvider = requireNonNull(helperProvider);
this.progress = requireNonNull(progress);
}
/**
* Formats a WebView object
*
* @param progress The generation progress
* @param parsedObject The parsed object
* @param variableName The variable name
* @throws GenerationException if an error occurs
*/
static void formatWebView(final GenerationProgress progress, final ParsedObject parsedObject, final String variableName) throws GenerationException {
void formatWebView(final ParsedObject parsedObject, final String variableName) throws GenerationException {
if (parsedObject.children().isEmpty() && parsedObject.properties().isEmpty()) {
final var sortedAttributes = getSortedAttributes(parsedObject);
final var sb = progress.stringBuilder();
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.web.WebView")).append(variableName).append(" = new javafx.scene.web.WebView();\n");
final var compatibilityHelper = helperProvider.getCompatibilityHelper();
sb.append(compatibilityHelper.getStartVar("javafx.scene.web.WebView")).append(variableName).append(" = new javafx.scene.web.WebView();\n");
final var engineVariable = progress.getNextVariableName("engine");
sb.append(GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.web.WebEngine")).append(engineVariable).append(" = ").append(variableName).append(".getEngine();\n");
sb.append(compatibilityHelper.getStartVar("javafx.scene.web.WebEngine")).append(engineVariable).append(" = ").append(variableName).append(".getEngine();\n");
for (final var value : sortedAttributes) {
formatAttribute(progress, value, parsedObject, variableName, engineVariable);
formatAttribute(value, parsedObject, variableName, engineVariable);
}
GenerationHelper.handleId(progress, parsedObject, variableName);
helperProvider.getGenerationHelper().handleId(parsedObject, variableName);
} else {
throw new GenerationException("WebView cannot have children or properties : " + parsedObject);
}
}
private static void formatAttribute(final GenerationProgress progress, final ParsedProperty value, final ParsedObject parsedObject,
private void formatAttribute(final ParsedProperty value, final ParsedObject parsedObject,
final String variableName, final String engineVariable) throws GenerationException {
switch (value.name()) {
case FX_ID -> {
//Do nothing
}
case "confirmHandler" -> injectConfirmHandler(progress, value, engineVariable);
case "createPopupHandler" -> injectCreatePopupHandler(progress, value, engineVariable);
case "confirmHandler" -> injectConfirmHandler(value, engineVariable);
case "createPopupHandler" -> injectCreatePopupHandler(value, engineVariable);
case "onAlert", "onResized", "onStatusChanged", "onVisibilityChanged" ->
injectEventHandler(progress, value, engineVariable);
case "promptHandler" -> injectPromptHandler(progress, value, engineVariable);
case "location" -> injectLocation(progress, value, engineVariable);
default -> PropertyFormatter.formatProperty(progress, value, parsedObject, variableName);
injectEventHandler(value, engineVariable);
case "promptHandler" -> injectPromptHandler(value, engineVariable);
case "location" -> injectLocation(value, engineVariable);
default -> helperProvider.getPropertyFormatter().formatProperty(value, parsedObject, variableName);
}
}
private static void injectConfirmHandler(final GenerationProgress progress, final ParsedProperty value, final String engineVariable) throws GenerationException {
private void injectConfirmHandler(final ParsedProperty value, final String engineVariable) throws GenerationException {
if (value.value().startsWith("#")) {
ControllerInjector.injectCallbackControllerMethod(progress, value, engineVariable, "String.class");
helperProvider.getControllerInjector().injectCallbackControllerMethod(value, engineVariable, "String.class");
} else {
setCallback(progress, value, engineVariable);
setCallback(value, engineVariable);
}
}
private static void injectCreatePopupHandler(final GenerationProgress progress, final ParsedProperty value, final String engineVariable) throws GenerationException {
private void injectCreatePopupHandler(final ParsedProperty value, final String engineVariable) throws GenerationException {
if (value.value().startsWith("#")) {
ControllerInjector.injectCallbackControllerMethod(progress, value, engineVariable, "javafx.scene.web.PopupFeatures.class");
helperProvider.getControllerInjector().injectCallbackControllerMethod(value, engineVariable, "javafx.scene.web.PopupFeatures.class");
} else {
setCallback(progress, value, engineVariable);
setCallback(value, engineVariable);
}
}
private static void injectEventHandler(final GenerationProgress progress, final ParsedProperty value, final String engineVariable) throws GenerationException {
private void injectEventHandler(final ParsedProperty value, final String engineVariable) throws GenerationException {
if (value.value().startsWith("#")) {
ControllerInjector.injectEventHandlerControllerMethod(progress, value, engineVariable);
helperProvider.getControllerInjector().injectEventHandlerControllerMethod(value, engineVariable);
} else {
FieldSetter.setEventHandler(progress, value, engineVariable);
helperProvider.getFieldSetter().setEventHandler(value, engineVariable);
}
}
private static void injectPromptHandler(final GenerationProgress progress, final ParsedProperty value, final String engineVariable) throws GenerationException {
private void injectPromptHandler(final ParsedProperty value, final String engineVariable) throws GenerationException {
if (value.value().startsWith("#")) {
ControllerInjector.injectCallbackControllerMethod(progress, value, engineVariable, "javafx.scene.web.PromptData.class");
helperProvider.getControllerInjector().injectCallbackControllerMethod(value, engineVariable, "javafx.scene.web.PromptData.class");
} else {
setCallback(progress, value, engineVariable);
setCallback(value, engineVariable);
}
}
private static void injectLocation(final GenerationProgress progress, final ParsedProperty value, final String engineVariable) {
private void injectLocation(final ParsedProperty value, final String engineVariable) {
progress.stringBuilder().append(" ").append(engineVariable).append(".load(\"").append(value.value()).append("\");\n");
}
@@ -96,11 +102,10 @@ final class WebViewFormatter {
/**
* Sets a callback field
*
* @param progress The generation progress
* @param property The property to inject
* @param parentVariable The parent variable
*/
private static void setCallback(final GenerationProgress progress, final ParsedProperty property, final String parentVariable) throws GenerationException {
FieldSetter.setField(progress, property, parentVariable, "javafx.util.Callback");
private void setCallback(final ParsedProperty property, final String parentVariable) throws GenerationException {
helperProvider.getFieldSetter().setField(property, parentVariable, "javafx.util.Callback");
}
}

View File

@@ -2,8 +2,7 @@ package com.github.gtache.fxml.compiler.impl.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.GenerationRequest;
import com.github.gtache.fxml.compiler.InjectionType;
import com.github.gtache.fxml.compiler.impl.ControllerFieldInjectionTypes;
import com.github.gtache.fxml.compiler.impl.ControllerMethodsInjectionType;
import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
@@ -18,14 +17,12 @@ import java.util.List;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestControllerInjector {
private final GenerationProgress progress;
private final GenerationRequest request;
private final GenerationParameters parameters;
private final ControllerInfo controllerInfo;
private final List<String> controllerFactoryPostAction;
private final String id;
@@ -34,12 +31,8 @@ class TestControllerInjector {
private final String propertyValue;
private final StringBuilder sb;
TestControllerInjector(@Mock final GenerationProgress progress, @Mock final GenerationRequest request,
@Mock final GenerationParameters parameters, @Mock final ControllerInfo controllerInfo,
TestControllerInjector(@Mock final ControllerInfo controllerInfo,
@Mock final ParsedProperty property) {
this.progress = Objects.requireNonNull(progress);
this.request = Objects.requireNonNull(request);
this.parameters = Objects.requireNonNull(parameters);
this.controllerInfo = Objects.requireNonNull(controllerInfo);
this.controllerFactoryPostAction = new ArrayList<>();
this.id = "id";
@@ -51,19 +44,14 @@ class TestControllerInjector {
@BeforeEach
void beforeEach() {
when(progress.request()).thenReturn(request);
when(request.parameters()).thenReturn(parameters);
when(request.controllerInfo()).thenReturn(controllerInfo);
when(progress.controllerFactoryPostAction()).thenReturn(controllerFactoryPostAction);
when(progress.stringBuilder()).thenReturn(sb);
when(property.name()).thenReturn("name");
when(property.value()).thenReturn(propertyValue);
}
@Test
void testInjectControllerFieldFactory() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.FACTORY);
ControllerInjector.injectControllerField(progress, id, variable);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.FACTORY, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
injector.injectControllerField(id, variable);
final var expected = " fieldMap.put(\"" + id + "\", " + variable + ");\n";
assertEquals(expected, sb.toString());
assertTrue(controllerFactoryPostAction.isEmpty());
@@ -71,8 +59,8 @@ class TestControllerInjector {
@Test
void testInjectControllerFieldAssign() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.ASSIGN);
ControllerInjector.injectControllerField(progress, id, variable);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.ASSIGN, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
injector.injectControllerField(id, variable);
final var expected = " controller." + id + " = " + variable + ";\n";
assertEquals(expected, sb.toString());
assertTrue(controllerFactoryPostAction.isEmpty());
@@ -80,8 +68,8 @@ class TestControllerInjector {
@Test
void testInjectControllerFieldSetters() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.SETTERS);
ControllerInjector.injectControllerField(progress, id, variable);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.SETTERS, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
injector.injectControllerField(id, variable);
final var expected = " controller." + GenerationHelper.getSetMethod(id) + "(" + variable + ");\n";
assertEquals(expected, sb.toString());
assertTrue(controllerFactoryPostAction.isEmpty());
@@ -89,8 +77,8 @@ class TestControllerInjector {
@Test
void testInjectControllerFieldReflection() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.REFLECTION);
ControllerInjector.injectControllerField(progress, id, variable);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.REFLECTION, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
injector.injectControllerField(id, variable);
final var expected = " injectField(\"" + id + "\", " + variable + ");\n";
assertEquals(expected, sb.toString());
assertTrue(controllerFactoryPostAction.isEmpty());
@@ -98,15 +86,14 @@ class TestControllerInjector {
@Test
void testInjectControllerFieldUnknown() {
when(parameters.fieldInjectionType()).thenReturn(null);
assertThrows(GenerationException.class, () -> ControllerInjector.injectControllerField(progress, id, variable));
final var injector = new ControllerInjector(controllerInfo, mock(InjectionType.class), ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
assertThrows(GenerationException.class, () -> injector.injectControllerField(id, variable));
}
@Test
void testInjectEventHandlerReferenceFactoryNoArgument() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.FACTORY);
when(parameters.methodInjectionType()).thenReturn(ControllerMethodsInjectionType.REFERENCE);
ControllerInjector.injectEventHandlerControllerMethod(progress, property, variable);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.FACTORY, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
injector.injectEventHandlerControllerMethod(property, variable);
final var expected = " " + variable + "." + GenerationHelper.getSetMethod(property.name()) + "(e -> controller." + property.value().replace("#", "") + "());\n";
assertEquals(1, controllerFactoryPostAction.size());
assertEquals(expected, controllerFactoryPostAction.getFirst());
@@ -115,10 +102,9 @@ class TestControllerInjector {
@Test
void testInjectEventHandlerReferenceFactoryWithArgument() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.FACTORY);
when(parameters.methodInjectionType()).thenReturn(ControllerMethodsInjectionType.REFERENCE);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.FACTORY, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
when(controllerInfo.handlerHasArgument(propertyValue.replace("#", ""))).thenReturn(true);
ControllerInjector.injectEventHandlerControllerMethod(progress, property, variable);
injector.injectEventHandlerControllerMethod(property, variable);
final var expected = " " + variable + "." + GenerationHelper.getSetMethod(property.name()) + "(controller::" + propertyValue.replace("#", "") + ");\n";
assertEquals(1, controllerFactoryPostAction.size());
assertEquals(expected, controllerFactoryPostAction.getFirst());
@@ -127,9 +113,8 @@ class TestControllerInjector {
@Test
void testInjectEventHandlerReflectionAssign() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.ASSIGN);
when(parameters.methodInjectionType()).thenReturn(ControllerMethodsInjectionType.REFLECTION);
ControllerInjector.injectEventHandlerControllerMethod(progress, property, variable);
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.ASSIGN, ControllerMethodsInjectionType.REFLECTION, sb, controllerFactoryPostAction);
injector.injectEventHandlerControllerMethod(property, variable);
final var expected = " " + variable + "." + GenerationHelper.getSetMethod(property.name()) + "(e -> callEventHandlerMethod(\"" + propertyValue.replace("#", "") + "\", e));\n";
assertEquals(expected, sb.toString());
assertTrue(controllerFactoryPostAction.isEmpty());
@@ -137,23 +122,20 @@ class TestControllerInjector {
@Test
void testInjectEventHandlerUnknownMethod() {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.ASSIGN);
when(parameters.methodInjectionType()).thenReturn(null);
assertThrows(GenerationException.class, () -> ControllerInjector.injectEventHandlerControllerMethod(progress, property, variable));
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.ASSIGN, mock(InjectionType.class), sb, controllerFactoryPostAction);
assertThrows(GenerationException.class, () -> injector.injectEventHandlerControllerMethod(property, variable));
}
@Test
void testInjectEventHandlerUnknownField() {
when(parameters.fieldInjectionType()).thenReturn(null);
when(parameters.methodInjectionType()).thenReturn(ControllerMethodsInjectionType.REFLECTION);
assertThrows(GenerationException.class, () -> ControllerInjector.injectEventHandlerControllerMethod(progress, property, variable));
final var injector = new ControllerInjector(controllerInfo, mock(InjectionType.class), ControllerMethodsInjectionType.REFLECTION, sb, controllerFactoryPostAction);
assertThrows(GenerationException.class, () -> injector.injectEventHandlerControllerMethod(property, variable));
}
@Test
void testInjectCallbackReflectionSetters() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.ASSIGN);
when(parameters.methodInjectionType()).thenReturn(ControllerMethodsInjectionType.REFLECTION);
ControllerInjector.injectCallbackControllerMethod(progress, property, variable, "clazz");
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.ASSIGN, ControllerMethodsInjectionType.REFLECTION, sb, controllerFactoryPostAction);
injector.injectCallbackControllerMethod(property, variable, "clazz");
final var expected = " " + variable + "." + GenerationHelper.getSetMethod(property.name()) + "(e -> callCallbackMethod(\"" + propertyValue.replace("#", "") + "\", e, clazz));\n";
assertEquals(expected, sb.toString());
assertTrue(controllerFactoryPostAction.isEmpty());
@@ -161,9 +143,8 @@ class TestControllerInjector {
@Test
void testInjectCallbackReferenceFactory() throws GenerationException {
when(parameters.fieldInjectionType()).thenReturn(ControllerFieldInjectionTypes.FACTORY);
when(parameters.methodInjectionType()).thenReturn(ControllerMethodsInjectionType.REFERENCE);
ControllerInjector.injectCallbackControllerMethod(progress, property, variable, "clazz");
final var injector = new ControllerInjector(controllerInfo, ControllerFieldInjectionTypes.FACTORY, ControllerMethodsInjectionType.REFERENCE, sb, controllerFactoryPostAction);
injector.injectCallbackControllerMethod(property, variable, "clazz");
final var expected = " " + variable + "." + GenerationHelper.getSetMethod(property.name()) + "(controller::" + propertyValue.replace("#", "") + ");\n";
assertEquals(1, controllerFactoryPostAction.size());
assertEquals(expected, controllerFactoryPostAction.getFirst());

View File

@@ -1,141 +1,126 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.ControllerFieldInfo;
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.GenerationRequest;
import com.github.gtache.fxml.compiler.compatibility.GenerationCompatibility;
import com.github.gtache.fxml.compiler.compatibility.ListCollector;
import com.github.gtache.fxml.compiler.impl.GenericTypesImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import com.github.gtache.fxml.compiler.parsing.impl.ParsedPropertyImpl;
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.util.List;
import java.util.Map;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestGenerationCompatibilityHelper {
private final GenerationProgress progress;
private final GenerationRequest request;
private final GenerationParameters parameters;
private final HelperProvider helperProvider;
private final ReflectionHelper reflectionHelper;
private final GenerationCompatibility compatibility;
private final ParsedObject parsedObject;
private final GenerationCompatibilityHelper compatibilityHelper;
TestGenerationCompatibilityHelper(@Mock final GenerationProgress progress, @Mock final GenerationRequest request,
@Mock final GenerationParameters parameters, @Mock final GenerationCompatibility compatibility,
@Mock final ParsedObject parsedObject) {
this.progress = Objects.requireNonNull(progress);
this.request = Objects.requireNonNull(request);
this.parameters = Objects.requireNonNull(parameters);
TestGenerationCompatibilityHelper(@Mock final GenerationCompatibility compatibility, @Mock final HelperProvider helperProvider,
@Mock final ReflectionHelper reflectionHelper, @Mock final ParsedObject parsedObject) {
this.compatibility = Objects.requireNonNull(compatibility);
this.helperProvider = Objects.requireNonNull(helperProvider);
this.reflectionHelper = Objects.requireNonNull(reflectionHelper);
this.parsedObject = Objects.requireNonNull(parsedObject);
this.compatibilityHelper = new GenerationCompatibilityHelper(helperProvider, compatibility);
}
@BeforeEach
void beforeEach() {
when(progress.request()).thenReturn(request);
when(request.parameters()).thenReturn(parameters);
when(parameters.compatibility()).thenReturn(compatibility);
when(helperProvider.getReflectionHelper()).thenReturn(reflectionHelper);
when(parsedObject.className()).thenReturn("java.lang.String");
}
@Test
void testGetStartVarUseVar() {
when(compatibility.useVar()).thenReturn(true);
assertEquals(" final var ", GenerationCompatibilityHelper.getStartVar(progress, "class", 2));
assertEquals(" final var ", compatibilityHelper.getStartVar("class", 2));
}
@Test
void testGetStartVarUseVarDefaultIndent() {
when(compatibility.useVar()).thenReturn(true);
assertEquals(" final var ", GenerationCompatibilityHelper.getStartVar(progress, "class"));
assertEquals(" final var ", compatibilityHelper.getStartVar("class"));
}
@Test
void testGetStartVarUseVarObject() throws GenerationException {
when(compatibility.useVar()).thenReturn(true);
assertEquals(" final var ", GenerationCompatibilityHelper.getStartVar(progress, parsedObject));
assertEquals(" final var ", compatibilityHelper.getStartVar(parsedObject));
}
@Test
void testGetStartVarDontUseVar() {
when(compatibility.useVar()).thenReturn(false);
assertEquals(" final javafx.scene.control.Label ", GenerationCompatibilityHelper.getStartVar(progress, "javafx.scene.control.Label", 2));
assertEquals(" final javafx.scene.control.Label ", compatibilityHelper.getStartVar("javafx.scene.control.Label", 2));
}
@Test
void testGetStartVarDontUseVarObject() throws GenerationException {
when(compatibility.useVar()).thenReturn(false);
when(parsedObject.className()).thenReturn("javafx.scene.control.Label");
assertEquals(" final javafx.scene.control.Label ", GenerationCompatibilityHelper.getStartVar(progress, parsedObject));
when(reflectionHelper.getGenericTypes(parsedObject)).thenReturn("");
assertEquals(" final javafx.scene.control.Label ", compatibilityHelper.getStartVar(parsedObject));
verify(reflectionHelper).getGenericTypes(parsedObject);
}
@Test
void testGetStartVarDontUseVarGenericObject() throws GenerationException {
when(compatibility.useVar()).thenReturn(false);
when(parsedObject.className()).thenReturn("javafx.scene.control.TableView");
final var id = "tableView";
when(parsedObject.attributes()).thenReturn(Map.of("fx:id", new ParsedPropertyImpl("fx:id", null, id)));
final var info = mock(ControllerInfo.class);
final var fieldInfo = mock(ControllerFieldInfo.class);
when(info.fieldInfo(id)).thenReturn(fieldInfo);
when(request.controllerInfo()).thenReturn(info);
when(fieldInfo.isGeneric()).thenReturn(true);
when(fieldInfo.genericTypes()).thenReturn(List.of(new GenericTypesImpl("java.lang.String", List.of()), new GenericTypesImpl("java.lang.Integer", List.of())));
assertEquals(" final javafx.scene.control.TableView<java.lang.String, java.lang.Integer> ", GenerationCompatibilityHelper.getStartVar(progress, parsedObject));
when(reflectionHelper.getGenericTypes(parsedObject)).thenReturn("<java.lang.String, java.lang.Integer>");
assertEquals(" final javafx.scene.control.TableView<java.lang.String, java.lang.Integer> ", compatibilityHelper.getStartVar(parsedObject));
verify(reflectionHelper).getGenericTypes(parsedObject);
}
@Test
void testGetToListToList() {
when(compatibility.listCollector()).thenReturn(ListCollector.TO_LIST);
assertEquals(".toList()", GenerationCompatibilityHelper.getToList(progress));
assertEquals(".toList()", compatibilityHelper.getToList());
}
@Test
void testGetToListCollectToUnmodifiableList() {
when(compatibility.listCollector()).thenReturn(ListCollector.COLLECT_TO_UNMODIFIABLE_LIST);
assertEquals(".collect(java.util.stream.Collectors.toUnmodifiableList())", GenerationCompatibilityHelper.getToList(progress));
assertEquals(".collect(java.util.stream.Collectors.toUnmodifiableList())", compatibilityHelper.getToList());
}
@Test
void testGetToListCollectToList() {
when(compatibility.listCollector()).thenReturn(ListCollector.COLLECT_TO_LIST);
assertEquals(".collect(java.util.stream.Collectors.toList())", GenerationCompatibilityHelper.getToList(progress));
assertEquals(".collect(java.util.stream.Collectors.toList())", compatibilityHelper.getToList());
}
@Test
void testGetFirstUse() {
when(compatibility.useGetFirst()).thenReturn(true);
assertEquals(".getFirst()", GenerationCompatibilityHelper.getGetFirst(progress));
assertEquals(".getFirst()", compatibilityHelper.getGetFirst());
}
@Test
void testGetFirstDontUse() {
when(compatibility.useGetFirst()).thenReturn(false);
assertEquals(".get(0)", GenerationCompatibilityHelper.getGetFirst(progress));
assertEquals(".get(0)", compatibilityHelper.getGetFirst());
}
@Test
void testGetListOfUse() {
when(compatibility.useCollectionsOf()).thenReturn(true);
assertEquals("java.util.List.of(", GenerationCompatibilityHelper.getListOf(progress));
assertEquals("java.util.List.of(", compatibilityHelper.getListOf());
}
@Test
void testGetListOfDontUse() {
when(compatibility.useCollectionsOf()).thenReturn(false);
assertEquals("java.util.Arrays.asList(", GenerationCompatibilityHelper.getListOf(progress));
assertEquals("java.util.Arrays.asList(", compatibilityHelper.getListOf());
}
}

View File

@@ -19,27 +19,31 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestConstructorFormatter {
class TestInitializationFormatter {
private final GenerationProgress progress;
private final GenerationRequest request;
private final GenerationParameters parameters;
private final HelperProvider helperProvider;
private final StringBuilder stringBuilder;
private final SourceInfo sourceInfo;
private final ParsedInclude include;
private final Map<String, SourceInfo> sourceToSourceInfo;
private final InitializationFormatter initializationFormatter;
TestConstructorFormatter(@Mock final GenerationProgress progress, @Mock final GenerationRequest request,
@Mock final GenerationParameters parameters, @Mock final StringBuilder stringBuilder,
TestInitializationFormatter(@Mock final GenerationProgress progress, @Mock final GenerationRequest request,
@Mock final GenerationParameters parameters, @Mock final HelperProvider helperProvider,
@Mock final SourceInfo sourceInfo, @Mock final ParsedInclude include) {
this.progress = Objects.requireNonNull(progress);
this.request = Objects.requireNonNull(request);
this.parameters = Objects.requireNonNull(parameters);
this.stringBuilder = Objects.requireNonNull(stringBuilder);
this.stringBuilder = new StringBuilder();
this.helperProvider = Objects.requireNonNull(helperProvider);
this.sourceInfo = Objects.requireNonNull(sourceInfo);
this.include = Objects.requireNonNull(include);
this.sourceToSourceInfo = new HashMap<>();
this.initializationFormatter = new InitializationFormatter(helperProvider, progress);
}
@BeforeEach
@@ -53,6 +57,6 @@ class TestConstructorFormatter {
@Test
void testFormatSubViewConstructorCallNullSubInfo() {
assertThrows(GenerationException.class, () -> ConstructorFormatter.formatSubViewConstructorCall(progress, include));
assertThrows(GenerationException.class, () -> initializationFormatter.formatSubViewConstructorCall(include));
}
}

View File

@@ -3,7 +3,6 @@ package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.ControllerFieldInfo;
import com.github.gtache.fxml.compiler.ControllerInfo;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.GenerationRequest;
import com.github.gtache.fxml.compiler.impl.GenericTypesImpl;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
@@ -34,28 +33,23 @@ import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestReflectionHelper {
private final GenerationProgress progress;
private final GenerationRequest request;
private final Map<String, ParsedProperty> attributes;
private final ControllerInfo controllerInfo;
private final ControllerFieldInfo fieldInfo;
private final ParsedObject parsedObject;
private final ReflectionHelper reflectionHelper;
TestReflectionHelper(@Mock final GenerationProgress progress, @Mock final GenerationRequest request,
@Mock final ControllerInfo controllerInfo, @Mock final ControllerFieldInfo fieldInfo,
TestReflectionHelper(@Mock final ControllerInfo controllerInfo, @Mock final ControllerFieldInfo fieldInfo,
@Mock final ParsedObject parsedObject) {
this.progress = Objects.requireNonNull(progress);
this.request = Objects.requireNonNull(request);
this.controllerInfo = Objects.requireNonNull(controllerInfo);
this.fieldInfo = Objects.requireNonNull(fieldInfo);
this.parsedObject = Objects.requireNonNull(parsedObject);
this.attributes = new HashMap<>();
this.reflectionHelper = new ReflectionHelper(controllerInfo);
}
@BeforeEach
void beforeEach() {
when(progress.request()).thenReturn(request);
when(request.controllerInfo()).thenReturn(controllerInfo);
when(controllerInfo.fieldInfo("id")).thenReturn(fieldInfo);
when(parsedObject.attributes()).thenReturn(attributes);
when(parsedObject.className()).thenReturn("javafx.scene.control.ComboBox");
@@ -191,31 +185,31 @@ class TestReflectionHelper {
@Test
void testGetGenericTypesNotGeneric() throws GenerationException {
when(parsedObject.className()).thenReturn("java.lang.String");
assertEquals("", ReflectionHelper.getGenericTypes(progress, parsedObject));
assertEquals("", reflectionHelper.getGenericTypes(parsedObject));
}
@Test
void testGetGenericTypesNullProperty() throws GenerationException {
attributes.clear();
assertEquals("", ReflectionHelper.getGenericTypes(progress, parsedObject));
assertEquals("", reflectionHelper.getGenericTypes(parsedObject));
}
@Test
void testGetGenericTypesFieldNotFound() throws GenerationException {
when(controllerInfo.fieldInfo("id")).thenReturn(null);
assertEquals("", ReflectionHelper.getGenericTypes(progress, parsedObject));
assertEquals("", reflectionHelper.getGenericTypes(parsedObject));
}
@Test
void testGetGenericTypesFieldNotGeneric() throws GenerationException {
when(fieldInfo.isGeneric()).thenReturn(false);
when(fieldInfo.genericTypes()).thenReturn(List.of(new GenericTypesImpl("java.lang.String", List.of()), new GenericTypesImpl("java.lang.Integer", List.of())));
assertEquals("", ReflectionHelper.getGenericTypes(progress, parsedObject));
assertEquals("", reflectionHelper.getGenericTypes(parsedObject));
}
@Test
void testGetGenericTypes() throws GenerationException {
when(fieldInfo.genericTypes()).thenReturn(List.of(new GenericTypesImpl("java.lang.String", List.of()), new GenericTypesImpl("java.lang.Integer", List.of())));
assertEquals("<java.lang.String, java.lang.Integer>", ReflectionHelper.getGenericTypes(progress, parsedObject));
assertEquals("<java.lang.String, java.lang.Integer>", reflectionHelper.getGenericTypes(parsedObject));
}
}

View File

@@ -1,9 +1,108 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
import com.github.gtache.fxml.compiler.parsing.impl.ParsedPropertyImpl;
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.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
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)
class TestURLFormatter {
private final HelperProvider helperProvider;
private final GenerationHelper generationHelper;
private final GenerationCompatibilityHelper compatibilityHelper;
private final ParsedObject parsedObject;
private final String variableName;
private final StringBuilder sb;
private final GenerationProgress progress;
private final URLFormatter urlFormatter;
TestURLFormatter(@Mock final HelperProvider helperProvider, @Mock final GenerationHelper generationHelper,
@Mock final GenerationCompatibilityHelper compatibilityHelper, @Mock final ParsedObject parsedObject,
@Mock final GenerationProgress progress) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.generationHelper = Objects.requireNonNull(generationHelper);
this.compatibilityHelper = Objects.requireNonNull(compatibilityHelper);
this.parsedObject = Objects.requireNonNull(parsedObject);
this.progress = Objects.requireNonNull(progress);
this.sb = new StringBuilder();
this.variableName = "variable";
this.urlFormatter = new URLFormatter(helperProvider, progress);
}
@BeforeEach
void beforeEach() throws GenerationException {
when(helperProvider.getCompatibilityHelper()).thenReturn(compatibilityHelper);
when(helperProvider.getGenerationHelper()).thenReturn(generationHelper);
when(progress.stringBuilder()).thenReturn(sb);
when(progress.getNextVariableName("url")).thenReturn("url1", "url2");
when(compatibilityHelper.getStartVar(anyString())).then(i -> i.getArgument(0));
when(parsedObject.children()).thenReturn(List.of());
when(parsedObject.properties()).thenReturn(new LinkedHashMap<>());
doAnswer(i -> sb.append("handleId")).when(generationHelper).handleId(any(), anyString());
}
@Test
void testFormatURLSheets() {
final var styleSheets = List.of("style1.css", "@style2.css");
final var expected = " final java.net.URL url1;\n" +
" try {\n" +
" url1 = new java.net.URI(\"style1.css\").toURL();\n" +
" } catch (final java.net.MalformedURLException | java.net.URISyntaxException e) {\n" +
" throw new RuntimeException(\"Couldn't parse url : style1.css\", e);\n" +
" }\njava.net.URLurl2 = getClass().getResource(\"style2.css\");\n";
assertEquals(List.of("url1", "url2"), urlFormatter.formatURL(styleSheets));
assertEquals(expected, sb.toString());
}
@Test
void testFormatURLObjectChildren() {
when(parsedObject.children()).thenReturn(List.of(parsedObject));
assertThrows(GenerationException.class, () -> urlFormatter.formatURL(parsedObject, variableName));
}
@Test
void testFormatURLObjectProperties() {
final var map = new LinkedHashMap<ParsedProperty, SequencedCollection<ParsedObject>>();
map.put(mock(ParsedProperty.class), List.of());
when(parsedObject.properties()).thenReturn(map);
assertThrows(GenerationException.class, () -> urlFormatter.formatURL(parsedObject, variableName));
}
@Test
void testFormatURLObjectUnknownAttribute() {
final var attributes = new HashMap<String, ParsedProperty>();
attributes.put("unknown", new ParsedPropertyImpl("unknown", null, "value"));
when(parsedObject.attributes()).thenReturn(attributes);
assertThrows(GenerationException.class, () -> urlFormatter.formatURL(parsedObject, variableName));
}
@Test
void testFormatURLObject() throws GenerationException {
final var attributes = new HashMap<String, ParsedProperty>();
attributes.put("value", new ParsedPropertyImpl("value", null, "key"));
attributes.put("fx:id", new ParsedPropertyImpl("fx:id", null, "id"));
when(parsedObject.attributes()).thenReturn(attributes);
urlFormatter.formatURL(parsedObject, variableName);
final var expected = "java.net.URL" + variableName + " = getClass().getResource(\"key\");\nhandleId";
assertEquals(expected, sb.toString());
verify(generationHelper).handleId(parsedObject, variableName);
}
}

View File

@@ -1,8 +1,145 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.InjectionType;
import com.github.gtache.fxml.compiler.impl.ResourceBundleInjectionTypes;
import javafx.geometry.Pos;
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.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestValueFormatter {
private final Map<String, VariableInfo> idToVariableInfo;
private final InjectionType resourceInjectionType;
private final ValueFormatter formatter;
TestValueFormatter(@Mock final InjectionType resourceInjectionType) {
this.resourceInjectionType = requireNonNull(resourceInjectionType);
this.idToVariableInfo = new HashMap<>();
this.formatter = new ValueFormatter(resourceInjectionType, idToVariableInfo);
}
@Test
void testGetArgStringResourceUnknown() {
assertThrows(GenerationException.class, () -> formatter.getArg("%value", String.class));
}
@Test
void testGetArgStringResourceSimpleGet() throws GenerationException {
final var types = List.of(ResourceBundleInjectionTypes.CONSTRUCTOR, ResourceBundleInjectionTypes.CONSTRUCTOR_NAME, ResourceBundleInjectionTypes.GET_BUNDLE);
for (final var type : types) {
final var resourceFormatter = new ValueFormatter(type, idToVariableInfo);
assertEquals("resourceBundle.getString(\"value\")", resourceFormatter.getArg("%value", String.class));
}
}
@Test
void testGetArgStringResourceController() throws GenerationException {
final var resourceFormatter = new ValueFormatter(ResourceBundleInjectionTypes.GETTER, idToVariableInfo);
assertEquals("controller.resources().getString(\"value\")", resourceFormatter.getArg("%value", String.class));
}
@Test
void testGetArgStringResourceFunction() throws GenerationException {
final var resourceFormatter = new ValueFormatter(ResourceBundleInjectionTypes.CONSTRUCTOR_FUNCTION, idToVariableInfo);
assertEquals("resourceBundleFunction.apply(\"value\")", resourceFormatter.getArg("%value", String.class));
}
@Test
void testGetArgRelativePath() throws GenerationException {
assertEquals("getClass().getResource(\"value\").toString()", formatter.getArg("@value", String.class));
assertEquals("getClass().getResource(\"value\").toString()", formatter.getArg("@value", URL.class));
}
@Test
void testGetArgBinding() {
assertThrows(GenerationException.class, () -> formatter.getArg("${value}", String.class));
}
@Test
void testGetArgExpressionNull() {
assertThrows(GenerationException.class, () -> formatter.getArg("$value", String.class));
}
@Test
void testGetArgExpression() throws GenerationException {
final var info = mock(VariableInfo.class);
when(info.variableName()).thenReturn("variable");
idToVariableInfo.put("value", info);
assertEquals("variable", formatter.getArg("$value", String.class));
}
@Test
void testGetArgOther() throws GenerationException {
assertEquals("\"value\"", formatter.getArg("value", String.class));
}
@Test
void testToStringString() {
assertEquals("\"value\"", formatter.toString("value", String.class));
}
@Test
void testToStringEscape() {
assertEquals("\"val\\\\u\\\"e\"", formatter.toString("\\val\\u\"e", String.class));
}
@Test
void testToStringChar() {
assertEquals("'v'", formatter.toString("v", char.class));
assertEquals("'v'", formatter.toString("v", Character.class));
}
@Test
void testToStringBoolean() {
assertEquals("true", formatter.toString("true", boolean.class));
assertEquals("true", formatter.toString("true", Boolean.class));
}
@Test
void testToStringInteger() {
final var types = List.of(byte.class, Byte.class, short.class, Short.class, long.class, Long.class, int.class, Integer.class);
for (final var type : types) {
assertEquals("1", formatter.toString("1", type));
assertEquals(ReflectionHelper.getWrapperClass(type) + ".valueOf(\"value\")", formatter.toString("value", type));
}
}
@Test
void testToStringDecimal() {
final var types = List.of(float.class, Float.class, double.class, Double.class);
for (final var type : types) {
assertEquals("1.0", formatter.toString("1.0", type));
assertEquals(ReflectionHelper.getWrapperClass(type) + ".valueOf(\"value\")", formatter.toString("value", type));
}
}
@Test
void testToStringValueOfEnum() {
assertEquals("javafx.geometry.Pos.value", formatter.toString("value", Pos.class));
}
@Test
void testToStringValueOfColor() {
assertEquals("javafx.scene.paint.Color.valueOf(\"value\")", formatter.toString("value", javafx.scene.paint.Color.class));
}
@Test
void testOther() {
assertEquals("value", formatter.toString("value", Object.class));
}
}

View File

@@ -1,8 +1,163 @@
package com.github.gtache.fxml.compiler.impl.internal;
import com.github.gtache.fxml.compiler.GenerationException;
import com.github.gtache.fxml.compiler.parsing.ParsedObject;
import com.github.gtache.fxml.compiler.parsing.ParsedProperty;
import com.github.gtache.fxml.compiler.parsing.impl.ParsedPropertyImpl;
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.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
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.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TestWebViewFormatter {
private final HelperProvider helperProvider;
private final GenerationCompatibilityHelper compatibilityHelper;
private final ControllerInjector controllerInjector;
private final FieldSetter fieldSetter;
private final PropertyFormatter propertyFormatter;
private final GenerationHelper generationHelper;
private final GenerationProgress progress;
private final ParsedObject parsedObject;
private final String variableName;
private final String engineVariable;
private final ParsedProperty parsedProperty;
private final StringBuilder sb;
private final Map<String, ParsedProperty> attributes;
private final WebViewFormatter webViewFormatter;
TestWebViewFormatter(@Mock final HelperProvider helperProvider, @Mock final GenerationCompatibilityHelper compatibilityHelper,
@Mock final ControllerInjector controllerInjector, @Mock final FieldSetter fieldSetter,
@Mock final PropertyFormatter propertyFormatter, @Mock final GenerationHelper generationHelper,
@Mock final GenerationProgress progress, @Mock final ParsedObject parsedObject,
@Mock final ParsedProperty parsedProperty) {
this.helperProvider = Objects.requireNonNull(helperProvider);
this.compatibilityHelper = Objects.requireNonNull(compatibilityHelper);
this.controllerInjector = Objects.requireNonNull(controllerInjector);
this.fieldSetter = Objects.requireNonNull(fieldSetter);
this.propertyFormatter = Objects.requireNonNull(propertyFormatter);
this.generationHelper = Objects.requireNonNull(generationHelper);
this.progress = Objects.requireNonNull(progress);
this.parsedObject = Objects.requireNonNull(parsedObject);
this.variableName = "variable";
this.engineVariable = "engine";
this.parsedProperty = Objects.requireNonNull(parsedProperty);
this.sb = new StringBuilder();
this.attributes = new HashMap<>();
this.webViewFormatter = new WebViewFormatter(helperProvider, progress);
}
@BeforeEach
void beforeEach() throws GenerationException {
when(parsedObject.children()).thenReturn(List.of());
when(parsedObject.properties()).thenReturn(new LinkedHashMap<>());
when(helperProvider.getCompatibilityHelper()).thenReturn(compatibilityHelper);
when(helperProvider.getControllerInjector()).thenReturn(controllerInjector);
when(helperProvider.getFieldSetter()).thenReturn(fieldSetter);
when(helperProvider.getGenerationHelper()).thenReturn(generationHelper);
when(helperProvider.getPropertyFormatter()).thenReturn(propertyFormatter);
when(compatibilityHelper.getStartVar(anyString())).then(i -> i.getArgument(0));
doAnswer(i -> sb.append(((ParsedProperty) i.getArgument(0)).value()).append((String) i.getArgument(2))).when(controllerInjector).injectCallbackControllerMethod(any(), eq(engineVariable), any());
doAnswer(i -> sb.append(((ParsedProperty) i.getArgument(0)).value())).when(controllerInjector).injectEventHandlerControllerMethod(any(), eq(engineVariable));
doAnswer(i -> sb.append(((ParsedProperty) i.getArgument(0)).value())).when(fieldSetter).setEventHandler(any(), eq(engineVariable));
doAnswer(i -> sb.append(((ParsedProperty) i.getArgument(0)).value()).append((String) i.getArgument(2))).when(fieldSetter).setField(any(), eq(engineVariable), any());
doAnswer(i -> sb.append("handleId")).when(generationHelper).handleId(parsedObject, variableName);
doAnswer(i -> sb.append(((ParsedProperty) i.getArgument(0)).value())).when(propertyFormatter).formatProperty(any(), any(), any());
when(parsedObject.attributes()).thenReturn(attributes);
when(progress.stringBuilder()).thenReturn(sb);
when(progress.getNextVariableName("engine")).thenReturn(engineVariable);
}
@Test
void testFormatHasChildren() {
when(parsedObject.children()).thenReturn(List.of(parsedObject));
assertThrows(GenerationException.class, () -> webViewFormatter.formatWebView(parsedObject, variableName));
}
@Test
void testFormatHasProperty() {
final var properties = new LinkedHashMap<ParsedProperty, SequencedCollection<ParsedObject>>();
properties.put(parsedProperty, List.of(parsedObject));
when(parsedObject.properties()).thenReturn(properties);
assertThrows(GenerationException.class, () -> webViewFormatter.formatWebView(parsedObject, variableName));
}
@Test
void testFormatAllMethods() throws GenerationException {
attributes.put("confirmHandler", new ParsedPropertyImpl("confirmHandler", null, "#confirmHandler"));
attributes.put("createPopupHandler", new ParsedPropertyImpl("createPopupHandler", null, "#createPopupHandler"));
attributes.put("onAlert", new ParsedPropertyImpl("onAlert", null, "#onAlert"));
attributes.put("onResized", new ParsedPropertyImpl("onResized", null, "#onResized"));
attributes.put("onStatusChanged", new ParsedPropertyImpl("onStatusChanged", null, "#onStatusChanged"));
attributes.put("onVisibilityChanged", new ParsedPropertyImpl("onVisibilityChanged", null, "#onVisibilityChanged"));
attributes.put("promptHandler", new ParsedPropertyImpl("promptHandler", null, "#promptHandler"));
attributes.put("location", new ParsedPropertyImpl("location", null, "location"));
attributes.put("property", new ParsedPropertyImpl("property", null, "property"));
attributes.put("fx:id", new ParsedPropertyImpl("fx:id", null, "id"));
webViewFormatter.formatWebView(parsedObject, variableName);
final var expected = "javafx.scene.web.WebViewvariable = new javafx.scene.web.WebView();\n" +
"javafx.scene.web.WebEngineengine = variable.getEngine();\n" +
"#confirmHandlerString.class#createPopupHandlerjavafx.scene.web.PopupFeatures.class" +
" engine.load(\"location\");\n#onAlert#onResized#onStatusChanged#onVisibilityChanged#promptHandlerjavafx.scene.web.PromptData.class" +
"propertyhandleId";
assertEquals(expected, sb.toString());
verify(propertyFormatter).formatProperty(attributes.get("property"), parsedObject, variableName);
verify(controllerInjector).injectCallbackControllerMethod(attributes.get("confirmHandler"), engineVariable, "String.class");
verify(controllerInjector).injectCallbackControllerMethod(attributes.get("createPopupHandler"), engineVariable, "javafx.scene.web.PopupFeatures.class");
verify(controllerInjector).injectEventHandlerControllerMethod(attributes.get("onAlert"), engineVariable);
verify(controllerInjector).injectEventHandlerControllerMethod(attributes.get("onResized"), engineVariable);
verify(controllerInjector).injectEventHandlerControllerMethod(attributes.get("onStatusChanged"), engineVariable);
verify(controllerInjector).injectEventHandlerControllerMethod(attributes.get("onVisibilityChanged"), engineVariable);
verify(controllerInjector).injectCallbackControllerMethod(attributes.get("promptHandler"), engineVariable, "javafx.scene.web.PromptData.class");
verify(generationHelper).handleId(parsedObject, variableName);
}
@Test
void testFormatAllVariables() throws GenerationException {
attributes.put("confirmHandler", new ParsedPropertyImpl("confirmHandler", null, "$controller.confirmHandler"));
attributes.put("createPopupHandler", new ParsedPropertyImpl("createPopupHandler", null, "$controller.createPopupHandler"));
attributes.put("onAlert", new ParsedPropertyImpl("onAlert", null, "$controller.onAlert"));
attributes.put("onResized", new ParsedPropertyImpl("onResized", null, "$controller.onResized"));
attributes.put("onStatusChanged", new ParsedPropertyImpl("onStatusChanged", null, "$controller.onStatusChanged"));
attributes.put("onVisibilityChanged", new ParsedPropertyImpl("onVisibilityChanged", null, "$controller.onVisibilityChanged"));
attributes.put("promptHandler", new ParsedPropertyImpl("promptHandler", null, "$controller.promptHandler"));
attributes.put("location", new ParsedPropertyImpl("location", null, "location"));
attributes.put("property", new ParsedPropertyImpl("property", null, "property"));
attributes.put("fx:id", new ParsedPropertyImpl("fx:id", null, "id"));
webViewFormatter.formatWebView(parsedObject, variableName);
final var expected = "javafx.scene.web.WebViewvariable = new javafx.scene.web.WebView();\n" +
"javafx.scene.web.WebEngineengine = variable.getEngine();\n" +
"$controller.confirmHandlerjavafx.util.Callback$controller.createPopupHandlerjavafx.util.Callback" +
" engine.load(\"location\");\n$controller.onAlert$controller.onResized$controller.onStatusChanged$controller.onVisibilityChanged" +
"$controller.promptHandlerjavafx.util.Callback" +
"propertyhandleId";
assertEquals(expected, sb.toString());
verify(fieldSetter).setEventHandler(attributes.get("onAlert"), engineVariable);
verify(fieldSetter).setEventHandler(attributes.get("onResized"), engineVariable);
verify(fieldSetter).setEventHandler(attributes.get("onStatusChanged"), engineVariable);
verify(fieldSetter).setEventHandler(attributes.get("onVisibilityChanged"), engineVariable);
verify(propertyFormatter).formatProperty(attributes.get("property"), parsedObject, variableName);
verify(fieldSetter).setField(attributes.get("confirmHandler"), engineVariable, "javafx.util.Callback");
verify(fieldSetter).setField(attributes.get("createPopupHandler"), engineVariable, "javafx.util.Callback");
verify(fieldSetter).setField(attributes.get("promptHandler"), engineVariable, "javafx.util.Callback");
verify(generationHelper).handleId(parsedObject, variableName);
}
}