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
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,14 +564,16 @@ 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.
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation mentions "a reachability-metadata.json file" (singular) but the native-image-agent generates multiple configuration files (reflect-config.json, resource-config.json, jni-config.json, proxy-config.json, serialization-config.json, and predefined-classes-config.json). The documentation should clarify that multiple metadata files are generated and list them for clarity.

Copilot uses AI. Check for mistakes.

This file is currently created manually by running all the unit tests, and having an agent collect tracing info:
This file 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 write the metadata files to `src/main/resources/META-INF/native-image`.

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-output-dir=${native.image.agent.output.dir}</argLine>
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Maven profile will regenerate all GraalVM metadata files in the output directory, which could overwrite existing hand-crafted configurations like reflect-config.json and reachability-metadata.json. Consider documenting this risk in the README or implementing a mechanism to preserve or merge critical hand-crafted configurations. The agent's config-merge-dir option could be used instead of config-output-dir to merge with existing configurations.

Suggested change
<argLine>${surefire.argline} -agentlib:native-image-agent=config-output-dir=${native.image.agent.output.dir}</argLine>
<argLine>${surefire.argline} -agentlib:native-image-agent=config-merge-dir=${native.image.agent.output.dir}</argLine>

Copilot uses AI. Check for mistakes.
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
255 changes: 255 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,255 @@
[
{
"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":"org.apache.maven.surefire.booter.ForkedBooter",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
Comment on lines +97 to +100
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The jni-config.json includes test framework classes (org.apache.maven.surefire.booter.ForkedBooter) that should not be bundled in production native images. This was captured because the GraalVM agent ran during test execution. Test-specific JNI configurations should be filtered out.

Suggested change
"name":"org.apache.maven.surefire.booter.ForkedBooter",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{

Copilot uses AI. Check for mistakes.
"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":[] }]
},
Comment on lines +1 to +250
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The jni-config.json contains extensive AWT/Swing/ImageIO configurations that may not be necessary for Datafaker's core functionality. These were likely captured during test execution if tests use any UI components or image processing. Consider reviewing whether AWT/Swing support is needed for production use cases, as including these significantly increases native image size and build time.

Copilot uses AI. Check for mistakes.
{
"name":"sun.management.VMManagementImpl",
"fields":[{"name":"compTimeMonitoringSupport"}, {"name":"currentThreadCpuTimeSupport"}, {"name":"objectMonitorUsageSupport"}, {"name":"otherThreadCpuTimeSupport"}, {"name":"remoteDiagnosticCommandsSupport"}, {"name":"synchronizerUsageSupport"}, {"name":"threadAllocatedMemorySupport"}, {"name":"threadContentionMonitoringSupport"}]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"type":"agent-extracted",
"classes":[
]
}
]

80 changes: 80 additions & 0 deletions src/main/resources/META-INF/native-image/proxy-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
[
{
"interfaces":["net.bytebuddy.description.method.MethodDescription$InDefinedShape$AbstractBase$Executable"]
},
{
"interfaces":["net.bytebuddy.description.method.ParameterDescription$ForLoadedParameter$Parameter"]
},
{
"interfaces":["net.bytebuddy.description.method.ParameterList$ForLoadedExecutable$Executable"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDefinition$Sort$AnnotatedType"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$ForLoadedType$Dispatcher"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedExecutableExceptionType$Dispatcher"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedExecutableParameterType$Dispatcher"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedField$Dispatcher"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedMethodReturnType$Dispatcher"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForComponentType$AnnotatedParameterizedType"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForOwnerType$AnnotatedType"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForTypeArgument$AnnotatedParameterizedType"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForTypeVariableBoundType$AnnotatedTypeVariable"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForTypeVariableBoundType$OfFormalTypeVariable$FormalTypeVariable"]
},
{
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForWildcardUpperBoundType$AnnotatedWildcardType"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfClassDesc"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfDirectMethodHandleDesc"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfDirectMethodHandleDesc$ForKind"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfDynamicConstantDesc"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfMethodHandleDesc"]
},
{
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfMethodTypeDesc"]
},
{
"interfaces":["net.bytebuddy.utility.JavaModule$Module"]
},
{
"interfaces":["net.bytebuddy.utility.JavaModule$Resolver"]
}
]
Comment on lines +1 to +80
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proxy-config.json contains only ByteBuddy-related proxies, which are used by Mockito for test mocking. These proxies should not be included in production native image metadata as they are test-specific dependencies. Consider filtering out test framework proxy configurations.

Copilot uses AI. Check for mistakes.
Loading