镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
build:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, ubuntu-24.04-arm]
os: [windows-latest, ubuntu-latest, ubuntu-26.04-arm]
runs-on: ${{ matrix.os }}
concurrency: main_tests_${{ github.ref }}_${{ matrix.os }}
steps:
Expand Down Expand Up @@ -64,31 +64,26 @@ jobs:
with:
java-version: 21
distribution: graalvm
# test pipeline to check native support
# Test pipeline to check GraalVM native image support:
#
# - GraalVM is added to the runner
# - A simple native project is build and run
#
# At the something like that should be found in the log :
#
# INFO: name : FreeMarker Native Demo, version : 2.3.35-nightly
# Jan 15, 2025 4:28:19 PM freemarker.log._JULLoggerFactory$JULLogger info
# INFO: result :
# <html>
# <head>
# <title>Hello : FreeMarker GraalVM Native Demo</title>
# </head>
# <body>
# <h1>Hello : FreeMarker GraalVM Native Demo</h1>
# <p>Test template for Apache FreeMarker GraalVM native support (2.3.35-nightly)</p>
# </body>
# </html>
# - GraalVM 21 is added to the runner
# - The freemarker-test-graalvm-native executable is built (nativeCompile) and executed
# - The JUnit 5 native test suite is compiled and executed as a native image (nativeTest),
# exercising a broad percentage of the FreeMarker codebase across core directives,
# ranges/slicing, variadic/recursive macros and functions, built-ins, lambdas, dynamic
# evaluation (?eval, ?eval_json, ?interpret), BeansWrapper (Java records, enums, static
# models, overloaded methods, default/whitelist/blacklist/legacy member access policies),
# template loaders (#include, #import, auto_include, auto_import), TemplateConfiguration
# matchers, output formats, custom directives/methods, custom number/date formats,
# arithmetic engines, exception handlers, XML DOM NodeModel, Properties-based
# configuration, and logger resolution.
- name: Test GraalVM native support (build and run)
id: native_test
if: runner.os != 'Windows'
run: |
./gradlew :freemarker-test-graalvm-native:nativeCompile
./freemarker-test-graalvm-native/build/native/nativeCompile/freemarker-test-graalvm-native
./gradlew :freemarker-test-graalvm-native:nativeTest
- name: Upload Failed Report
uses: actions/upload-artifact@v7
if: failure() && steps.build_step.outcome == 'failure'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log._AvalonLoggerFactory.java",
"name" : "freemarker.log._AvalonLoggerFactory",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
Expand All @@ -29,7 +29,7 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log._CommonsLoggingLoggerFactory.java",
"name" : "freemarker.log._CommonsLoggingLoggerFactory",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
Expand All @@ -38,7 +38,7 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log._JULLoggerFactory.java",
"name" : "freemarker.log._JULLoggerFactory",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
Expand All @@ -47,7 +47,7 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log._Log4jLoggerFactory.java",
"name" : "freemarker.log._Log4jLoggerFactory",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
Expand All @@ -56,7 +56,7 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log._Log4jOverSLF4JTester.java",
"name" : "freemarker.log._Log4jOverSLF4JTester",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
Expand All @@ -65,7 +65,7 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log._NullLoggerFactory.java",
"name" : "freemarker.log._NullLoggerFactory",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
Expand All @@ -74,9 +74,9 @@
"condition" : {
"typeReachable" : "freemarker.template.Configuration"
},
"name" : "freemarker.log.CommonsLoggingLoggerFactory.java",
"name" : "freemarker.log.CommonsLoggingLoggerFactory",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ ]
} ]
} ]
} ]
8 changes: 7 additions & 1 deletion freemarker-test-graalvm-native/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# freemarker-test-graalvm-natice
# freemarker-test-graalvm-native

Test project for GraalVM support. This is not built by default.

