Skip to content

Commit e6e49ac

Browse files
committed
DSL extension and documentation for native image plugin
1 parent cdf8c42 commit e6e49ac

5 files changed

Lines changed: 318 additions & 11 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2009-2026 jMonkeyEngine
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are
7+
* met:
8+
*
9+
* * Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
*
12+
* * Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
*
16+
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17+
* may be used to endorse or promote products derived from this software
18+
* without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
package com.jme3.util;
33+
34+
import java.lang.annotation.ElementType;
35+
import java.lang.annotation.Retention;
36+
import java.lang.annotation.RetentionPolicy;
37+
import java.lang.annotation.Target;
38+
39+
/**
40+
* Marks a class whose constructors, fields, and methods should be preserved for
41+
* reflective access by ahead-of-time compilation and metadata generation tools.
42+
*/
43+
@Retention(RetentionPolicy.RUNTIME)
44+
@Target(ElementType.TYPE)
45+
public @interface PreserveReflection {
46+
}

jme3-nativeimage-plugin/README.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# jMonkeyEngine Native Image Gradle Plugin
2+
3+
The `org.jmonkeyengine.nativeimage` plugin generates GraalVM Native Image
4+
reachability metadata for jMonkeyEngine applications and prepares the native
5+
runtime library layout used by native-image executables.
6+
7+
Use it together with the official GraalVM Build Tools plugin:
8+
9+
```groovy
10+
plugins {
11+
id 'application'
12+
id 'org.graalvm.buildtools.native' version '1.1.0'
13+
id 'org.jmonkeyengine.nativeimage'
14+
}
15+
16+
application {
17+
mainClass = 'com.example.MyGame'
18+
}
19+
20+
graalvmNative {
21+
binaries {
22+
named('main') {
23+
imageName = 'my-game'
24+
mainClass = 'com.example.MyGame'
25+
}
26+
}
27+
}
28+
29+
jmeNativeImage {
30+
useDefaultResourceSettings()
31+
}
32+
```
33+
34+
Build the native executable with:
35+
36+
```bash
37+
./gradlew nativeCompile
38+
```
39+
40+
## Reflection Metadata
41+
42+
The plugin automatically preserves common jME runtime types, such as
43+
`Savable`, `AssetLoader`, `Control`, `Filter`, networking serializers, and
44+
other engine extension points.
45+
46+
For application classes, use the `jmeNativeImage` DSL:
47+
48+
```groovy
49+
jmeNativeImage {
50+
targetType 'com.example.MyNiftyController'
51+
targetType 'com.example.MyCustomAssetLoader'
52+
}
53+
```
54+
55+
`targetType` accepts either a concrete class or a type used as a match target.
56+
If the configured type is an interface or superclass, the generator preserves
57+
matching classes found on the scan classpath.
58+
59+
You can also preserve all classes marked with an annotation:
60+
61+
```groovy
62+
jmeNativeImage {
63+
targetAnnotation 'com.example.ReflectiveEntryPoint'
64+
}
65+
```
66+
67+
jME also provides a built-in annotation for this:
68+
69+
```java
70+
import com.jme3.util.PreserveReflection;
71+
72+
@PreserveReflection
73+
public class MyNiftyController {
74+
public void startGame() {
75+
}
76+
}
77+
```
78+
79+
Classes annotated with `@PreserveReflection` are included by default when this
80+
plugin generates metadata.
81+
82+
83+
## Default Resource Settings
84+
85+
```groovy
86+
jmeNativeImage {
87+
useDefaultResourceSettings()
88+
}
89+
```
90+
91+
adds broad default GraalVM resource settings:
92+
93+
```text
94+
-H:IncludeResources=.*
95+
-H:ExcludeResources=(?i).*\.(class|jar|dylib|so|dll|jnilib)$
96+
```
97+
98+
This includes ordinary resources while avoiding class files, jars, and native
99+
libraries as embedded resources.
100+
101+
You can override those defaults through the DSL:
102+
103+
```groovy
104+
jmeNativeImage {
105+
includeResources 'Interface/.*|Textures/.*|Models/.*'
106+
excludeResources '(?i).*\\.(class|jar|dylib|so|dll|jnilib)$'
107+
}
108+
```
109+
110+
The generated metadata is written under:
111+
112+
```text
113+
build/generated/native-image-metadata/resources/META-INF/native-image/<group>/<project>/
114+
```
115+
116+
## Advanced Usage
117+
118+
The following options are available for unusual cases, but most applications
119+
should not need them. The plugin already scans the main source set resources,
120+
preserves common jME extension points, and supports `@PreserveReflection` for
121+
application classes.
122+
123+
### Resource Globs
124+
125+
A resource glob is an optional path pattern for extra files that should be
126+
included as resources in the generated native image metadata.
127+
128+
It is not a Java class name. It is a resource path inside your application or
129+
dependency jars, using `/` separators.
130+
131+
You usually do not need to configure resource globs for ordinary files under
132+
the project's `src/main/resources`: the plugin scans the main source set
133+
resources and writes metadata for them automatically.
134+
135+
Use `resourceGlob` when a resource is outside the normal main resources scan,
136+
comes from a dependency, is generated by a separate task, or needs to be added
137+
as a broader pattern instead of as a discovered concrete file.
138+
139+
Examples of optional extra resource globs:
140+
141+
```groovy
142+
jmeNativeImage {
143+
resourceGlob 'Interface/**'
144+
resourceGlob 'Textures/**'
145+
resourceGlob 'Models/**/*.j3o'
146+
resourceGlob 'com/example/external-runtime-config.properties'
147+
}
148+
```
149+
150+
Typical jME resources are asset files such as `.j3o`, `.j3m`, `.j3md`, `.png`,
151+
`.jpg`, `.xml`, `.fnt`, `.frag`, `.vert`, and other files loaded through the
152+
asset manager.
153+
154+
### Proxy Interfaces
155+
156+
If your application uses dynamic proxies, configure the interface set:
157+
158+
```groovy
159+
jmeNativeImage {
160+
proxyInterfaceSet([
161+
'com.example.Service',
162+
'com.example.ServiceEvents'
163+
])
164+
}
165+
```
166+
167+
Each `proxyInterfaceSet` entry represents one proxy definition containing the
168+
interfaces implemented by that proxy.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.jmonkeyengine.gradle.nativeimage
2+
3+
import org.gradle.api.model.ObjectFactory
4+
import org.gradle.api.provider.ListProperty
5+
import org.gradle.api.provider.Property
6+
7+
import javax.inject.Inject
8+
9+
/**
10+
* DSL extension for jMonkeyEngine Native Image metadata generation.
11+
*/
12+
class JmeNativeImageExtension {
13+
14+
final ListProperty<String> additionalTargetTypes
15+
final ListProperty<String> additionalTargetAnnotations
16+
final ListProperty<List<String>> additionalProxyInterfaceSets
17+
final ListProperty<String> additionalResourceGlobs
18+
final Property<String> includeResourcesPattern
19+
final Property<String> excludeResourcesPattern
20+
final Property<Boolean> defaultResourceSettings
21+
22+
@Inject
23+
JmeNativeImageExtension(ObjectFactory objects) {
24+
additionalTargetTypes = objects.listProperty(String).convention([])
25+
additionalTargetAnnotations = objects.listProperty(String).convention([])
26+
additionalProxyInterfaceSets = objects.listProperty(List).convention([])
27+
additionalResourceGlobs = objects.listProperty(String).convention([])
28+
includeResourcesPattern = objects.property(String)
29+
excludeResourcesPattern = objects.property(String)
30+
defaultResourceSettings = objects.property(Boolean).convention(false)
31+
}
32+
33+
void targetType(String className) {
34+
additionalTargetTypes.add(className)
35+
}
36+
37+
void targetAnnotation(String annotationClassName) {
38+
additionalTargetAnnotations.add(annotationClassName)
39+
}
40+
41+
void proxyInterfaceSet(Iterable<String> interfaceClassNames) {
42+
additionalProxyInterfaceSets.add(new ArrayList<String>(interfaceClassNames))
43+
}
44+
45+
void resourceGlob(String glob) {
46+
additionalResourceGlobs.add(glob)
47+
}
48+
49+
void includeResources(String pattern) {
50+
includeResourcesPattern.set(pattern)
51+
}
52+
53+
void excludeResources(String pattern) {
54+
excludeResourcesPattern.set(pattern)
55+
}
56+
57+
void useDefaultResourceSettings() {
58+
defaultResourceSettings.set(true)
59+
}
60+
}

jme3-nativeimage-plugin/src/main/groovy/org/jmonkeyengine/gradle/nativeimage/JmeNativeImagePlugin.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class JmeNativeImagePlugin implements Plugin<Project> {
1313

1414
@Override
1515
void apply(Project project) {
16+
project.extensions.create('jmeNativeImage', JmeNativeImageExtension)
1617
URL metadataScript = getClass().getResource('/org/jmonkeyengine/gradle/nativeimage/native-image-metadata.gradle')
1718
if (metadataScript == null) {
1819
throw new IllegalStateException('Unable to locate bundled native image Gradle script.')

0 commit comments

Comments
 (0)