Hard to reproduce Unsupported target type
Hi, we run openjdk 17.0.2 with graal compiler in version 21.3.0. Today we experienced following error.
Cannot convert '93086195' (language: Java, type: java.lang.String) to Java type 'java.lang.String[]': Unsupported target type.
Signature of the failing method looks like this:
@Override
@HostAccess.Export
public DataBuilder addData(String... identifiers) {
... do some stuff
}
// called like x.addData('xyz');
It happened for the first time and only on 1 out of 50 nodes. May it be some unwanted compiler optimization? May it be related to using varargs? Is there some way we can confirm what happened without restarting app - it will most likely fix the problem.
Hi @hejcz
thanks for reporting that issue. We are not already aware of any problem in that area. I am trying to reproduce your issue, but have not been lucky so far. I can also not see any recent change around that specific error.
What is interesting is that java.lang.String[] is mentioned and the exact error is Unsupported target type. In most cases, the error I can reproduce if I force it by providing wrong data is on the string primitive (non-array) and the message is Invalid or lossy primitive coercion. I can only get your message if I use String[] instead of String... on the Java side.
I'll further try to reproduce the issue, but it might only trigger on your specific setup and/or code patterns used.
Do you pass in one String or several? do you pass them as an argument list or as an array? As you do @Override: does the parent have a method of the exact same signature? Is there any method the compiler might confuse this with (even though it should not according to Java semantics), in this class or in the parent?
Best, Christian
Hi @wirthi, we use graaljs for over a year and this situation happened for the first time so I guess it might be tricky to reproduce it. The script works as expected in our unit tests and on the other instances of an app so I believe we can just restart an app and forget about the issue for another year, but I thought that maybe you'll be able to provide some thoughts on it. Regarding your questions:
- we pass single string like this
objectFromHost.addData('xyz') - signature in an interface is exactly the same but without
@HostAccess.Export - there are no other methods with the same name in the interface and the class. Here is our setup for graal context:
static boolean isNullOrUndefined(String str) {
return str == null || str.equals("null") || str.equals("undefined");
}
static Double parseDoubleOrReturnNan(String str) {
try {
return Double.valueOf(str);
} catch (NumberFormatException ignored) {
return Double.NaN;
}
}
private static String doubleToString(Double obj) {
if (Double.isNaN(obj)) {
return "NaN";
}
if (Double.isInfinite(obj)) {
return "Infinity";
}
return BigDecimal.valueOf(obj).stripTrailingZeros().toPlainString();
}
HostAccess hostAccess = HostAccess.newBuilder()
.allowAccessAnnotatedBy(HostAccess.Export.class)
.allowListAccess(true)
.targetTypeMapping(String.class, Double.class, str -> true,
str -> GraalJsonUtils.isNullOrUndefined(str) ? null
: GraalJsonUtils.parseDoubleOrReturnNan(str))
.targetTypeMapping(String.class, Integer.class, str -> true,
str -> GraalJsonUtils.isNullOrUndefined(str) ? null : Integer.valueOf(str))
.targetTypeMapping(Double.class, String.class, obj -> true,
obj -> obj == null ? null : doubleToString(obj))
.targetTypeMapping(String[].class, String.class, Objects::nonNull,
array -> array.length == 0 ? null : array[0])
.targetTypeMapping(Object.class, String.class, obj -> true,
obj -> obj == null ? null : obj.toString())
.targetTypeMapping(String[].class, String[].class, Objects::isNull, array -> new String[] {})
.build();
Context context = Context.newBuilder("js")
.engine(Engine.newBuilder().build())
.allowCreateProcess(false)
.allowCreateThread(false)
.allowEnvironmentAccess(EnvironmentAccess.NONE)
.allowHostClassLoading(false)
.allowHostClassLookup(null)
.allowIO(false)
.allowNativeAccess(false)
.allowPolyglotAccess(PolyglotAccess.NONE)
.allowHostAccess(hostAccess)
.option("js.strict", "true")
.allowExperimentalOptions(true)
.option("js.interop-complete-promises", "true")
.option("js.console", consoleEnabled ? "true" : "false")
.option("js.foreign-object-prototype", "true")
.option("js.graal-builtin", "false")
.option("js.regexp-static-result", "false")
.option("js.java-package-globals", "false")
.option("js.global-property", "false")
.option("js.performance", "false")
.option("js.print", "false")
.option("js.load", "false")
.option("js.disable-eval", evalEnabled ? "false" : "true")
.resourceLimits(null)
.build();
The fact that we don't have this problem on the other instances of an app made me think about some compilation problem where under specific circumstances String... was changed to String[].
Hi @wirthi , any news on this issue?
Hi,
we are currently trying to figure out if there is anything we can suggest based on the error message or your settings. I don't have strong hopes though to identify such a rare occurrence.
Christian
Hi guys, have you spotted anything interesting? The problem seems to happen from time to time. Is there anything I can do to help like enabling some debug mode or switch?
@wirthi Hi, just wanted to let you know that in openjdk 18 and graal 21.3.2.1the problem occurred in all our apps using graal just after restart. As we couldn't find the solution we just deprecated varargs methods and moved to single param and array overloads.
Have you found anything related to this issue? If you don't have plans to fix it you can close this ticket.
Hi,
no, sorry, we have no clue, I believe you are the only one to have ever reported that.
I see you are running on OpenJDK (18). This means, you are not on GraalVM, but you pull in the respective JARs and setup everything yourself? That is possible, but not really supported from our side (and not extensively tested) - we assume everything is executed in a full GraalVM. I don't see how this can trigger your problem, but it might.
The only thing I see how we can help you on this is if you can minify the problem to a code example we can execute on our machines. Then we could debug it.
Best, Christian