Skip to content

Commit

Permalink
Introduce a typeReached check for Class.forName
Browse files Browse the repository at this point in the history
  • Loading branch information
vjovanov committed Mar 22, 2024
1 parent 4b1e416 commit c73d231
Show file tree
Hide file tree
Showing 37 changed files with 660 additions and 226 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
"title": "JSON schema for the conditions used in GraalVM Native Image configuration files",
"properties": {
"typeReachable": {
"type": "string",
"deprecated": true,
"$ref": "config-type-schema-v1.0.0.json",
"title": "Fully qualified name of a class that must be reachable in order to register the type <type> for reflection"
},
"typeReached": {
"$ref": "config-type-schema-v1.0.0.json",
"title": "Fully qualified name of a class that must be reached in order to register the type <type> for reflection"
}
},
"required": [
"typeReachable"
"oneOf": [
"typeReachable",
"typeReached"
],
"additionalProperties": false,
"type": "object"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,43 +43,51 @@
import java.util.Objects;

/**
* A condition that describes if a reflectively accessed element in Native Image is visible by the
* A condition that describes if a reflectively-accessed element in Native Image is visible by the
* user.
* <p>
* Currently, there is only one type of condition (<code>typeReached</code>) so this is a single
* Currently, there is only one type of condition (<code>typeReached</code>) so this is a final
* class instead of the class hierarchy. The {@link ConfigurationCondition#type} represents the
* {@link Class<>} that needs to be reached by analysis in order for an element to be visible.
*/
public final class ConfigurationCondition {

/* Cached to save space: it is used as a marker for all non-conditional elements */
private static final ConfigurationCondition JAVA_LANG_OBJECT_REACHED = new ConfigurationCondition(Object.class);
private static final ConfigurationCondition JAVA_LANG_OBJECT_REACHED = new ConfigurationCondition(Object.class, true);

public static ConfigurationCondition alwaysTrue() {
return JAVA_LANG_OBJECT_REACHED;
}

private final Class<?> type;

public static ConfigurationCondition create(Class<?> type) {
private final boolean runtimeChecked;

public static ConfigurationCondition create(Class<?> type, boolean runtimeChecked) {
Objects.requireNonNull(type);
if (JAVA_LANG_OBJECT_REACHED.getType().equals(type)) {
return JAVA_LANG_OBJECT_REACHED;
}
return new ConfigurationCondition(type);
return new ConfigurationCondition(type, runtimeChecked);
}

public boolean isAlwaysTrue() {
return ConfigurationCondition.alwaysTrue().equals(this);
}

private ConfigurationCondition(Class<?> type) {
private ConfigurationCondition(Class<?> type, boolean runtimeChecked) {
this.runtimeChecked = runtimeChecked;
this.type = type;
}

public Class<?> getType() {
return type;
}

public boolean isRuntimeChecked() {
return runtimeChecked;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -88,13 +96,13 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
ConfigurationCondition condition = (ConfigurationCondition) o;
return Objects.equals(type, condition.type);
ConfigurationCondition that = (ConfigurationCondition) o;
return runtimeChecked == that.runtimeChecked && Objects.equals(type, that.type);
}

@Override
public int hashCode() {
return Objects.hash(type);
return Objects.hash(type, runtimeChecked);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,27 @@
import java.util.Objects;

/**
* This is an unresolved version of the {@link ConfigurationCondition} used only during parsing.
* Represents a {@link ConfigurationCondition} during parsing before it is resolved in a context
* of the classpath.
*/
public class UnresolvedConfigurationCondition implements Comparable<UnresolvedConfigurationCondition> {
public final class UnresolvedConfigurationCondition implements Comparable<UnresolvedConfigurationCondition> {
private static final UnresolvedConfigurationCondition JAVA_LANG_OBJECT_REACHED = new UnresolvedConfigurationCondition(Object.class.getTypeName(), true);
public static final String TYPE_REACHED_KEY = "typeReached";
public static final String TYPE_REACHABLE_KEY = "typeReachable";
private final String typeName;
private static final UnresolvedConfigurationCondition JAVA_LANG_OBJECT_REACHED = new UnresolvedConfigurationCondition(Object.class.getTypeName());
private final boolean runtimeChecked;

public static UnresolvedConfigurationCondition create(String typeName) {
public static UnresolvedConfigurationCondition create(String typeName, boolean runtimeChecked) {
Objects.requireNonNull(typeName);
if (JAVA_LANG_OBJECT_REACHED.getTypeName().equals(typeName)) {
return JAVA_LANG_OBJECT_REACHED;
}
return new UnresolvedConfigurationCondition(typeName);
return new UnresolvedConfigurationCondition(typeName, runtimeChecked);
}

protected UnresolvedConfigurationCondition(String typeName) {
private UnresolvedConfigurationCondition(String typeName, boolean runtimeChecked) {
this.typeName = typeName;
this.runtimeChecked = runtimeChecked;
}

public static UnresolvedConfigurationCondition alwaysTrue() {
Expand All @@ -69,6 +74,14 @@ public String getTypeName() {
return typeName;
}

public boolean isRuntimeChecked() {
return runtimeChecked;
}

public boolean isAlwaysTrue() {
return typeName.equals(JAVA_LANG_OBJECT_REACHED.getTypeName());
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -77,26 +90,28 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
UnresolvedConfigurationCondition condition = (UnresolvedConfigurationCondition) o;
return Objects.equals(typeName, condition.typeName);
UnresolvedConfigurationCondition that = (UnresolvedConfigurationCondition) o;
return runtimeChecked == that.runtimeChecked && Objects.equals(typeName, that.typeName);
}

@Override
public int hashCode() {
return Objects.hash(typeName);
return Objects.hash(typeName, runtimeChecked);
}

@Override
public String toString() {
return "[\"typeReachable\": \"" + typeName + "\"" + "]";
public int compareTo(UnresolvedConfigurationCondition o) {
int res = Boolean.compare(runtimeChecked, o.runtimeChecked);
if (res != 0) {
return res;
}
return typeName.compareTo(o.typeName);
}

@Override
public int compareTo(UnresolvedConfigurationCondition c) {
return this.typeName.compareTo(c.typeName);
public String toString() {
var field = runtimeChecked ? TYPE_REACHED_KEY : TYPE_REACHABLE_KEY;
return "[" + field + ": \"" + typeName + "\"" + "]";
}

public boolean isAlwaysTrue() {
return typeName.equals(JAVA_LANG_OBJECT_REACHED.getTypeName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
package com.oracle.svm.configure.config;

import static com.oracle.svm.core.configure.ConfigurationParser.CONDITIONAL_KEY;
import static com.oracle.svm.core.configure.ConfigurationParser.TYPE_REACHABLE_KEY;
import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHABLE_KEY;

import java.io.IOException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private ConfigurationSet deduceConditionalConfiguration(Map<MethodInfo, List<Met
for (List<MethodCallNode> value : methodCallNodes.values()) {
for (MethodCallNode node : value) {
String className = node.methodInfo.getJavaDeclaringClassName();
UnresolvedConfigurationCondition condition = UnresolvedConfigurationCondition.create(className);
UnresolvedConfigurationCondition condition = UnresolvedConfigurationCondition.create(className, false);
var resolveCondition = ConfigurationConditionResolver.identityResolver().resolveCondition(condition);
addConfigurationWithCondition(configurationSet, node.configuration, resolveCondition.get());
}
Expand Down

0 comments on commit c73d231

Please sign in to comment.