Skip to content

Commit

Permalink
Fix error messages for JSON config
Browse files Browse the repository at this point in the history
  • Loading branch information
vjovanov committed Aug 8, 2023
1 parent f760369 commit c71766b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ public static final class Options {
public static final HostedOptionKey<LocatableMultiOptionValue.Strings> SerializationDenyConfigurationResources = new HostedOptionKey<>(
LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

@Option(help = "Files describing Java resources to be included in the image.", type = OptionType.User)//
@Option(help = "Files describing Java resources to be included in the image according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/resource-config-schema-v1.0.0.json", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> ResourceConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing Java resources to be included in the image.", type = OptionType.User)//
@Option(help = "Resources describing Java resources to be included in the image according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/resource-config-schema-v1.0.0.json", type = OptionType.User)//
public static final HostedOptionKey<LocatableMultiOptionValue.Strings> ResourceConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

@Option(help = "Files describing program elements to be made accessible via JNI (for syntax, see ReflectionConfigurationFiles)", type = OptionType.User)//
Expand All @@ -93,18 +95,20 @@ public static final class Options {
@Option(help = "Resources describing program elements to be made accessible via JNI (see JNIConfigurationFiles).", type = OptionType.User)//
public static final HostedOptionKey<LocatableMultiOptionValue.Strings> JNIConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

@Option(help = "Files describing predefined classes that can be loaded at runtime.", type = OptionType.User)//
@Option(help = "Files describing predefined classes that can be loaded at runtime according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/predefined-classes-config-schema-v1.0.0.json", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> PredefinedClassesConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing predefined classes that can be loaded at runtime.", type = OptionType.User)//
@Option(help = "Resources describing predefined classes that can be loaded at runtime according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/predefined-classes-config-schema-v1.0.0.json", type = OptionType.User)//
public static final HostedOptionKey<LocatableMultiOptionValue.Strings> PredefinedClassesConfigurationResources = new HostedOptionKey<>(
LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

@Option(help = "When configuration files don't match the schema, abort the image build instead of emitting a warning.")//
@Option(help = "When configuration files do not match their schema, abort the image build instead of emitting a warning.")//
public static final HostedOptionKey<Boolean> StrictConfiguration = new HostedOptionKey<>(false);

@Option(help = "When configuration files don't match the schema, abort the image build instead of emitting a warning.", type = OptionType.Expert)//
public static final HostedOptionKey<Boolean> PrintMissingMetadataElements = new HostedOptionKey<>(false);
@Option(help = "Warn when reflection and JNI configuration files have elements that could not be found on the classpath or modulepath.", type = OptionType.Expert)//
public static final HostedOptionKey<Boolean> WarnAboutMissingReflectionOrJNIMetadataElements = new HostedOptionKey<>(false);
}

public static List<Path> findConfigurationFiles(String fileName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
One or several (comma-separated) paths to JSON files that specify lists of interfaces that define Java proxy classes.
The structure is an array of arrays of fully qualified interface names.
The JSON structure is described in the following schema:

Example:
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/proxy-config-schema-v1.0.0.json

An example file contents follows:

[
["java.lang.AutoCloseable", "java.util.Comparator"],
["java.util.Comparator"],
["java.util.List"]
{
"condition" : {
"typeReachable" : "org.example.CallingClass"
},
"interfaces" : [
"java.lang.AutoCloseable",
"java.util.Comparator"
]
},
{
"condition" : {
"typeReachable" : "org.example.CallingClass"
},
"interfaces" : [
"java.util.Comparator"
]
}
]
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
One or several (comma-separated) paths to JSON files that specify which program elements should be made available via reflection.
The JSON object schema is:
The JSON object schema is described at:

{
String name; // fully qualified class name
boolean allDeclaredConstructors; // include all declared constructors, see Class.getDeclaredConstructors()
boolean allPublicConstructors; // include all public constructors, see Class.getConstructors()
boolean allDeclaredMethods; // include all declared methods, see Class.getDeclaredMethods()
boolean allPublicMethods; // include all public methods, see Class.getMethods()
boolean allDeclaredFields; // include all declared fields, see Class.getDeclaredFields()
boolean allPublicFields; // include all public fields, see Class.getFields()
{
String name; // method name
String[] parameterTypes; // parameter types (optional, use if ambiguous)
}[] methods;
{
String name; // field name
}[] fields;
}[];
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reflect-config-schema-v1.0.0.json

Example:

[
{
"condition" : {
"typeReachable" : "org.example.CallingClass"
},
"name" : "java.lang.Class",
"allDeclaredConstructors" : "true",
"allPublicConstructors" : "true",
"allDeclaredMethods" : "true",
"allPublicMethods" : "true"
},
{
"condition" : {
"typeReachable" : "org.example.CallingClass"
},
"name" : "java.lang.String",
"fields" : [
{ "name" : "value" },
Expand All @@ -42,6 +33,9 @@ Example:
]
},
{
"condition" : {
"typeReachable" : "org.example.CallingClass"
},
"name" : "java.lang.String$CaseInsensitiveComparator",
"methods" : [
{ "name" : "compare" }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
One or several (comma-separated) paths to JSON files that specify lists of serialization configurations.
The structure is an array of elements specifying the target serialization/deserialization class.
The structure is described in the following schema:

https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/serialization-config-schema-v1.0.0.json

Example:

[
{
"condition":{"typeReachable":"app.DataSerializer"},
"name":"java.util.ArrayList"
"condition" : {
"typeReachable" : "app.DataSerializer"
},
"name" : "java.util.ArrayList"
}
]

For deserializing lambda classes, the capturing class of the lambda needs to be specified in a separate section of the configuration file, for example:

[
"types": [
{"name":"java.lang.Object"}
"types" : [
{
"name" : "java.lang.Object"
}
],
"lambdaCapturingTypes": [
{"name":"java.util.Comparator"}
"lambdaCapturingTypes" : [
{
"name" : "java.util.Comparator"
}
]
]

Expand All @@ -35,8 +43,10 @@ serialization-config.json:

[
{
"condition":{"typeReachable":"org.apache.spark.SparkContext"},
"name":"org.apache.spark.SparkContext$$anonfun$hadoopFile$1",
"customTargetConstructorClass":"java.lang.Object"
"condition" : {
"typeReachable" : "org.apache.spark.SparkContext"
},
"name" : "org.apache.spark.SparkContext$$anonfun$hadoopFile$1",
"customTargetConstructorClass" : "java.lang.Object"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
*/
package com.oracle.svm.hosted.config;

import static com.oracle.svm.common.option.CommonOptions.PrintFlags;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
Expand All @@ -49,7 +47,6 @@
import com.oracle.svm.core.configure.ReflectionConfigurationParser;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.option.LocatableMultiOptionValue;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.util.UserError;
import com.oracle.svm.hosted.ImageClassLoader;

Expand All @@ -58,8 +55,7 @@ public final class ConfigurationParserUtils {
public static ReflectionConfigurationParser<ConditionalElement<Class<?>>> create(ReflectionRegistry registry, ImageClassLoader imageClassLoader) {
return new ReflectionConfigurationParser<>(RegistryAdapter.create(registry, imageClassLoader),
ConfigurationFiles.Options.StrictConfiguration.getValue(),
ConfigurationFiles.Options.PrintMissingMetadataElements.getValue()
);
ConfigurationFiles.Options.WarnAboutMissingReflectionOrJNIMetadataElements.getValue());
}

/**
Expand All @@ -76,12 +72,11 @@ public static int parseAndRegisterConfigurations(ConfigurationParser parser, Ima

List<Path> paths = configFilesOption.getValue().values();
List<String> resourceValues = configResourcesOption.getValue().values();
var configFilesOptionName = configFilesOption.getName();
return parseAndRegisterConfigurations(parser, classLoader, featureName, configFilesOptionName, configResourcesOption.getName(), directoryFileName, paths, resourceValues);
return parseAndRegisterConfigurations(parser, classLoader, featureName, directoryFileName, paths, resourceValues);
}

public static int parseAndRegisterConfigurations(ConfigurationParser parser, ImageClassLoader classLoader,
String featureName, String configFilesOptionName, String configResourcesOptionName,
String featureName,
String directoryFileName, List<Path> paths,
List<String> resourceValues) {
int parsedCount = 0;
Expand All @@ -91,7 +86,7 @@ public static int parseAndRegisterConfigurations(ConfigurationParser parser, Ima
if (!Files.exists(path)) {
throw UserError.abort("The %s configuration file \"%s\" does not exist.", featureName, path);
}
doParseAndRegister(parser, featureName, path, configFilesOptionName);
doParseAndRegister(parser, featureName, path);
return 1;
}).sum();

Expand All @@ -118,13 +113,13 @@ public boolean tryAdvance(Consumer<? super URL> action) {
});
Stream<URL> resources = Stream.concat(configResourcesFromOption, ConfigurationFiles.findConfigurationResources(directoryFileName, classLoader.getClassLoader()).stream());
parsedCount += resources.mapToInt(url -> {
doParseAndRegister(parser, featureName, url, configResourcesOptionName);
doParseAndRegister(parser, featureName, url);
return 1;
}).sum();
return parsedCount;
}

private static void doParseAndRegister(ConfigurationParser parser, String featureName, Object location, String optionName) {
private static void doParseAndRegister(ConfigurationParser parser, String featureName, Object location) {
try {
URI uri;
if (location instanceof Path) {
Expand All @@ -138,8 +133,10 @@ private static void doParseAndRegister(ConfigurationParser parser, String featur
if (errorMessage == null || errorMessage.isEmpty()) {
errorMessage = e.toString();
}
throw UserError.abort("Error parsing %s configuration in %s:%n%s%nVerify that the configuration matches the schema described in the %s output for option %s.",
featureName, location, errorMessage, SubstrateOptionsParser.commandArgument(PrintFlags, "+"), optionName);
throw UserError.abort(
"Error parsing %s configuration in %s:%n%s%nVerify that the configuration matches the corresponding schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/",
featureName, location, errorMessage);
}
}
}

0 comments on commit c71766b

Please sign in to comment.