Skip to content

Commit 9aac928

Browse files
committed
java-json-tools#96: add support for GraalJS script engine on RegExp checks
1 parent 9af226f commit 9aac928

File tree

2 files changed

+50
-12
lines changed

2 files changed

+50
-12
lines changed

src/main/java/com/github/fge/jsonschema/core/util/RegexECMA262Helper.java

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@
4949
* the full story. And if you don't yet have Jeffrey Friedl's "Mastering regular
5050
* expressions", just <a href="http://regex.info">buy it</a> :p</p>
5151
*
52-
* <p>As script engine is used either Nashorn or Rhino as its fallback.
53-
* Nashorn is only available on Java 8 up to 14.</p>
52+
* <p>As script engine is used either GraalJS, Nashorn or Rhino as their
53+
* fallback. Nashorn is only available on Java 8 up to 14.</p>
5454
*
55-
* <p>Rhino is the fallback as it is tremendously slower.</p>
55+
* <p>GraalJS is the first choice as it supports more RegExp features, e.g.
56+
* lookbehind assertions, than both alternatives.</p>
57+
*
58+
* <p>Rhino is the fallback as it is tremendously slower than Nashorn.</p>
5659
*/
5760
@ThreadSafe
5861
public final class RegexECMA262Helper
@@ -89,10 +92,15 @@ private RegexECMA262Helper()
8992

9093
private static RegexScript determineRegexScript()
9194
{
95+
try {
96+
return new GraalJsScript();
97+
} catch(final ScriptException e) {
98+
// most probably GraalJS is simply not available
99+
}
92100
try {
93101
return new NashornScript();
94102
} catch(final ScriptException e) {
95-
// either Nashorn is not available or the JavaScript can't be parsed
103+
// most probably Nashorn is simply not available
96104
}
97105
return new RhinoScript();
98106
}
@@ -134,26 +142,25 @@ private interface RegexScript
134142
boolean regMatch(String regex, String input);
135143
}
136144

137-
private static class NashornScript implements RegexScript
145+
private static abstract class ScriptEngineScript implements RegexScript
138146
{
139147
/**
140148
* Script engine
141149
*/
142150
private final Invocable scriptEngine;
143151

144-
private NashornScript() throws ScriptException
152+
private ScriptEngineScript(final String engineName) throws ScriptException
145153
{
146154
final ScriptEngine engine = new ScriptEngineManager()
147-
.getEngineByName("nashorn");
148-
if (engine == null) {
149-
throw new ScriptException("ScriptEngine 'nashorn' not found.");
155+
.getEngineByName(engineName);
156+
if(engine == null) {
157+
throw new ScriptException("ScriptEngine '" + engineName + "' not found.");
150158
}
151159
engine.eval(jsAsString);
152160
this.scriptEngine = (Invocable) engine;
153161
}
154162

155-
private boolean invokeScriptEngine(final String function,
156-
final Object... values)
163+
boolean invoke(final String function, final Object... values)
157164
{
158165
try {
159166
return (Boolean) scriptEngine.invokeFunction(function,
@@ -178,6 +185,37 @@ public boolean regMatch(final String regex, final String input)
178185
{
179186
return invokeScriptEngine(REG_MATCH_FUNCTION_NAME, regex, input);
180187
}
188+
189+
abstract boolean invokeScriptEngine(final String function, final Object... values);
190+
}
191+
192+
private static class GraalJsScript extends ScriptEngineScript
193+
{
194+
private GraalJsScript() throws ScriptException
195+
{
196+
super("graal.js");
197+
}
198+
199+
// GraalJS works single-threaded. The synchronized ensures this.
200+
@Override
201+
synchronized boolean invokeScriptEngine(final String function,
202+
final Object... values) {
203+
return invoke(function, values);
204+
}
205+
}
206+
207+
private static class NashornScript extends ScriptEngineScript
208+
{
209+
private NashornScript() throws ScriptException
210+
{
211+
super("nashorn");
212+
}
213+
214+
@Override
215+
boolean invokeScriptEngine(final String function,
216+
final Object... values) {
217+
return invoke(function, values);
218+
}
181219
}
182220

183221
private static class RhinoScript implements RegexScript

src/test/java/com/github/fge/jsonschema/core/util/RegexECMA262HelperTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public Iterator<Object[]> ecma262regexes()
7171
{
7272
return ImmutableList.of(
7373
new Object[] { "[^]", true },
74-
new Object[] { "(?<=foo)bar", false },
74+
new Object[] { "(?<=foobar", false },
7575
new Object[] { "", true },
7676
new Object[] { "[a-z]+(?!foo)(?=bar)", true }
7777
).iterator();

0 commit comments

Comments
 (0)