Skip to content

Commit 25ebe5b

Browse files
author
ntwigg
committed
Extract JTE out into a compile-only section.
1 parent 9670cc8 commit 25ebe5b

File tree

3 files changed

+173
-131
lines changed

3 files changed

+173
-131
lines changed

build.gradle

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
id 'com.diffplug.blowdryer'
33
id 'com.diffplug.spotless-changelog'
4+
// id 'io.github.davidburstrom.version-compatibility' version '0.5.0' // https://github.com/davidburstrom/version-compatibility-gradle-plugin?tab=readme-ov-file#releases
45
}
56

67
apply from: 干.file('base/java.gradle')
@@ -12,6 +13,26 @@ apply from: 干.file('spotless/java.gradle')
1213
apply from: 干.file('base/maven.gradle')
1314
apply from: 干.file('base/sonatype.gradle')
1415

16+
def NEEDS_GLUE = ['jte']
17+
for (glue in NEEDS_GLUE) {
18+
sourceSets.register(glue) {
19+
compileClasspath += sourceSets.main.output
20+
runtimeClasspath += sourceSets.main.output
21+
java {}
22+
}
23+
}
24+
jar {
25+
for (glue in NEEDS_GLUE) {
26+
from sourceSets.getByName(glue).output.classesDirs
27+
}
28+
}
29+
30+
spotless {
31+
java {
32+
target 'src/**/*.java'
33+
}
34+
}
35+
1536
dependencies {
1637
// reflection for version decoupling
1738
implementation 'org.jooq:joor:0.9.15'
@@ -24,6 +45,8 @@ dependencies {
2445
api "org.eclipse.jetty:jetty-servlet:$VER_JETTY"
2546
// jte codegen
2647
String VER_JTE = '3.2.1'
27-
implementation "gg.jte:jte-runtime:${VER_JTE}"
28-
implementation "gg.jte:jte:${VER_JTE}"
48+
jteCompileOnly gradleApi()
49+
jteCompileOnly "gg.jte:jte-runtime:${VER_JTE}"
50+
jteCompileOnly "gg.jte:jte:${VER_JTE}"
2951
}
52+
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright (C) 2025 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.webtools.jte;
17+
18+
import gg.jte.ContentType;
19+
import gg.jte.TemplateConfig;
20+
import gg.jte.compiler.TemplateParser;
21+
import gg.jte.compiler.TemplateParserVisitorAdapter;
22+
import gg.jte.compiler.TemplateType;
23+
import java.io.File;
24+
import java.io.IOException;
25+
import java.nio.charset.StandardCharsets;
26+
import java.nio.file.Files;
27+
import java.util.LinkedHashMap;
28+
import java.util.LinkedHashSet;
29+
import org.gradle.api.file.FileType;
30+
import org.gradle.work.ChangeType;
31+
import org.gradle.work.InputChanges;
32+
33+
public class JteRenderer {
34+
public static void renderTask(JtePlugin.RenderModelClassesTask task, InputChanges changes) throws IOException {
35+
var templateConfig = new TemplateConfig((ContentType) task.getContentType().get(), task.getPackageName().get());
36+
var renderer = new JteRenderer(task.getInputDir().getAsFile().get(), templateConfig);
37+
for (var change : changes.getFileChanges(task.getInputDir())) {
38+
if (change.getFileType() == FileType.DIRECTORY) {
39+
return;
40+
}
41+
String name = change.getFile().getName();
42+
if (!name.endsWith(".jte") && !name.endsWith(".kte")) {
43+
continue;
44+
}
45+
var targetFileJte = task.getOutputDir().file(change.getNormalizedPath()).get().getAsFile().getAbsolutePath();
46+
var targetFile = new File(targetFileJte.substring(0, targetFileJte.length() - 4) + ".kt");
47+
if (change.getChangeType() == ChangeType.REMOVED) {
48+
targetFile.delete();
49+
} else {
50+
targetFile.getParentFile().mkdirs();
51+
Files.write(targetFile.toPath(), renderer.render(change.getFile()).getBytes(StandardCharsets.UTF_8));
52+
}
53+
}
54+
}
55+
56+
static String convertJavaToKotlin(String javaType) {
57+
if (javaType.equals("boolean")) {
58+
return "Boolean";
59+
} else if (javaType.equals("int")) {
60+
return "Int";
61+
} else {
62+
// e.g. `@param Result<?> records` -> `val records: Result<*>`
63+
return javaType
64+
.replace("<?>", "<*>")
65+
.replace("java.util.Collection", "Collection")
66+
.replace("java.util.List", "List")
67+
.replace("java.util.Map", "Map")
68+
.replace("java.util.Set", "Set");
69+
}
70+
}
71+
72+
final File rootDir;
73+
final TemplateConfig config;
74+
75+
JteRenderer(File rootDir, TemplateConfig config) {
76+
this.rootDir = rootDir;
77+
this.config = config;
78+
}
79+
80+
String render(File file) throws IOException {
81+
var pkg = file.getParentFile().getAbsolutePath().substring(rootDir.getAbsolutePath().length() + 1).replace(File.separatorChar, '.');
82+
var name = file.getName();
83+
var lastDot = name.lastIndexOf('.');
84+
name = name.substring(0, lastDot);
85+
String ext = file.getName().substring(lastDot);
86+
87+
var imports = new LinkedHashSet<String>();
88+
imports.add("gg.jte.TemplateEngine");
89+
imports.add("gg.jte.TemplateOutput");
90+
var params = new LinkedHashMap<String, String>();
91+
92+
new TemplateParser(Files.readString(file.toPath()), TemplateType.Template, new TemplateParserVisitorAdapter() {
93+
@Override
94+
public void onImport(String importClass) {
95+
imports.add(importClass.replace("static ", ""));
96+
}
97+
98+
@Override
99+
public void onParam(String parameter) {
100+
var idxOfColon = parameter.indexOf(':');
101+
if (idxOfColon == -1) { // .jte
102+
// lastIndexOf accounts for valid multiple spaces, e.g `Map<String, String> featureMap`
103+
var spaceIdx = parameter.lastIndexOf(' ');
104+
var type = parameter.substring(0, spaceIdx).trim();
105+
var name = parameter.substring(spaceIdx + 1).trim();
106+
if (name.endsWith("Nullable")) {
107+
type += "?";
108+
}
109+
params.put(name, convertJavaToKotlin(type));
110+
} else { // .kte
111+
var name = parameter.substring(0, idxOfColon).trim();
112+
var type = parameter.substring(idxOfColon + 1).trim();
113+
params.put(name, type);
114+
}
115+
}
116+
}, config).parse();
117+
118+
var builder = new StringBuilder();
119+
builder.append("package " + pkg + "\n");
120+
builder.append("\n");
121+
for (var imp : imports) {
122+
builder.append("import " + imp + "\n");
123+
}
124+
builder.append("\n");
125+
builder.append("class " + name + "(\n");
126+
params.forEach((paramName, type) -> {
127+
builder.append("\tval " + paramName + ": " + type + ",\n");
128+
});
129+
builder.append("\t) : common.JteModel {\n");
130+
builder.append("\n");
131+
builder.append("\toverride fun render(engine: TemplateEngine, output: TemplateOutput) {\n");
132+
builder.append("\t\tengine.render(\"" + pkg.replace('.', '/') + "/" + name + ext + "\", mapOf(\n");
133+
params.forEach((paramName, type) -> {
134+
builder.append("\t\t\t\"" + paramName + "\" to " + paramName + ",\n");
135+
});
136+
builder.append("\t\t), output)\n");
137+
builder.append("\t}\n");
138+
builder.append("}");
139+
return builder.toString();
140+
}
141+
}

src/main/java/com/diffplug/webtools/jte/JtePlugin.java

Lines changed: 7 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,15 @@
1818
import static org.joor.Reflect.on;
1919
import static org.joor.Reflect.onClass;
2020

21-
import gg.jte.ContentType;
22-
import gg.jte.TemplateConfig;
23-
import gg.jte.compiler.TemplateParser;
24-
import gg.jte.compiler.TemplateParserVisitorAdapter;
25-
import gg.jte.compiler.TemplateType;
2621
import java.io.File;
2722
import java.io.IOException;
28-
import java.nio.charset.StandardCharsets;
29-
import java.nio.file.Files;
30-
import java.util.LinkedHashMap;
31-
import java.util.LinkedHashSet;
3223
import org.gradle.api.DefaultTask;
3324
import org.gradle.api.Plugin;
3425
import org.gradle.api.Project;
3526
import org.gradle.api.file.DirectoryProperty;
36-
import org.gradle.api.file.FileType;
3727
import org.gradle.api.plugins.JavaPluginExtension;
3828
import org.gradle.api.provider.Property;
39-
import org.gradle.api.tasks.Input;
40-
import org.gradle.api.tasks.InputDirectory;
41-
import org.gradle.api.tasks.OutputDirectory;
42-
import org.gradle.api.tasks.PathSensitive;
43-
import org.gradle.api.tasks.PathSensitivity;
44-
import org.gradle.api.tasks.SourceSet;
45-
import org.gradle.api.tasks.TaskAction;
46-
import org.gradle.work.ChangeType;
29+
import org.gradle.api.tasks.*;
4730
import org.gradle.work.Incremental;
4831
import org.gradle.work.InputChanges;
4932

@@ -61,18 +44,19 @@ public void apply(Project project) {
6144
task.getInputs().dir(extension.call("getSourceDirectory"));
6245
});
6346

