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 (${})
@@ -14,11 +12,11 @@ import com.github.gtache.fxml.compiler.impl.internal.LoadMethodFormatter;
* Implementation of {@link Generator}
*/
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,
final double requestedHeight, final boolean preserveRatio, final boolean smooth, final String variableName) {
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,
final double requestedHeight, final boolean preserveRatio, final boolean smooth,
final boolean backgroundLoading, final String variableName) {
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,
final Iterable<? extends ParsedObject> objects, final String parentVariable) throws GenerationException {
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,
final String parentVariable) throws GenerationException {
final var getMethod = GenerationHelper.getGetMethod(propertyName);
private void formatMultipleChildren(final Iterable<String> variables, final String propertyName, final ParsedObject parent,
final String parentVariable) throws GenerationException {
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,
final String parentVariable) throws GenerationException {
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,
final ParsedProperty property, final ParsedObject parent,
final String parentVariable) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property);
final var getMethod = GenerationHelper.getGetMethod(property);
private void formatSingleChildInstance(final String variableName,
final ParsedProperty property, final ParsedObject parent,
final String parentVariable) throws GenerationException {
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,
final ParsedProperty property, final String parentVariable) throws GenerationException {
final var setMethod = GenerationHelper.getSetMethod(property);
private void formatSingleChildStatic(final String variableName,
final ParsedProperty property, final String parentVariable) throws GenerationException {
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,
final String variableName, final String engineVariable) throws GenerationException {
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,
@Mock final SourceInfo sourceInfo, @Mock final ParsedInclude include) {
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);
}
}