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
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,16 +562,28 @@ NATIVE IMAGE
------------

Since version 2.4.1, Datafaker provides **experimental** native-image support.
This is done by providing a `reachability-metadata.json` file in the META-INF directory.
This is done by shipping GraalVM reachability metadata in the `META-INF/native-image` directory. The agent generates
several configuration files, each covering a different aspect of the runtime:

This file is currently created manually by running all the unit tests, and having an agent collect tracing info:
* `reflect-config.json` – classes, methods and fields accessed via reflection
* `resource-config.json` – resources loaded at runtime (including locale `.yml` files)
* `jni-config.json` – JNI-reachable classes, methods and fields
* `proxy-config.json` – dynamic proxy interface lists
* `serialization-config.json` – serialization types
* `predefined-classes-config.json` – classes generated/loaded at runtime

These files can be regenerated by running tests with the GraalVM native-image agent using the provided Maven profile:

```
-agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image
mvn test -Pnative-image-agent -PnoGpg
```

Future enhancements should automate and improve this process, but if you encounter any unexpected behaviour,
feel free to report an issue.
This requires a GraalVM JDK to be installed and configured. The agent will collect tracing info during test execution
and merge the metadata files into `src/main/resources/META-INF/native-image`. The profile uses `config-merge-dir`
so existing hand-crafted configuration (e.g. `reachability-metadata.json`) is preserved. Review the resulting diff
before committing and drop any entries that are specific to the test runtime (JUnit, Surefire, Mockito, ByteBuddy).

If you encounter any unexpected behaviour with native images, feel free to report an issue.

An example usage of this can be found here: https://github.com/datafaker-net/datafaker-native-demo

