Finishes implementing, seems to work ; needs to manage define, copy, reference, root
This commit is contained in:
@@ -44,9 +44,18 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.gtache</groupId>
|
||||
<artifactId>fxml-compiler-loader</artifactId>
|
||||
<artifactId>fxml-compiler-xml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.github.gtache.fxml.compiler.maven;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Info about FXML file compilation
|
||||
*
|
||||
* @param inputFile The input file
|
||||
* @param outputFile The output file
|
||||
* @param outputClass The output class name
|
||||
* @param controllerFile The controller file
|
||||
* @param controllerClass The controller class name
|
||||
* @param injectedFields The injected fields
|
||||
* @param injectedMethods The injected methods
|
||||
* @param includes The FXML inclusions
|
||||
*/
|
||||
record CompilationInfo(Path inputFile, Path outputFile, String outputClass, Path controllerFile,
|
||||
String controllerClass,
|
||||
Set<FieldInfo> injectedFields,
|
||||
Set<String> injectedMethods, Map<String, Path> includes) {
|
||||
|
||||
CompilationInfo {
|
||||
Objects.requireNonNull(inputFile);
|
||||
Objects.requireNonNull(outputFile);
|
||||
Objects.requireNonNull(outputClass);
|
||||
Objects.requireNonNull(controllerFile);
|
||||
injectedFields = Set.copyOf(injectedFields);
|
||||
injectedMethods = Set.copyOf(injectedMethods);
|
||||
includes = Map.copyOf(includes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link CompilationInfo}
|
||||
*/
|
||||
static class Builder {
|
||||
|
||||
private Path inputFile;
|
||||
private Path outputFile;
|
||||
private String outputClass;
|
||||
private Path controllerFile;
|
||||
private String controllerClass;
|
||||
private final Set<FieldInfo> injectedFields;
|
||||
private final Set<String> injectedMethods;
|
||||
private final Map<String, Path> includes;
|
||||
|
||||
Builder() {
|
||||
this.injectedFields = new HashSet<>();
|
||||
this.injectedMethods = new HashSet<>();
|
||||
this.includes = new HashMap<>();
|
||||
}
|
||||
|
||||
Path inputFile() {
|
||||
return inputFile;
|
||||
}
|
||||
|
||||
Builder inputFile(final Path inputFile) {
|
||||
this.inputFile = inputFile;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder outputFile(final Path outputFile) {
|
||||
this.outputFile = outputFile;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder outputClass(final String outputClassName) {
|
||||
this.outputClass = outputClassName;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder controllerFile(final Path controllerFile) {
|
||||
this.controllerFile = controllerFile;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder controllerClass(final String controllerClass) {
|
||||
this.controllerClass = controllerClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder addInjectedField(final String field, final String type) {
|
||||
injectedFields.add(new FieldInfo(type, field));
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder addInjectedMethod(final String method) {
|
||||
injectedMethods.add(method);
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder addInclude(final String key, final Path value) {
|
||||
this.includes.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
CompilationInfo build() {
|
||||
return new CompilationInfo(inputFile, outputFile, outputClass, controllerFile, controllerClass, injectedFields, injectedMethods, includes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.github.gtache.fxml.compiler.maven;
|
||||
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* Helper class for {@link FXMLCompilerMojo} to provides {@link CompilationInfo}
|
||||
*/
|
||||
class CompilationInfoProvider {
|
||||
|
||||
private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
|
||||
private static final Pattern START_DOT_PATTERN = Pattern.compile("^\\.");
|
||||
|
||||
private final MavenProject project;
|
||||
private final Path outputDirectory;
|
||||
private final Log logger;
|
||||
|
||||
CompilationInfoProvider(final MavenProject project, final Path outputDirectory, final Log logger) {
|
||||
this.project = requireNonNull(project);
|
||||
this.outputDirectory = requireNonNull(outputDirectory);
|
||||
this.logger = requireNonNull(logger);
|
||||
}
|
||||
|
||||
CompilationInfo getCompilationInfo(final Path root, final Path inputPath, final Map<? extends Path, String> controllerMapping) throws MojoExecutionException {
|
||||
logger.info("Parsing " + inputPath);
|
||||
try {
|
||||
final var documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
|
||||
final var document = documentBuilder.parse(inputPath.toFile());
|
||||
document.getDocumentElement().normalize();
|
||||
final var builder = new CompilationInfo.Builder();
|
||||
builder.inputFile(inputPath);
|
||||
final var inputFilename = inputPath.getFileName().toString();
|
||||
final var outputFilename = getOutputFilename(inputFilename);
|
||||
final var outputClass = getOutputClass(root, inputPath, outputFilename);
|
||||
final var replacedPrefixPath = inputPath.toString().replace(root.toString(), outputDirectory.toString());
|
||||
final var targetPath = Paths.get(replacedPrefixPath.replace(inputFilename, outputFilename));
|
||||
builder.outputFile(targetPath);
|
||||
builder.outputClass(outputClass);
|
||||
handleNode(document.getDocumentElement(), builder, controllerMapping);
|
||||
logger.info(inputPath + " will be compiled to " + targetPath);
|
||||
return builder.build();
|
||||
} catch (final SAXException | IOException | ParserConfigurationException e) {
|
||||
throw new MojoExecutionException("Error parsing fxml at " + inputPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getOutputClass(final Path root, final Path inputPath, final String outputFilename) {
|
||||
final var inputFilename = inputPath.getFileName().toString();
|
||||
final var className = outputFilename.replace(".java", "");
|
||||
final var replacedPrefixPath = inputPath.toString().replace(root.toString(), "").replace(inputFilename, className);
|
||||
return START_DOT_PATTERN.matcher(replacedPrefixPath.replace(File.separator, ".")).replaceAll("");
|
||||
}
|
||||
|
||||
private static String getOutputFilename(final CharSequence inputFilename) {
|
||||
final var builder = new StringBuilder(inputFilename.length());
|
||||
var nextUppercase = true;
|
||||
for (var i = 0; i < inputFilename.length(); i++) {
|
||||
final var c = inputFilename.charAt(i);
|
||||
if (c == '-' || c == '_') {
|
||||
nextUppercase = true;
|
||||
} else if (nextUppercase) {
|
||||
builder.append(Character.toUpperCase(c));
|
||||
nextUppercase = false;
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return builder.toString().replace(".fxml", ".java");
|
||||
}
|
||||
|
||||
private void handleNode(final Node node, final CompilationInfo.Builder builder, final Map<? extends Path, String> controllerMapping) throws MojoExecutionException {
|
||||
if (node.getNodeName().equals("fx:include")) {
|
||||
handleInclude(node, builder);
|
||||
}
|
||||
handleAttributes(node, builder, controllerMapping);
|
||||
handleChildren(node, builder, controllerMapping);
|
||||
}
|
||||
|
||||
private void handleInclude(final Node node, final CompilationInfo.Builder builder) throws MojoExecutionException {
|
||||
final var map = node.getAttributes();
|
||||
if (map == null) {
|
||||
throw new MojoExecutionException("Missing attributes for include");
|
||||
} else {
|
||||
final var sourceAttr = map.getNamedItem("source");
|
||||
if (sourceAttr == null) {
|
||||
throw new MojoExecutionException("Missing source for include");
|
||||
} else {
|
||||
final var source = sourceAttr.getNodeValue();
|
||||
final var path = getRelativePath(builder.inputFile(), source);
|
||||
logger.info("Found include " + source);
|
||||
builder.addInclude(source, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getRelativePath(final Path base, final String relative) {
|
||||
return base.getParent().resolve(relative).normalize();
|
||||
}
|
||||
|
||||
private void handleChildren(final Node node, final CompilationInfo.Builder builder, final Map<? extends Path, String> controllerMapping) throws MojoExecutionException {
|
||||
final var nl = node.getChildNodes();
|
||||
for (var i = 0; i < nl.getLength(); i++) {
|
||||
handleNode(nl.item(i), builder, controllerMapping);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAttributes(final Node node, final CompilationInfo.Builder builder, final Map<? extends Path, String> controllerMapping) throws MojoExecutionException {
|
||||
final var map = node.getAttributes();
|
||||
if (map != null) {
|
||||
for (var i = 0; i < map.getLength(); i++) {
|
||||
final var item = map.item(i);
|
||||
final var name = item.getNodeName();
|
||||
final var value = item.getNodeValue();
|
||||
if (name.startsWith("on") && value.startsWith("#")) {
|
||||
final var methodName = value.replace("#", "");
|
||||
logger.debug("Found injected method " + methodName);
|
||||
builder.addInjectedMethod(methodName);
|
||||
} else if (name.equals("fx:controller")) {
|
||||
handleController(value, builder);
|
||||
} else if (name.equals("fx:id")) {
|
||||
final var type = node.getNodeName();
|
||||
logger.debug("Found injected field " + value + " of type " + type);
|
||||
if (type.equals("fx:include")) {
|
||||
final var path = getRelativePath(builder.inputFile(), map.getNamedItem("source").getNodeValue()).normalize();
|
||||
final var controllerClass = controllerMapping.get(path);
|
||||
if (controllerClass == null) {
|
||||
throw new MojoExecutionException("Cannot find controller for " + path);
|
||||
}
|
||||
builder.addInjectedField(value + "Controller", controllerClass);
|
||||
} else {
|
||||
builder.addInjectedField(value, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleController(final String controllerClass, final CompilationInfo.Builder builder) throws MojoExecutionException {
|
||||
final var subPath = controllerClass.replace(".", "/") + ".java";
|
||||
final var path = project.getCompileSourceRoots().stream()
|
||||
.map(s -> Paths.get(s).resolve(subPath))
|
||||
.filter(Files::exists)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new MojoExecutionException("Cannot find controller " + controllerClass));
|
||||
logger.info("Found controller " + controllerClass);
|
||||
builder.controllerFile(path);
|
||||
builder.controllerClass(controllerClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.github.gtache.fxml.compiler.maven;
|
||||
|
||||
import com.github.gtache.fxml.compiler.ControllerInfo;
|
||||
import com.github.gtache.fxml.compiler.impl.ClassesFinder;
|
||||
import com.github.gtache.fxml.compiler.impl.ControllerInfoImpl;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Helper class for {@link FXMLCompilerMojo} to provides {@link ControllerInfo}
|
||||
*/
|
||||
class ControllerInfoProvider {
|
||||
|
||||
private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\s+(?:static\\s+)?(?<import>[^;]+);");
|
||||
|
||||
private static final Set<String> JAVA_LANG_CLASSES;
|
||||
|
||||
static {
|
||||
final var set = new HashSet<String>();
|
||||
set.add("Object");
|
||||
set.add("String");
|
||||
set.add("Boolean");
|
||||
set.add("Character");
|
||||
set.add("Byte");
|
||||
set.add("Short");
|
||||
set.add("Integer");
|
||||
set.add("Long");
|
||||
set.add("Float");
|
||||
set.add("Double");
|
||||
JAVA_LANG_CLASSES = Set.copyOf(set);
|
||||
}
|
||||
|
||||
private final Log logger;
|
||||
|
||||
ControllerInfoProvider(final Log logger) {
|
||||
this.logger = Objects.requireNonNull(logger);
|
||||
}
|
||||
|
||||
ControllerInfo getControllerInfo(final CompilationInfo info) throws MojoExecutionException {
|
||||
try {
|
||||
final var content = Files.readString(info.controllerFile());
|
||||
final var imports = getImports(content);
|
||||
final var propertyGenericTypes = new HashMap<String, List<String>>();
|
||||
for (final var fieldInfo : info.injectedFields()) {
|
||||
final var name = fieldInfo.name();
|
||||
final var type = fieldInfo.type();
|
||||
if (fillGenericTypes(type, name, content, imports, propertyGenericTypes)) {
|
||||
logger.debug("Found injected field " + name + " of type " + type + " with generic types "
|
||||
+ propertyGenericTypes.get(name) + " in controller " + info.controllerFile());
|
||||
} else if (type.contains(".")) {
|
||||
final var simpleName = type.substring(type.lastIndexOf('.') + 1);
|
||||
if (fillGenericTypes(simpleName, name, content, imports, propertyGenericTypes)) {
|
||||
logger.debug("Found injected field " + name + " of type " + simpleName + " with generic types "
|
||||
+ propertyGenericTypes.get(name) + " in controller " + info.controllerFile());
|
||||
}
|
||||
} else {
|
||||
throw new MojoExecutionException("Cannot find field " + name + "(" + type + ")" + " in controller " + info.controllerFile());
|
||||
}
|
||||
}
|
||||
final var handlerHasArgument = new HashMap<String, Boolean>();
|
||||
for (final var name : info.injectedMethods()) {
|
||||
final var pattern = Pattern.compile("void\\s+" + Pattern.quote(name) + "\\s*\\((?<arg>[^)]*)\\)");
|
||||
final var matcher = pattern.matcher(content);
|
||||
if (matcher.find()) {
|
||||
final var arg = matcher.group("arg");
|
||||
handlerHasArgument.put(name, arg != null && !arg.isBlank());
|
||||
logger.debug("Found injected method " + name + " with argument " + arg + " in controller " + info.controllerFile());
|
||||
} else {
|
||||
throw new MojoExecutionException("Cannot find method " + name + " in controller " + info.controllerFile());
|
||||
}
|
||||
}
|
||||
return new ControllerInfoImpl(handlerHasArgument, propertyGenericTypes);
|
||||
} catch (final IOException e) {
|
||||
throw new MojoExecutionException("Error reading controller " + info.controllerFile(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Imports getImports(final CharSequence content) throws MojoExecutionException {
|
||||
final var resolved = new HashMap<String, String>();
|
||||
final var unresolved = new HashSet<String>();
|
||||
final var matcher = IMPORT_PATTERN.matcher(content);
|
||||
while (matcher.find()) {
|
||||
final var value = matcher.group("import");
|
||||
if (value.endsWith(".*")) {
|
||||
final var packagePath = value.substring(0, value.length() - 2);
|
||||
try {
|
||||
final var classes = ClassesFinder.getClasses(packagePath);
|
||||
if (classes.isEmpty()) {
|
||||
unresolved.add(packagePath);
|
||||
} else {
|
||||
classes.forEach(s -> resolved.put(s.substring(packagePath.length() + 1), s));
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new MojoExecutionException("Error reading package " + packagePath, e);
|
||||
}
|
||||
} else {
|
||||
final var simpleName = value.substring(value.lastIndexOf('.') + 1);
|
||||
resolved.put(simpleName, value);
|
||||
}
|
||||
}
|
||||
return new Imports(resolved, unresolved);
|
||||
}
|
||||
|
||||
private static boolean fillGenericTypes(final String type, final String name, final CharSequence content, final Imports imports, final Map<? super String, ? super List<String>> propertyGenericTypes) throws MojoExecutionException {
|
||||
final var pattern = Pattern.compile(Pattern.quote(type) + "(?<type><[^>]+>)?\\s+" + Pattern.quote(name) + "\\s*;");
|
||||
final var matcher = pattern.matcher(content);
|
||||
if (matcher.find()) {
|
||||
final var genericTypes = matcher.group("type");
|
||||
if (genericTypes != null && !genericTypes.isBlank()) {
|
||||
if (genericTypes.equals("<>")) {
|
||||
propertyGenericTypes.put(name, List.of());
|
||||
} else {
|
||||
final var split = genericTypes.replace("<", "").replace(">", "").split(",");
|
||||
final var resolved = new ArrayList<String>();
|
||||
for (final var s : split) {
|
||||
final var trimmed = s.trim();
|
||||
if (trimmed.contains(".") || JAVA_LANG_CLASSES.contains(trimmed)) {
|
||||
resolved.add(trimmed);
|
||||
} else {
|
||||
final var imported = imports.imports().get(trimmed);
|
||||
if (imported == null) {
|
||||
throw new MojoExecutionException("Cannot find class " + trimmed + " probably in one of " + imports.packages() + " ; " +
|
||||
"Use non-wildcard imports, use fully qualified name or put the classes in a dependency.");
|
||||
} else {
|
||||
resolved.add(imported);
|
||||
}
|
||||
}
|
||||
}
|
||||
propertyGenericTypes.put(name, resolved);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private record Imports(Map<String, String> imports, Set<String> packages) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,188 @@
|
||||
package com.github.gtache.fxml.compiler.maven;
|
||||
|
||||
import com.github.gtache.fxml.compiler.ControllerInjection;
|
||||
import com.github.gtache.fxml.compiler.GenerationException;
|
||||
import com.github.gtache.fxml.compiler.impl.ControllerFieldInjectionTypes;
|
||||
import com.github.gtache.fxml.compiler.impl.ControllerInjectionImpl;
|
||||
import com.github.gtache.fxml.compiler.impl.ControllerMethodsInjectionType;
|
||||
import com.github.gtache.fxml.compiler.impl.GenerationParametersImpl;
|
||||
import com.github.gtache.fxml.compiler.impl.GenerationRequestImpl;
|
||||
import com.github.gtache.fxml.compiler.impl.GeneratorImpl;
|
||||
import com.github.gtache.fxml.compiler.impl.ResourceBundleInjectionImpl;
|
||||
import com.github.gtache.fxml.compiler.impl.ResourceBundleInjectionTypes;
|
||||
import com.github.gtache.fxml.compiler.parsing.ParseException;
|
||||
import com.github.gtache.fxml.compiler.parsing.xml.DOMFXMLParser;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Main mojo for FXML compiler
|
||||
*/
|
||||
@Mojo(name = "fxml-compile", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
|
||||
@Mojo(name = "compile", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
|
||||
public class FXMLCompilerMojo extends AbstractMojo {
|
||||
private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
|
||||
|
||||
@Parameter(defaultValue = "${project}", required = true, readonly = true)
|
||||
private MavenProject project;
|
||||
|
||||
@Parameter(defaultValue = "${project.build.directory}/generated-sources", required = true)
|
||||
@Parameter(property = "output-directory", defaultValue = "${project.build.directory}/generated-sources/java", required = true)
|
||||
private Path outputDirectory;
|
||||
|
||||
@Parameter(property = "field-injection", defaultValue = "REFLECTION", required = true)
|
||||
private ControllerFieldInjectionTypes fieldInjectionTypes;
|
||||
|
||||
@Parameter(property = "method-injection", defaultValue = "REFLECTION", required = true)
|
||||
private ControllerMethodsInjectionType methodsInjectionType;
|
||||
|
||||
@Parameter(property = "bundle-injection", defaultValue = "CONSTRUCTOR", required = true)
|
||||
private ResourceBundleInjectionTypes bundleInjectionType;
|
||||
|
||||
@Parameter(property = "bundle-map")
|
||||
private Map<String, String> bundleMap;
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||
public void execute() throws MojoExecutionException {
|
||||
final var fxmls = getAllFXMLs();
|
||||
final var controllerMapping = createControllerMapping(fxmls);
|
||||
final var mapping = createMapping(fxmls, controllerMapping);
|
||||
compile(mapping);
|
||||
}
|
||||
|
||||
private Map<Path, Path> getAllFXMLs() throws MojoExecutionException {
|
||||
final var map = new HashMap<Path, Path>();
|
||||
for (final var resource : project.getResources()) {
|
||||
final var location = resource.getLocation("");
|
||||
location.toString();
|
||||
final var path = Paths.get(resource.getDirectory());
|
||||
if (Files.isDirectory(path)) {
|
||||
try (final var stream = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.toString().endsWith(".fxml"), FileVisitOption.FOLLOW_LINKS)) {
|
||||
final var curList = stream.toList();
|
||||
getLog().info("Found " + curList);
|
||||
for (final var p : curList) {
|
||||
map.put(p, path);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new MojoExecutionException("Error reading resources", e);
|
||||
}
|
||||
} else {
|
||||
getLog().info("Directory " + path + " does not exist");
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static Map<Path, String> createControllerMapping(final Map<? extends Path, ? extends Path> fxmls) throws MojoExecutionException {
|
||||
final var mapping = new HashMap<Path, String>();
|
||||
for (final var fxml : fxmls.keySet()) {
|
||||
mapping.put(fxml, getControllerClass(fxml));
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private static String getControllerClass(final Path fxml) throws MojoExecutionException {
|
||||
try {
|
||||
final var documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
|
||||
final var document = documentBuilder.parse(fxml.toFile());
|
||||
document.getDocumentElement().normalize();
|
||||
|
||||
final var controller = document.getDocumentElement().getAttribute("fx:controller");
|
||||
if (controller.isBlank()) {
|
||||
throw new MojoExecutionException("Missing controller attribute for " + fxml);
|
||||
} else {
|
||||
return controller;
|
||||
}
|
||||
} catch (final SAXException | IOException | ParserConfigurationException e) {
|
||||
throw new MojoExecutionException("Error parsing fxml at " + fxml, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Path, CompilationInfo> createMapping(final Map<? extends Path, ? extends Path> fxmls, final Map<? extends Path, String> controllerMapping) throws MojoExecutionException {
|
||||
final var compilationInfoProvider = new CompilationInfoProvider(project, outputDirectory, getLog());
|
||||
final var mapping = new HashMap<Path, CompilationInfo>();
|
||||
for (final var entry : fxmls.entrySet()) {
|
||||
final var info = compilationInfoProvider.getCompilationInfo(entry.getValue(), entry.getKey(), controllerMapping);
|
||||
mapping.put(entry.getKey(), info);
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private void compile(final Map<Path, CompilationInfo> mapping) throws MojoExecutionException {
|
||||
final var generator = new GeneratorImpl();
|
||||
final var parser = new DOMFXMLParser();
|
||||
final var controllerInfoProvider = new ControllerInfoProvider(getLog());
|
||||
try {
|
||||
for (final var entry : mapping.entrySet()) {
|
||||
final var inputPath = entry.getKey();
|
||||
final var info = entry.getValue();
|
||||
getLog().info("Parsing " + inputPath + " with " + parser.getClass().getSimpleName());
|
||||
final var root = parser.parse(inputPath);
|
||||
final var controllerInjection = getControllerInjection(mapping, info);
|
||||
final var sourceToGeneratedClassName = getSourceToGeneratedClassName(mapping, info);
|
||||
final var sourceToControllerName = getSourceToControllerName(mapping, info);
|
||||
final var resourceBundleInjection = new ResourceBundleInjectionImpl(bundleInjectionType, getBundleName(info));
|
||||
final var parameters = new GenerationParametersImpl(controllerInjection, sourceToGeneratedClassName, sourceToControllerName, resourceBundleInjection);
|
||||
final var controllerInfo = controllerInfoProvider.getControllerInfo(info);
|
||||
final var output = info.outputFile();
|
||||
final var request = new GenerationRequestImpl(parameters, controllerInfo, root, info.outputClass());
|
||||
getLog().info("Compiling " + inputPath);
|
||||
final var content = generator.generate(request);
|
||||
final var outputDirectory = output.getParent();
|
||||
Files.createDirectories(outputDirectory);
|
||||
Files.writeString(output, content);
|
||||
getLog().info("Compiled " + inputPath + " to " + output);
|
||||
}
|
||||
} catch (final IOException | RuntimeException | ParseException | GenerationException e) {
|
||||
throw new MojoExecutionException("Error compiling fxml", e);
|
||||
}
|
||||
project.addCompileSourceRoot(outputDirectory.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
private String getBundleName(final CompilationInfo info) {
|
||||
return bundleMap == null ? "" : bundleMap.getOrDefault(info.inputFile().toString(), "");
|
||||
}
|
||||
|
||||
private static Map<String, String> getSourceToControllerName(final Map<Path, CompilationInfo> mapping, final CompilationInfo info) {
|
||||
final var ret = new HashMap<String, String>();
|
||||
for (final var entry : info.includes().entrySet()) {
|
||||
ret.put(entry.getKey(), mapping.get(entry.getValue()).controllerClass());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static Map<String, String> getSourceToGeneratedClassName(final Map<Path, CompilationInfo> mapping, final CompilationInfo info) {
|
||||
final var ret = new HashMap<String, String>();
|
||||
for (final var entry : info.includes().entrySet()) {
|
||||
ret.put(entry.getKey(), mapping.get(entry.getValue()).outputClass());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private Map<String, ControllerInjection> getControllerInjection(final Map<Path, CompilationInfo> compilationInfoMapping, final CompilationInfo info) {
|
||||
final var ret = new HashMap<String, ControllerInjection>();
|
||||
ret.put(info.controllerClass(), getControllerInjection(info));
|
||||
for (final var entry : info.includes().entrySet()) {
|
||||
final var key = entry.getKey();
|
||||
final var value = entry.getValue();
|
||||
final var subInfo = compilationInfoMapping.get(value);
|
||||
ret.put(key, getControllerInjection(subInfo));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private ControllerInjection getControllerInjection(final CompilationInfo info) {
|
||||
return new ControllerInjectionImpl(fieldInjectionTypes, methodsInjectionType, info.controllerClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.github.gtache.fxml.compiler.maven;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Info about a field
|
||||
*
|
||||
* @param type The field type
|
||||
* @param name The field name
|
||||
*/
|
||||
record FieldInfo(String type, String name) {
|
||||
FieldInfo {
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user