Expand Down Expand Up @@ -39,6 +39,12 @@ Test project for GraalVM support. This is not built by default.
</html>
```

4. Run the JUnit test suite inside a GraalVM native image:

```shell
./gradlew :freemarker-test-graalvm-native:nativeTest
```

## CI (GitHub workflow)

GraalVM native test for this module is included in the GitHub [CI](../.github/workflows/ci.yml) workflow.
1 change: 1 addition & 0 deletions freemarker-test-graalvm-native/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ graalvmNative {
binaries.all {
fallback.set(false)
verbose.set(true)
buildArgs.add("--add-exports=java.xml/com.sun.org.apache.xml.internal.utils=ALL-UNNAMED")
configurationFileDirectories.from(file("src/main/graalvm-native-config"))
resources.autodetect()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
[
{
"name": "org.freemarker.core.graal.HelloDataModel",
"allPublicMethods": true
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.freemarker.core.graal.HelloDataModel$Item",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.freemarker.core.graal.HelloDataModel$Status",
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}
]
]
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,34 @@

package org.freemarker.core.graal;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import freemarker.ext.beans.TemplateAccessible;

public class HelloDataModel {

public enum Status {
ACTIVE,
PENDING,
ARCHIVED
}

public record Item(String title, BigDecimal price, boolean inStock, List<String> tags) {
}

public String exposedNote = "public-field-ok";

private String name;

private String version;

private Status status = Status.ACTIVE;

private List<Item> items = new ArrayList<>();

public String getVersion() {
return version;
}
Expand All @@ -33,6 +55,7 @@ public void setVersion(String version) {
this.version = version;
}

@TemplateAccessible
public String getName() {
return name;
}
Expand All @@ -41,4 +64,41 @@ public void setName(String name) {
this.name = name;
}

public Status getStatus() {
return status;
}

public void setStatus(Status status) {
this.status = status;
}

public List<Item> getItems() {
return Collections.unmodifiableList(items);
}

public void setItems(List<Item> items) {
this.items = new ArrayList<>(items);
}

public String formatItem(String label, int quantity) {
return label + " x" + quantity;
}

public String formatItem(String label, String note) {
return label + " (" + note + ")";
}

@TemplateAccessible
public String whitelistedAction() {
return "allowed:" + name;
}

public String getRestrictedSecret() {
return "top-secret";
}

public static String staticGreeting(String target) {
return "Hello from static, " + target + "!";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public class HelloFreeMarker {
private final static Logger log = Logger.getLogger(HelloFreeMarker.class.getName());

public static void main(String[] args) throws Exception {
String output = executeHelloWorld();
log.info(String.format("result :\n%s", output));
}

public static String executeHelloWorld() throws Exception {
// To test native configuration
Class.forName("freemarker.ext.jython.JythonModel");

Expand All @@ -48,7 +53,7 @@ public static void main(String[] args) throws Exception {
// Process template
Template template = cfg.getTemplate("hello-world.ftlh");
template.process(dataModel, buffer);
log.info(String.format("result :\n%s", buffer));
return buffer.toString();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<#--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<#import "macro-lib.ftlh" as lib>
<#include "included-header.ftlh">
<@lib.badge text=name kind="primary"; upperKind>(${upperKind})</@lib.badge>
<#list items>
<ul>
<#items as item>
<li>${item?counter}.${item?item_parity}:${item.title}=${item.price?string("0.00")}[${item.tags?join(",")}]</li>
</#items>
</ul>
<#else>
<p>Empty</p>
</#list>
TotalInStock=${lib.sumPrices(items)?string("0.00")}
OverloadInt=${formatItem("Box", 3)}
OverloadStr=${formatItem("Box", "fragile")}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<#--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<header>[${name} :: ${status}]</header>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<#--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<#macro badge text kind="info"><span class="badge-${kind}">${text}</span><#nested kind?upper_case></#macro>
<#function sumPrices items>
<#local total = 0>
<#list items as item>
<#if item.inStock>
<#local total = total + item.price>
</#if>
</#list>
<#return total>
</#function>
Loading