Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ public interface JsonPrinter<T> {
* @see JsonWriter#print(Object)
*/
static <T> void printCollection(JsonWriter writer, Collection<T> collection, Comparator<T> comparator, JsonPrinter<T> elementPrinter) throws IOException {
if (collection.isEmpty()) {
printCollection(writer, collection, comparator, elementPrinter, true, true);
}

/* Utility method to allow printing multiple collections into the same array */
static <T> void printCollection(JsonWriter writer, Collection<T> collection, Comparator<T> comparator, JsonPrinter<T> elementPrinter, boolean arrayStart, boolean arrayEnd) throws IOException {
if (collection.isEmpty() && arrayStart && arrayEnd) {
writer.append("[]");
return;
}
Expand All @@ -66,7 +71,9 @@ static <T> void printCollection(JsonWriter writer, Collection<T> collection, Com
((List<T>) ordered).sort(comparator);
}

writer.appendArrayStart();
if (arrayStart) {
writer.appendArrayStart();
}
boolean separator = false;
for (T t : ordered) {
if (separator) {
Expand All @@ -75,6 +82,8 @@ static <T> void printCollection(JsonWriter writer, Collection<T> collection, Com
elementPrinter.print(t, writer);
separator = true;
}
writer.appendArrayEnd();
if (arrayEnd) {
writer.appendArrayEnd();
}
}
}
33 changes: 9 additions & 24 deletions docs/reference-manual/native-image/ReachabilityMetadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ The _reachability-metadata.json_ configuration contains a single object with one
```json
{
"reflection":[],
"resources":[],
"bundles":[]
"resources":[]
}
```

Expand Down Expand Up @@ -562,13 +561,13 @@ For each registered resource you get:
Java localization support (`java.util.ResourceBundle`) enables to load L10N resources and show messages localized for a specific _locale_.
Native Image needs knowledge of the resource bundles that your application uses so that it can include appropriate resources and program elements to the application.

A simple bundle can be specified in the `bundles` section of _reachability-metadata.json_:
A simple bundle can be specified in the `resources` section of _reachability-metadata.json_:

```json
{
"bundles": [
"resources": [
{
"name":"your.pkg.Bundle"
"bundle": "your.pkg.Bundle"
}
]
}
Expand All @@ -577,26 +576,15 @@ A simple bundle can be specified in the `bundles` section of _reachability-metad
To request a bundle from a specific module:
```json
{
"bundles": [
"resources": [
{
"name":"app.module:module.pkg.Bundle"
"bundle": "app.module:module.pkg.Bundle"
}
]
}
```

By default, resource bundles are included for all locales that are [included into the image](#locales).
Below is the example how to include only specific locales for a bundle:
```json
{
"bundles": [
{
"name": "specific.locales.Bundle",
"locales": ["en", "de", "sk"]
}
]
}
```
Resource bundles are included for all locales that are [included into the image](#locales).

### Locales

Expand Down Expand Up @@ -737,12 +725,9 @@ See below is a sample reachability metadata configuration that you can use in _r
{
"module": "optional.module.of.a.resource",
"glob": "path1/level*/**"
}
],
"bundles": [
},
{
"name": "fully.qualified.bundle.name",
"locales": ["en", "de", "other_optional_locales"]
"bundle": "fully.qualified.bundle.name"
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,37 +64,69 @@
"type": "array",
"default": [],
"items": {
"title": "Resource that should be available",
"type": "object",
"properties": {
"reason": {
"title": "Reason for the resource's inclusion in the metadata",
"$ref": "#/$defs/reason"
},
"condition": {
"title": "Condition under which the resource should be registered for runtime access",
"$ref": "#/$defs/condition"
},
"module": {
"title": "Module containing the resource",
"type": "string",
"default": ""
},
"glob": {
"title": "Resource name or pattern matching multiple resources (accepts * and ** wildcards)",
"type": "string"
"oneOf": [
{
"title": "Resource that should be available",
"type": "object",
"properties": {
"reason": {
"title": "Reason for the resource's inclusion in the metadata",
"$ref": "#/$defs/reason"
},
"condition": {
"title": "Condition under which the resource should be registered for runtime access",
"$ref": "#/$defs/condition"
},
"module": {
"title": "Module containing the resource",
"type": "string",
"default": ""
},
"glob": {
"title": "Resource name or pattern matching multiple resources (accepts * and ** wildcards)",
"type": "string"
}
},
"required": [
"glob"
],
"additionalProperties": false
},
{
"title": "Resource bundle that should be available",
"type": "object",
"properties": {
"reason": {
"title": "Reason for the resource bundle's inclusion in the metadata",
"$ref": "#/$defs/reason"
},
"condition": {
"title": "Condition under which the resource bundle should be registered for runtime access",
"$ref": "#/$defs/condition"
},
"module": {
"title": "Module containing the resource bundle",
"type": "string",
"default": ""
},
"bundle": {
"title": "Resource bundle name",
"type": "string"
}
},
"required": [
"bundle"
],
"additionalProperties": false
}
},
"required": [
"glob"
],
"additionalProperties": false
]
}
},
"bundles": {
"title": "Metadata to ensure resource bundles are available",
"type": "array",
"default": [],
"deprecated": true,
"items": {
"title": "Resource bundle that should be available",
"type": "object",
Expand Down
11 changes: 9 additions & 2 deletions sdk/src/org.graalvm.nativeimage/snapshot.sigtest
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ cons public init(java.lang.Throwable)
supr java.lang.Throwable
hfds serialVersionUID

CLSS public java.lang.LinkageError
cons public init()
cons public init(java.lang.String)
cons public init(java.lang.String,java.lang.Throwable)
supr java.lang.Error
hfds serialVersionUID

CLSS public java.lang.Exception
cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean)
cons public init()
Expand Down Expand Up @@ -230,7 +237,7 @@ meth public java.lang.Class<?> getDeclaringClass()
meth public java.lang.Class<?> getElementType()
meth public java.lang.String getElementName()
meth public java.lang.String getSignature()
supr java.lang.Error
supr java.lang.LinkageError
hfds declaringClass,elementName,elementType,serialVersionUID,signature

CLSS public final org.graalvm.nativeimage.MissingReflectionRegistrationError
Expand All @@ -239,7 +246,7 @@ meth public java.lang.Class<?> getDeclaringClass()
meth public java.lang.Class<?> getElementType()
meth public java.lang.Class<?>[] getParameterTypes()
meth public java.lang.String getElementName()
supr java.lang.Error
supr java.lang.LinkageError
hfds declaringClass,elementName,elementType,parameterTypes,serialVersionUID

CLSS public abstract interface org.graalvm.nativeimage.ObjectHandle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -74,7 +74,7 @@
*
* @since 24.1
*/
public final class MissingJNIRegistrationError extends Error {
public final class MissingJNIRegistrationError extends LinkageError {
@Serial private static final long serialVersionUID = -8940056537864516986L;

private final Class<?> elementType;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -91,7 +91,7 @@
*
* @since 23.0
*/
public final class MissingReflectionRegistrationError extends Error {
public final class MissingReflectionRegistrationError extends LinkageError {
@Serial private static final long serialVersionUID = 2764341882856270640L;

private final Class<?> elementType;
Expand Down
2 changes: 2 additions & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-60208) Adds the Tracing Agent support for applications using the Foreign Function & Memory (FFM) API. The agent generates FFM configuration in _foreign-config.json_. Additionally, support for FFM configurations has been added to the `native-image-configure` tool.
* (GR-64787) Enable `--install-exit-handlers` by default for executables and deprecate the option. If shared libraries were using this flag, the same functionality can be restored by using `-H:+InstallJavaExitHandlersForSharedLibrary`.
* (GR-47881) Remove the total number of loaded types, fields, and methods from the build output, deprecated these metrics in the build output schema, and removed already deprecated build output metrics.
* (GR-64619) Missing registration errors are now subclasses of `LinkageError`
* (GR-63591) Resource bundle registration is now included as part of the `"resources"` section of _reachability-metadata.json_. When this is the case, the bundle name is specified using the `"bundle"` field.

## GraalVM for JDK 24 (Internal Version 24.2.0)
* (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public static InputStream openStream(URI uri) throws IOException {
public static final String GLOBS_KEY = "globs";
public static final String MODULE_KEY = "module";
public static final String GLOB_KEY = "glob";
public static final String BUNDLE_KEY = "bundle";
private final Map<String, Set<String>> seenUnknownAttributesByType = new HashMap<>();
private final EnumSet<ConfigurationParserOption> parserOptions;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,17 @@ protected ResourceConfigurationParser(ConfigurationConditionResolver<C> conditio
protected void parseBundlesObject(Object bundlesObject) {
List<Object> bundles = asList(bundlesObject, "Attribute 'bundles' must be a list of bundles");
for (Object bundle : bundles) {
parseBundle(bundle);
parseBundle(bundle, false);
}
}

protected abstract UnresolvedConfigurationCondition parseCondition(EconomicMap<String, Object> condition);

private void parseBundle(Object bundle) {
protected void parseBundle(Object bundle, boolean inResourcesSection) {
EconomicMap<String, Object> resource = asMap(bundle, "Elements of 'bundles' list must be a bundle descriptor object");
checkAttributes(resource, "bundle descriptor object", Collections.singletonList("name"), Arrays.asList("locales", "classNames", "condition"));
String basename = asString(resource.get("name"));
String bundleNameAttribute = inResourcesSection ? BUNDLE_KEY : NAME_KEY;
checkAttributes(resource, "bundle descriptor object", Collections.singletonList(bundleNameAttribute), Arrays.asList("locales", "classNames", "condition"));
String basename = asString(resource.get(bundleNameAttribute));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource));
if (!resolvedConfigurationCondition.isPresent()) {
return;
Expand Down Expand Up @@ -121,7 +122,7 @@ protected interface GlobPatternConsumer<T> {
void accept(T a, String b, String c);
}

private void parseGlobEntry(Object data, GlobPatternConsumer<C> resourceRegistry) {
protected void parseGlobEntry(Object data, GlobPatternConsumer<C> resourceRegistry) {
EconomicMap<String, Object> globObject = asMap(data, "Elements of 'globs' list must be a glob descriptor objects");
checkAttributes(globObject, "glob resource descriptor object", Collections.singletonList(GLOB_KEY),
List.of(CONDITIONAL_KEY, MODULE_KEY));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import java.net.URI;
import java.util.EnumSet;
import java.util.List;

import org.graalvm.collections.EconomicMap;

Expand All @@ -40,7 +41,15 @@ final class ResourceMetadataParser<C> extends ResourceConfigurationParser<C> {
public void parseAndRegister(Object json, URI origin) {
Object resourcesJson = getFromGlobalFile(json, RESOURCES_KEY);
if (resourcesJson != null) {
parseGlobsObject(resourcesJson, origin);
List<Object> globsAndBundles = asList(resourcesJson, "'resources' section must be a list of glob pattern or bundle descriptors");
for (Object object : globsAndBundles) {
EconomicMap<String, Object> globOrBundle = asMap(object, "Elements of 'resources' list must be glob pattern or bundle descriptor objects");
if (globOrBundle.containsKey(GLOB_KEY)) {
parseGlobEntry(object, (condition, module, glob) -> registry.addGlob(condition, module, glob, origin));
} else if (globOrBundle.containsKey(BUNDLE_KEY)) {
parseBundle(globOrBundle, true);
}
}
}
Object bundlesJson = getFromGlobalFile(json, BUNDLES_KEY);
if (bundlesJson != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,7 @@ public static List<Path> writeConfigurationToAllPaths(Function<ConfigurationFile
}

public static void printConfigurationToCombinedFile(JsonPrintable config, ConfigurationFile configFile, JsonWriter writer) throws IOException {
if (!configFile.equals(ConfigurationFile.RESOURCES)) {
/*
* Resources are printed at the top level of the object, not in a defined field
*/
writer.quote(configFile.getFieldName()).appendFieldSeparator();
}
writer.quote(configFile.getFieldName()).appendFieldSeparator();
config.printJson(writer);
}

Expand Down
Loading
Loading