Expand Down
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -550,5 +550,23 @@
</plugins>
</build>
</profile>
<!-- Profile to generate native-image reachability metadata by running tests with the GraalVM agent -->
<profile>
<id>native-image-agent</id>
<properties>
<native.image.agent.output.dir>${project.basedir}/src/main/resources/META-INF/native-image</native.image.agent.output.dir>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argline} -agentlib:native-image-agent=config-merge-dir=${native.image.agent.output.dir}</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
251 changes: 251 additions & 0 deletions src/main/resources/META-INF/native-image/jni-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
[
{
"name":"[Lsun.java2d.loops.GraphicsPrimitive;"
},
{
"name":"com.apple.eawt._AppEventHandler",
"methods":[{"name":"handleNativeNotification","parameterTypes":["int"] }]
},
{
"name":"com.apple.eawt._AppMenuBarHandler",
"methods":[{"name":"initMenuStates","parameterTypes":["boolean","boolean","boolean","boolean"] }]
},
{
"name":"com.sun.imageio.plugins.jpeg.JPEGImageReader",
"methods":[{"name":"acceptPixels","parameterTypes":["int","boolean"] }, {"name":"passComplete","parameterTypes":[] }, {"name":"passStarted","parameterTypes":["int"] }, {"name":"pushBack","parameterTypes":["int"] }, {"name":"readInputData","parameterTypes":["byte[]","int","int"] }, {"name":"setImageData","parameterTypes":["int","int","int","int","int","byte[]"] }, {"name":"skipInputBytes","parameterTypes":["long"] }, {"name":"skipPastImage","parameterTypes":["int"] }, {"name":"warningOccurred","parameterTypes":["int"] }, {"name":"warningWithMessage","parameterTypes":["java.lang.String"] }]
},
{
"name":"com.sun.imageio.plugins.jpeg.JPEGImageWriter",
"methods":[{"name":"grabPixels","parameterTypes":["int"] }, {"name":"warningOccurred","parameterTypes":["int"] }, {"name":"warningWithMessage","parameterTypes":["java.lang.String"] }, {"name":"writeMetadata","parameterTypes":[] }, {"name":"writeOutputData","parameterTypes":["byte[]","int","int"] }]
},
{
"name":"java.awt.AlphaComposite",
"fields":[{"name":"extraAlpha"}, {"name":"rule"}]
},
{
"name":"java.awt.Color",
"methods":[{"name":"getRGB","parameterTypes":[] }]
},
{
"name":"java.awt.DisplayMode",
"methods":[{"name":"<init>","parameterTypes":["int","int","int","int"] }]
},
{
"name":"java.awt.event.InputEvent",
"methods":[{"name":"getButtonDownMasks","parameterTypes":[] }]
},
{
"name":"java.awt.geom.AffineTransform",
"fields":[{"name":"m00"}, {"name":"m01"}, {"name":"m02"}, {"name":"m10"}, {"name":"m11"}, {"name":"m12"}]
},
{
"name":"java.awt.geom.Path2D",
"fields":[{"name":"numTypes"}, {"name":"pointTypes"}, {"name":"windingRule"}]
},
{
"name":"java.awt.geom.Path2D$Float",
"fields":[{"name":"floatCoords"}]
},
{
"name":"java.awt.geom.Rectangle2D$Double",
"methods":[{"name":"<init>","parameterTypes":["double","double","double","double"] }]
},
{
"name":"java.awt.image.BufferedImage",
"fields":[{"name":"colorModel"}, {"name":"imageType"}, {"name":"raster"}],
"methods":[{"name":"getRGB","parameterTypes":["int","int","int","int","int[]","int","int"] }, {"name":"setRGB","parameterTypes":["int","int","int","int","int[]","int","int"] }]
},
{
"name":"java.awt.image.ColorModel",
"fields":[{"name":"colorSpace"}, {"name":"colorSpaceType"}, {"name":"isAlphaPremultiplied"}, {"name":"is_sRGB"}, {"name":"nBits"}, {"name":"numComponents"}, {"name":"pData"}, {"name":"supportsAlpha"}, {"name":"transparency"}],
"methods":[{"name":"getRGBdefault","parameterTypes":[] }]
},
{
"name":"java.awt.image.IndexColorModel",
"fields":[{"name":"allgrayopaque"}, {"name":"colorData"}, {"name":"map_size"}, {"name":"rgb"}, {"name":"transparent_index"}]
},
{
"name":"java.awt.image.Raster",
"fields":[{"name":"dataBuffer"}, {"name":"height"}, {"name":"minX"}, {"name":"minY"}, {"name":"numBands"}, {"name":"numDataElements"}, {"name":"sampleModel"}, {"name":"sampleModelTranslateX"}, {"name":"sampleModelTranslateY"}, {"name":"width"}]
},
{
"name":"java.awt.image.SampleModel",
"fields":[{"name":"height"}, {"name":"width"}],
"methods":[{"name":"getPixels","parameterTypes":["int","int","int","int","int[]","java.awt.image.DataBuffer"] }, {"name":"setPixels","parameterTypes":["int","int","int","int","int[]","java.awt.image.DataBuffer"] }]
},
{
"name":"java.awt.image.SinglePixelPackedSampleModel",
"fields":[{"name":"bitMasks"}, {"name":"bitOffsets"}, {"name":"bitSizes"}, {"name":"maxBitSize"}]
},
{
"name":"java.lang.String",
"methods":[{"name":"lastIndexOf","parameterTypes":["int"] }, {"name":"substring","parameterTypes":["int"] }]
},
{
"name":"java.lang.System",
"methods":[{"name":"getProperty","parameterTypes":["java.lang.String"] }, {"name":"load","parameterTypes":["java.lang.String"] }, {"name":"setProperty","parameterTypes":["java.lang.String","java.lang.String"] }]
},
{
"name":"javax.imageio.plugins.jpeg.JPEGHuffmanTable",
"fields":[{"name":"lengths"}, {"name":"values"}]
},
{
"name":"javax.imageio.plugins.jpeg.JPEGQTable",
"fields":[{"name":"qTable"}]
},
{
"name":"sun.awt.AWTAutoShutdown",
"methods":[{"name":"notifyToolkitThreadBusy","parameterTypes":[] }, {"name":"notifyToolkitThreadFree","parameterTypes":[] }]
},
{
"name":"sun.awt.SunHints",
"fields":[{"name":"INTVAL_STROKE_PURE"}]
},
{
"name":"sun.awt.image.BufImgSurfaceData$ICMColorData",
"fields":[{"name":"pData"}],
"methods":[{"name":"<init>","parameterTypes":["long"] }]
},
{
"name":"sun.awt.image.ByteComponentRaster",
"fields":[{"name":"data"}, {"name":"dataOffsets"}, {"name":"pixelStride"}, {"name":"scanlineStride"}, {"name":"type"}]
},
{
"name":"sun.awt.image.IntegerComponentRaster",
"fields":[{"name":"data"}, {"name":"dataOffsets"}, {"name":"pixelStride"}, {"name":"scanlineStride"}, {"name":"type"}]
},
{
"name":"sun.instrument.InstrumentationImpl",
"methods":[{"name":"<init>","parameterTypes":["long","boolean","boolean"] }, {"name":"loadClassAndCallAgentmain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"loadClassAndCallPremain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"transform","parameterTypes":["java.lang.Module","java.lang.ClassLoader","java.lang.String","java.lang.Class","java.security.ProtectionDomain","byte[]","boolean"] }]
},
{
"name":"sun.java2d.Disposer",
"methods":[{"name":"addRecord","parameterTypes":["java.lang.Object","long","long"] }]
},
{
"name":"sun.java2d.InvalidPipeException"
},
{
"name":"sun.java2d.NullSurfaceData"
},
{
"name":"sun.java2d.SunGraphics2D",
"fields":[{"name":"clipRegion"}, {"name":"composite"}, {"name":"eargb"}, {"name":"lcdTextContrast"}, {"name":"pixel"}, {"name":"strokeHint"}]
},
{
"name":"sun.java2d.SurfaceData",
"fields":[{"name":"pData"}, {"name":"valid"}]
},
{
"name":"sun.java2d.loops.Blit",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.BlitBg",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.CompositeType",
"fields":[{"name":"AnyAlpha"}, {"name":"Src"}, {"name":"SrcNoEa"}, {"name":"SrcOver"}, {"name":"SrcOverNoEa"}, {"name":"Xor"}]
},
{
"name":"sun.java2d.loops.DrawGlyphList",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawGlyphListAA",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawGlyphListLCD",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawLine",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawParallelogram",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawPath",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawPolygons",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.DrawRect",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.FillParallelogram",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.FillPath",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.FillRect",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.FillSpans",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.GraphicsPrimitive",
"fields":[{"name":"pNativePrim"}]
},
{
"name":"sun.java2d.loops.GraphicsPrimitiveMgr",
"methods":[{"name":"register","parameterTypes":["sun.java2d.loops.GraphicsPrimitive[]"] }]
},
{
"name":"sun.java2d.loops.MaskBlit",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.MaskFill",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.ScaledBlit",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.SurfaceType",
"fields":[{"name":"Any3Byte"}, {"name":"Any4Byte"}, {"name":"AnyByte"}, {"name":"AnyColor"}, {"name":"AnyInt"}, {"name":"AnyShort"}, {"name":"ByteBinary1Bit"}, {"name":"ByteBinary2Bit"}, {"name":"ByteBinary4Bit"}, {"name":"ByteGray"}, {"name":"ByteIndexed"}, {"name":"ByteIndexedBm"}, {"name":"FourByteAbgr"}, {"name":"FourByteAbgrPre"}, {"name":"Index12Gray"}, {"name":"Index8Gray"}, {"name":"IntArgb"}, {"name":"IntArgbBm"}, {"name":"IntArgbPre"}, {"name":"IntBgr"}, {"name":"IntRgb"}, {"name":"IntRgbx"}, {"name":"OpaqueColor"}, {"name":"ThreeByteBgr"}, {"name":"Ushort4444Argb"}, {"name":"Ushort555Rgb"}, {"name":"Ushort555Rgbx"}, {"name":"Ushort565Rgb"}, {"name":"UshortGray"}, {"name":"UshortIndexed"}]
},
{
"name":"sun.java2d.loops.TransformHelper",
"methods":[{"name":"<init>","parameterTypes":["long","sun.java2d.loops.SurfaceType","sun.java2d.loops.CompositeType","sun.java2d.loops.SurfaceType"] }]
},
{
"name":"sun.java2d.loops.XORComposite",
"fields":[{"name":"alphaMask"}, {"name":"xorColor"}, {"name":"xorPixel"}]
},
{
"name":"sun.java2d.opengl.OGLSurfaceData",
"fields":[{"name":"isBIOpShaderEnabled"}, {"name":"isFBObjectEnabled"}, {"name":"isGradShaderEnabled"}, {"name":"isLCDShaderEnabled"}]
},
{
"name":"sun.java2d.pipe.Region",
"fields":[{"name":"bands"}, {"name":"endIndex"}, {"name":"hix"}, {"name":"hiy"}, {"name":"lox"}, {"name":"loy"}]
},
{
"name":"sun.java2d.pipe.RegionIterator",
"fields":[{"name":"curIndex"}, {"name":"numXbands"}, {"name":"region"}]
},
{
"name":"sun.lwawt.macosx.LWCToolkit",
"methods":[{"name":"installToolkitThreadInJava","parameterTypes":[] }]
},
{
"name":"sun.management.VMManagementImpl",
"fields":[{"name":"compTimeMonitoringSupport"}, {"name":"currentThreadCpuTimeSupport"}, {"name":"objectMonitorUsageSupport"}, {"name":"otherThreadCpuTimeSupport"}, {"name":"remoteDiagnosticCommandsSupport"}, {"name":"synchronizerUsageSupport"}, {"name":"threadAllocatedMemorySupport"}, {"name":"threadContentionMonitoringSupport"}]
}
]
Loading
Loading