Skip to content

Commit af2aea5

Browse files
authored
Fix the declared Exceptions of Expression#evaluate() to match those of DoubleValues#doubleValue() (apache#12878)
1 parent b22a9b8 commit af2aea5

File tree

6 files changed

+63
-19
lines changed

6 files changed

+63
-19
lines changed

lucene/CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ Bug Fixes
121121

122122
* GITHUB#12220: Hunspell: disallow hidden title-case entries from compound middle/end
123123

124+
* GITHUB#12878: Fix the declared Exceptions of Expression#evaluate() to match those
125+
of DoubleValues#doubleValue(). (Uwe Schindler)
126+
124127
Other
125128
---------------------
126129

lucene/MIGRATE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ The new implementation of the Javascript expressions compiler no longer supports
122122
Due to the use of `MethodHandle`, classloader isolation is no longer needed, because JS code can only call
123123
MHs that were resolved by the application before using the expressions module.
124124

125+
### `Expression#evaluate()` declares to throw IOException (GITHUB#12878)
126+
127+
The expressions module has changed the `Expression#evaluate()` method signature:
128+
It now declares that it may throw `IOException`. This was an oversight because
129+
compiled expressions call `DoubleValues#doubleValue` behind the scenes, which
130+
may throw `IOException` on index problems, bubbling up unexpectedly to the caller.
131+
125132
## Migration from Lucene 9.0 to Lucene 9.1
126133

127134
### Test framework package migration and module (LUCENE-10301)

lucene/benchmark-jmh/src/java/org/apache/lucene/benchmark/jmh/ExpressionsBenchmark.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.apache.lucene.benchmark.jmh;
1818

1919
import java.io.IOException;
20-
import java.io.UncheckedIOException;
2120
import java.lang.invoke.MethodHandle;
2221
import java.lang.invoke.MethodHandles;
2322
import java.lang.invoke.MethodType;
@@ -83,12 +82,8 @@ private static double ident(double v) {
8382
private static final Expression NATIVE_IDENTITY_EXPRESSION =
8483
new Expression(NATIVE_IDENTITY_NAME, new String[] {"x"}) {
8584
@Override
86-
public double evaluate(DoubleValues[] functionValues) {
87-
try {
88-
return functionValues[0].doubleValue();
89-
} catch (IOException e) {
90-
throw new UncheckedIOException(e);
91-
}
85+
public double evaluate(DoubleValues[] functionValues) throws IOException {
86+
return functionValues[0].doubleValue();
9287
}
9388
};
9489

lucene/expressions/src/java/org/apache/lucene/expressions/Expression.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package org.apache.lucene.expressions;
1818

19+
import java.io.IOException;
1920
import org.apache.lucene.expressions.js.JavascriptCompiler;
2021
import org.apache.lucene.search.DoubleValues;
2122
import org.apache.lucene.search.DoubleValuesSource;
@@ -89,7 +90,7 @@ protected Expression(String sourceText, String[] variables) {
8990
* @param functionValues {@link DoubleValues} for each element of {@link #variables}.
9091
* @return The computed value of the expression for the given document.
9192
*/
92-
public abstract double evaluate(DoubleValues[] functionValues);
93+
public abstract double evaluate(DoubleValues[] functionValues) throws IOException;
9394

9495
/**
9596
* Get a DoubleValuesSource which can compute the value of this expression in the context of the

lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptCompiler.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ public final class JavascriptCompiler {
120120
DOUBLE_VAL_METHOD = getAsmMethod(double.class, "doubleValue"),
121121
PATCH_STACK_METHOD =
122122
getAsmMethod(Throwable.class, "patchStackTrace", Throwable.class, Expression.class);
123+
private static final Type[] EVALUATE_EXCEPTIONS = new Type[] {Type.getType(IOException.class)};
123124
private static final Handle DYNAMIC_CONSTANT_BOOTSTRAP_HANDLE =
124125
new Handle(
125126
Opcodes.H_INVOKESTATIC,
@@ -211,16 +212,6 @@ static Expression compile(String sourceText, Map<String, MethodHandle> functions
211212
return new JavascriptCompiler(sourceText, functions, picky).compileExpression();
212213
}
213214

214-
/**
215-
* This method is unused, it is just here to make sure that the function signatures don't change.
216-
* If this method fails to compile, you also have to change the byte code generator to correctly
217-
* use the FunctionValues class.
218-
*/
219-
@SuppressWarnings({"unused"})
220-
private static void unusedTestCompile(DoubleValues f) throws IOException {
221-
f.doubleValue();
222-
}
223-
224215
/**
225216
* Constructs a compiler for expressions with specific set of functions
226217
*
@@ -355,7 +346,8 @@ private void generateClass(
355346
constructor.endMethod();
356347

357348
final GeneratorAdapter gen =
358-
new GeneratorAdapter(Opcodes.ACC_PUBLIC, EVALUATE_METHOD, null, null, classWriter);
349+
new GeneratorAdapter(
350+
Opcodes.ACC_PUBLIC, EVALUATE_METHOD, null, EVALUATE_EXCEPTIONS, classWriter);
359351

360352
// add a try/catch block to rewrite stack trace of any Throwable
361353
final Label beginTry = gen.newLabel(), endTry = gen.newLabel(), catchHandler = gen.newLabel();
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.lucene.expressions.js;
18+
19+
import java.io.IOException;
20+
import org.apache.lucene.expressions.Expression;
21+
import org.apache.lucene.search.DoubleValues;
22+
23+
/** Some sanity checks with API as those are not detected by {@link JavascriptCompiler} */
24+
public class TestAPISanity extends CompilerTestCase {
25+
26+
// if this class does not compile, the Exception types of evaluate and DoubleValues do not match.
27+
@SuppressWarnings("unused")
28+
private static class SanityExpression extends Expression {
29+
30+
public SanityExpression(String sourceText, String[] variables) {
31+
super(sourceText, variables);
32+
}
33+
34+
@Override
35+
public double evaluate(DoubleValues[] functionValues) throws IOException {
36+
return functionValues[0].doubleValue();
37+
}
38+
}
39+
40+
public void testBytecodeExceptions() throws Exception {
41+
Expression expr = compile("1");
42+
assertArrayEquals(
43+
Expression.class.getDeclaredMethod("evaluate", DoubleValues[].class).getExceptionTypes(),
44+
expr.getClass().getDeclaredMethod("evaluate", DoubleValues[].class).getExceptionTypes());
45+
}
46+
}

0 commit comments

Comments
 (0)