64-
var jteModelsTask = project.getTasks().register("jteModels", RenderModelClasses.class, task -> {
47+
@SuppressWarnings("unchecked")
48+
var jteModelsTask = project.getTasks().register("jteModels", RenderModelClassesTask.class, task -> {
6549
var jteModels = new File(project.getLayout().getBuildDirectory().getAsFile().get(), "jte-models");
6650
main.getJava().srcDir(jteModels);
6751
task.getOutputDir().set(jteModels);
6852
task.getInputDir().set((File) extension.call("getSourceDirectory").call("get").call("toFile").get());
6953
task.getPackageName().set((Property<String>) extension.call("getPackageName").get());
70-
task.getContentType().set((Property<ContentType>) extension.call("getContentType").get());
54+
task.getContentType().set((Property<Enum<?>>) extension.call("getContentType").get());
7155
});
7256
project.getTasks().named("compileKotlin").configure(task -> task.dependsOn(jteModelsTask));
7357
}
7458

75-
public static abstract class RenderModelClasses extends DefaultTask {
59+
public static abstract class RenderModelClassesTask extends DefaultTask {
7660
@Incremental
7761
@PathSensitive(PathSensitivity.RELATIVE)
7862
@InputDirectory
@@ -85,117 +69,11 @@ public static abstract class RenderModelClasses extends DefaultTask {
8569
abstract Property<String> getPackageName();
8670

8771
@Input
88-
abstract Property<ContentType> getContentType();
72+
abstract Property<Enum<?>> getContentType();
8973

9074
@TaskAction
9175
public void render(InputChanges changes) throws IOException {
92-
var templateConfig = new TemplateConfig(getContentType().get(), getPackageName().get());
93-
var renderer = new JteRenderer(getInputDir().getAsFile().get(), templateConfig);
94-
for (var change : changes.getFileChanges(getInputDir())) {
95-
if (change.getFileType() == FileType.DIRECTORY) {
96-
return;
97-
}
98-
String name = change.getFile().getName();
99-
if (!name.endsWith(".jte") && !name.endsWith(".kte")) {
100-
continue;
101-
}
102-
var targetFileJte = getOutputDir().file(change.getNormalizedPath()).get().getAsFile().getAbsolutePath();
103-
var targetFile = new File(targetFileJte.substring(0, targetFileJte.length() - 4) + ".kt");
104-
if (change.getChangeType() == ChangeType.REMOVED) {
105-
targetFile.delete();
106-
} else {
107-
targetFile.getParentFile().mkdirs();
108-
Files.write(targetFile.toPath(), renderer.render(change.getFile()).getBytes(StandardCharsets.UTF_8));
109-
}
110-
}
111-
}
112-
}
113-
114-
static String convertJavaToKotlin(String javaType) {
115-
if (javaType.equals("boolean")) {
116-
return "Boolean";
117-
} else if (javaType.equals("int")) {
118-
return "Int";
119-
} else {
120-
// e.g. `@param Result<?> records` -> `val records: Result<*>`
121-
return javaType
122-
.replace("<?>", "<*>")
123-
.replace("java.util.Collection", "Collection")
124-
.replace("java.util.List", "List")
125-
.replace("java.util.Map", "Map")
126-
.replace("java.util.Set", "Set");
127-
}
128-
}
129-
130-
static class JteRenderer {
131-
final File rootDir;
132-
final TemplateConfig config;
133-
134-
JteRenderer(File rootDir, TemplateConfig config) {
135-
this.rootDir = rootDir;
136-
this.config = config;
137-
}
138-
139-
String render(File file) throws IOException {
140-
var pkg = file.getParentFile().getAbsolutePath().substring(rootDir.getAbsolutePath().length() + 1).replace(File.separatorChar, '.');
141-
var name = file.getName();
142-
var lastDot = name.lastIndexOf('.');
143-
name = name.substring(0, lastDot);
144-
String ext = file.getName().substring(lastDot);
145-
146-
var imports = new LinkedHashSet<String>();
147-
imports.add("gg.jte.TemplateEngine");
148-
imports.add("gg.jte.TemplateOutput");
149-
var params = new LinkedHashMap<String, String>();
150-
151-
new TemplateParser(Files.readString(file.toPath()), TemplateType.Template, new TemplateParserVisitorAdapter() {
152-
@Override
153-
public void onImport(String importClass) {
154-
imports.add(importClass.replace("static ", ""));
155-
}
156-
157-
@Override
158-
public void onParam(String parameter) {
159-
var idxOfColon = parameter.indexOf(':');
160-
if (idxOfColon == -1) { // .jte
161-
// lastIndexOf accounts for valid multiple spaces, e.g `Map<String, String> featureMap`
162-
var spaceIdx = parameter.lastIndexOf(' ');
163-
var type = parameter.substring(0, spaceIdx).trim();
164-
var name = parameter.substring(spaceIdx + 1).trim();
165-
if (name.endsWith("Nullable")) {
166-
type += "?";
167-
}
168-
params.put(name, convertJavaToKotlin(type));
169-
} else { // .kte
170-
var name = parameter.substring(0, idxOfColon).trim();
171-
var type = parameter.substring(idxOfColon + 1).trim();
172-
params.put(name, type);
173-
}
174-
}
175-
}, config).parse();
176-
177-
var builder = new StringBuilder();
178-
builder.append("package " + pkg + "\n");
179-
builder.append("\n");
180-
for (var imp : imports) {
181-
builder.append("import " + imp + "\n");
182-
}
183-
builder.append("\n");
184-
builder.append("class " + name + "(\n");
185-
params.forEach((paramName, type) -> {
186-
builder.append("\tval " + paramName + ": " + type + ",\n");
187-
});
188-
builder.append("\t) : common.JteModel {\n");
189-
builder.append("\n");
190-
builder.append("\toverride fun render(engine: TemplateEngine, output: TemplateOutput) {\n");
191-
builder.append("\t\tengine.render(\"" + pkg.replace('.', '/') + "/" + name + ext + "\", mapOf(\n");
192-
params.forEach((paramName, type) -> {
193-
builder.append("\t\t\t\"" + paramName + "\" to " + paramName + ",\n");
194-
});
195-
builder.append("\t\t), output)\n");
196-
builder.append("\t}\n");
197-
builder.append("}");
198-
return builder.toString();
76+
onClass("com.diffplug.webtools.jte.JteRenderer").call("renderTask", this, changes);
19977
}
20078
}
20179
}

0 commit comments

Comments
 (0)