Skip to content

Commit ca917af

Browse files
committed
[GR-47056] Do not print reflection warnings in JSON files.
PullRequest: graal/15083
2 parents 7416cea + bfa8f86 commit ca917af

File tree

8 files changed

+109
-73
lines changed

8 files changed

+109
-73
lines changed

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public void printJson(JsonWriter writer) throws IOException {
143143

144144
@Override
145145
public ConfigurationParser createParser() {
146-
return new ReflectionConfigurationParser<>(new ParserConfigurationAdapter(this), true);
146+
return new ReflectionConfigurationParser<>(new ParserConfigurationAdapter(this), true, false);
147147
}
148148

149149
@Override

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,12 @@ public static final class Options {
8181
public static final HostedOptionKey<LocatableMultiOptionValue.Strings> SerializationDenyConfigurationResources = new HostedOptionKey<>(
8282
LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
8383

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

9092
@Option(help = "Files describing program elements to be made accessible via JNI (for syntax, see ReflectionConfigurationFiles)", type = OptionType.User)//
@@ -99,15 +101,20 @@ public static final class Options {
99101
@Option(help = "Resources describing stubs allowing foreign calls.", type = OptionType.User)//
100102
public static final HostedOptionKey<LocatableMultiOptionValue.Strings> ForeignResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
101103

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

109-
@Option(help = "Causes unknown attributes in configuration objects to abort the image build instead of emitting a warning.")//
113+
@Option(help = "When configuration files do not match their schema, abort the image build instead of emitting a warning.")//
110114
public static final HostedOptionKey<Boolean> StrictConfiguration = new HostedOptionKey<>(false);
115+
116+
@Option(help = "Warn when reflection and JNI configuration files have elements that could not be found on the classpath or modulepath.", type = OptionType.Expert)//
117+
public static final HostedOptionKey<Boolean> WarnAboutMissingReflectionOrJNIMetadataElements = new HostedOptionKey<>(false);
111118
}
112119

113120
public static List<Path> findConfigurationFiles(String fileName) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ public static InputStream openStream(URI uri) throws IOException {
6262
public static final String CONDITIONAL_KEY = "condition";
6363
public static final String TYPE_REACHABLE_KEY = "typeReachable";
6464
private final Map<String, Set<String>> seenUnknownAttributesByType = new HashMap<>();
65-
private final boolean strictConfiguration;
65+
private final boolean strictSchema;
6666

6767
protected ConfigurationParser(boolean strictConfiguration) {
68-
this.strictConfiguration = strictConfiguration;
68+
this.strictSchema = strictConfiguration;
6969
}
7070

7171
public void parseAndRegister(URI uri) throws IOException {
@@ -121,14 +121,20 @@ protected void checkAttributes(EconomicMap<String, Object> map, String type, Col
121121

122122
if (unknownAttributes.size() > 0) {
123123
String message = "Unknown attribute(s) [" + String.join(", ", unknownAttributes) + "] in " + type;
124-
warnOrFail(message);
124+
warnOrFailOnSchemaError(message);
125125
Set<String> unknownAttributesForType = seenUnknownAttributesByType.computeIfAbsent(type, key -> new HashSet<>());
126126
unknownAttributesForType.addAll(unknownAttributes);
127127
}
128128
}
129129

130-
protected void warnOrFail(String message) {
131-
if (strictConfiguration) {
130+
/**
131+
* Used to warn about schema errors in configuration files. Should never be used if the type is
132+
* missing.
133+
*
134+
* @param message message to be displayed.
135+
*/
136+
protected void warnOrFailOnSchemaError(String message) {
137+
if (strictSchema) {
132138
throw new JSONParserException(message);
133139
} else {
134140
LogUtils.warning(message);
@@ -182,7 +188,7 @@ protected ConfigurationCondition parseCondition(EconomicMap<String, Object> data
182188
if (conditionType instanceof String) {
183189
return ConfigurationCondition.create((String) conditionType);
184190
} else {
185-
warnOrFail("'" + TYPE_REACHABLE_KEY + "' should be of type string");
191+
warnOrFailOnSchemaError("'" + TYPE_REACHABLE_KEY + "' should be of type string");
186192
}
187193
}
188194
return ConfigurationCondition.alwaysTrue();

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,15 @@ public final class ReflectionConfigurationParser<T> extends ConfigurationParser
5252
"allDeclaredClasses", "allRecordComponents", "allPermittedSubclasses", "allNestMembers", "allSigners",
5353
"allPublicClasses", "methods", "queriedMethods", "fields", CONDITIONAL_KEY,
5454
"queryAllDeclaredConstructors", "queryAllPublicConstructors", "queryAllDeclaredMethods", "queryAllPublicMethods", "unsafeAllocated");
55+
private final boolean printMissingElements;
5556

5657
public ReflectionConfigurationParser(ReflectionConfigurationParserDelegate<T> delegate) {
57-
this(delegate, true);
58+
this(delegate, true, false);
5859
}
5960

60-
public ReflectionConfigurationParser(ReflectionConfigurationParserDelegate<T> delegate, boolean strictConfiguration) {
61+
public ReflectionConfigurationParser(ReflectionConfigurationParserDelegate<T> delegate, boolean strictConfiguration, boolean printMissingElements) {
6162
super(strictConfiguration);
63+
this.printMissingElements = printMissingElements;
6264
this.delegate = delegate;
6365
}
6466

@@ -91,7 +93,7 @@ private void parseClass(EconomicMap<String, Object> data) {
9193
*/
9294
TypeResult<T> result = delegate.resolveType(condition, className, true);
9395
if (!result.isPresent()) {
94-
handleError("Could not resolve class " + className + " for reflection configuration.", result.getException());
96+
handleMissingElement("Could not resolve class " + className + " for reflection configuration.", result.getException());
9597
return;
9698
}
9799
T clazz = result.get();
@@ -199,7 +201,7 @@ private void parseClass(EconomicMap<String, Object> data) {
199201
break;
200202
}
201203
} catch (LinkageError e) {
202-
handleError("Could not register " + delegate.getTypeName(clazz) + ": " + name + " for reflection.", e);
204+
handleMissingElement("Could not register " + delegate.getTypeName(clazz) + ": " + name + " for reflection.", e);
203205
}
204206
}
205207
}
@@ -218,9 +220,9 @@ private void parseField(EconomicMap<String, Object> data, T clazz) {
218220
try {
219221
delegate.registerField(clazz, fieldName, allowWrite);
220222
} catch (NoSuchFieldException e) {
221-
handleError("Field " + formatField(clazz, fieldName) + " not found.");
223+
handleMissingElement("Field " + formatField(clazz, fieldName) + " not found.");
222224
} catch (LinkageError e) {
223-
handleError("Could not register field " + formatField(clazz, fieldName) + " for reflection.", e);
225+
handleMissingElement("Could not register field " + formatField(clazz, fieldName) + " for reflection.", e);
224226
}
225227
}
226228

@@ -251,9 +253,9 @@ private void parseMethod(boolean queriedOnly, EconomicMap<String, Object> data,
251253
delegate.registerMethod(queriedOnly, clazz, methodName, methodParameterTypes);
252254
}
253255
} catch (NoSuchMethodException e) {
254-
handleError("Method " + formatMethod(clazz, methodName, methodParameterTypes) + " not found.");
256+
handleMissingElement("Method " + formatMethod(clazz, methodName, methodParameterTypes) + " not found.");
255257
} catch (LinkageError e) {
256-
handleError("Could not register method " + formatMethod(clazz, methodName, methodParameterTypes) + " for reflection.", e);
258+
handleMissingElement("Could not register method " + formatMethod(clazz, methodName, methodParameterTypes) + " for reflection.", e);
257259
}
258260
} else {
259261
try {
@@ -267,7 +269,7 @@ private void parseMethod(boolean queriedOnly, EconomicMap<String, Object> data,
267269
throw new JSONParserException("Method " + formatMethod(clazz, methodName) + " not found");
268270
}
269271
} catch (LinkageError e) {
270-
handleError("Could not register method " + formatMethod(clazz, methodName) + " for reflection.", e);
272+
handleMissingElement("Could not register method " + formatMethod(clazz, methodName) + " for reflection.", e);
271273
}
272274
}
273275
}
@@ -278,7 +280,7 @@ private List<T> parseMethodParameters(T clazz, String methodName, List<Object> t
278280
String typeName = asString(type, "types");
279281
TypeResult<T> typeResult = delegate.resolveType(ConfigurationCondition.alwaysTrue(), typeName, true);
280282
if (!typeResult.isPresent()) {
281-
handleError("Could not register method " + formatMethod(clazz, methodName) + " for reflection.", typeResult.getException());
283+
handleMissingElement("Could not register method " + formatMethod(clazz, methodName) + " for reflection.", typeResult.getException());
282284
return null;
283285
}
284286
result.add(typeResult.get());
@@ -303,15 +305,17 @@ private String formatMethod(T clazz, String methodName, List<T> paramTypes) {
303305
return delegate.getTypeName(clazz) + '.' + methodName + '(' + parameterTypeNames + ')';
304306
}
305307

306-
private static void handleError(String message) {
307-
handleError(message, null);
308+
private void handleMissingElement(String message) {
309+
handleMissingElement(message, null);
308310
}
309311

310-
private static void handleError(String msg, Throwable cause) {
311-
String message = msg;
312-
if (cause != null) {
313-
message += " Reason: " + formatError(cause) + '.';
312+
private void handleMissingElement(String msg, Throwable cause) {
313+
if (printMissingElements) {
314+
String message = msg;
315+
if (cause != null) {
316+
message += " Reason: " + formatError(cause) + '.';
317+
}
318+
LogUtils.warning(message);
314319
}
315-
LogUtils.warning(message);
316320
}
317321
}
Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
One or several (comma-separated) paths to JSON files that specify lists of interfaces that define Java proxy classes.
2-
The structure is an array of arrays of fully qualified interface names.
2+
The JSON structure is described in the following schema:
33

4-
Example:
4+
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/proxy-config-schema-v1.0.0.json
5+
6+
An example file contents follows:
57

68
[
7-
["java.lang.AutoCloseable", "java.util.Comparator"],
8-
["java.util.Comparator"],
9-
["java.util.List"]
9+
{
10+
"condition" : {
11+
"typeReachable" : "org.example.CallingClass"
12+
},
13+
"interfaces" : [
14+
"java.lang.AutoCloseable",
15+
"java.util.Comparator"
16+
]
17+
},
18+
{
19+
"condition" : {
20+
"typeReachable" : "org.example.CallingClass"
21+
},
22+
"interfaces" : [
23+
"java.util.Comparator"
24+
]
25+
}
1026
]

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/ReflectionConfigurationFilesHelp.txt

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,25 @@
11
One or several (comma-separated) paths to JSON files that specify which program elements should be made available via reflection.
2-
The JSON object schema is:
2+
The JSON object schema is described at:
33

4-
{
5-
String name; // fully qualified class name
6-
boolean allDeclaredConstructors; // include all declared constructors, see Class.getDeclaredConstructors()
7-
boolean allPublicConstructors; // include all public constructors, see Class.getConstructors()
8-
boolean allDeclaredMethods; // include all declared methods, see Class.getDeclaredMethods()
9-
boolean allPublicMethods; // include all public methods, see Class.getMethods()
10-
boolean allDeclaredFields; // include all declared fields, see Class.getDeclaredFields()
11-
boolean allPublicFields; // include all public fields, see Class.getFields()
12-
{
13-
String name; // method name
14-
String[] parameterTypes; // parameter types (optional, use if ambiguous)
15-
}[] methods;
16-
{
17-
String name; // field name
18-
}[] fields;
19-
}[];
4+
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reflect-config-schema-v1.0.0.json
205

216
Example:
227

238
[
249
{
10+
"condition" : {
11+
"typeReachable" : "org.example.CallingClass"
12+
},
2513
"name" : "java.lang.Class",
2614
"allDeclaredConstructors" : "true",
2715
"allPublicConstructors" : "true",
2816
"allDeclaredMethods" : "true",
2917
"allPublicMethods" : "true"
3018
},
3119
{
20+
"condition" : {
21+
"typeReachable" : "org.example.CallingClass"
22+
},
3223
"name" : "java.lang.String",
3324
"fields" : [
3425
{ "name" : "value" },
@@ -42,6 +33,9 @@ Example:
4233
]
4334
},
4435
{
36+
"condition" : {
37+
"typeReachable" : "org.example.CallingClass"
38+
},
4539
"name" : "java.lang.String$CaseInsensitiveComparator",
4640
"methods" : [
4741
{ "name" : "compare" }
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
One or several (comma-separated) paths to JSON files that specify lists of serialization configurations.
2-
The structure is an array of elements specifying the target serialization/deserialization class.
2+
The structure is described in the following schema:
3+
4+
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/serialization-config-schema-v1.0.0.json
35

46
Example:
57

68
[
79
{
8-
"condition":{"typeReachable":"app.DataSerializer"},
9-
"name":"java.util.ArrayList"
10+
"condition" : {
11+
"typeReachable" : "app.DataSerializer"
12+
},
13+
"name" : "java.util.ArrayList"
1014
}
1115
]
1216

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

1519
[
16-
"types": [
17-
{"name":"java.lang.Object"}
20+
"types" : [
21+
{
22+
"name" : "java.lang.Object"
23+
}
1824
],
19-
"lambdaCapturingTypes": [
20-
{"name":"java.util.Comparator"}
25+
"lambdaCapturingTypes" : [
26+
{
27+
"name" : "java.util.Comparator"
28+
}
2129
]
2230
]
2331

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

3644
[
3745
{
38-
"condition":{"typeReachable":"org.apache.spark.SparkContext"},
39-
"name":"org.apache.spark.SparkContext$$anonfun$hadoopFile$1",
40-
"customTargetConstructorClass":"java.lang.Object"
46+
"condition" : {
47+
"typeReachable" : "org.apache.spark.SparkContext"
48+
},
49+
"name" : "org.apache.spark.SparkContext$$anonfun$hadoopFile$1",
50+
"customTargetConstructorClass" : "java.lang.Object"
4151
}
4252
]

0 commit comments

Comments
 (0)