Add a transformer to translate constant BigDecimal to double
This commit is contained in:
parent
50bb274efa
commit
b43b56a6a8
|
@ -390,16 +390,6 @@ power of the second argument.
|
|||
or underflow.
|
||||
|=======================================================================
|
||||
|
||||
[float]
|
||||
=== Floating point numbers in Groovy
|
||||
|
||||
When using floating-point literals in Groovy scripts, Groovy will automatically
|
||||
use BigDecimal instead of a floating point equivalent to support the
|
||||
'least-surprising' approach to literal math operations. To use a floating-point
|
||||
number instead, use the specific suffix on the number (ie, instead of 1.2, use
|
||||
1.2f). See the http://groovy.codehaus.org/Groovy+Math[Groovy Math] page for more
|
||||
information.
|
||||
|
||||
[float]
|
||||
=== Arithmetic precision in MVEL
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ public class GroovySandboxExpressionChecker implements SecureASTCustomizer.Expre
|
|||
java.util.HashMap.class.getName(),
|
||||
java.util.HashSet.class.getName(),
|
||||
java.util.UUID.class.getName(),
|
||||
java.math.BigDecimal.class.getName(),
|
||||
org.joda.time.DateTime.class.getName(),
|
||||
org.joda.time.DateTimeZone.class.getName()
|
||||
};
|
||||
|
|
|
@ -24,7 +24,16 @@ import groovy.lang.GroovyClassLoader;
|
|||
import groovy.lang.Script;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.Scorer;
|
||||
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.ast.expr.Expression;
|
||||
import org.codehaus.groovy.classgen.GeneratorContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
|
@ -37,6 +46,7 @@ import org.elasticsearch.script.SearchScript;
|
|||
import org.elasticsearch.search.lookup.SearchLookup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
@ -64,6 +74,8 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
|||
if (this.sandboxed) {
|
||||
config.addCompilationCustomizers(GroovySandboxExpressionChecker.getSecureASTCustomizer(settings));
|
||||
}
|
||||
// Add BigDecimal -> Double transformer
|
||||
config.addCompilationCustomizers(new GroovyBigDecimalTransformer(CompilePhase.CONVERSION));
|
||||
this.loader = new GroovyClassLoader(settings.getClassLoader(), config);
|
||||
}
|
||||
|
||||
|
@ -282,6 +294,51 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
|||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A compilation customizer that is used to transform a number like 1.23,
|
||||
* which would normally be a BigDecimal, into a double value.
|
||||
*/
|
||||
private class GroovyBigDecimalTransformer extends CompilationCustomizer {
|
||||
|
||||
private GroovyBigDecimalTransformer(CompilePhase phase) {
|
||||
super(phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
|
||||
new BigDecimalExpressionTransformer(source).visitClass(classNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Groovy expression transformer that converts BigDecimals to doubles
|
||||
*/
|
||||
private class BigDecimalExpressionTransformer extends ClassCodeExpressionTransformer {
|
||||
|
||||
private final SourceUnit source;
|
||||
|
||||
private BigDecimalExpressionTransformer(SourceUnit source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SourceUnit getSourceUnit() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression transform(Expression expr) {
|
||||
Expression newExpr = expr;
|
||||
if (expr instanceof ConstantExpression) {
|
||||
ConstantExpression constExpr = (ConstantExpression) expr;
|
||||
Object val = constExpr.getValue();
|
||||
if (val != null && val instanceof BigDecimal) {
|
||||
newExpr = new ConstantExpression(((BigDecimal) val).doubleValue());
|
||||
}
|
||||
}
|
||||
return super.transform(newExpr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.script;
|
||||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
|
||||
/**
|
||||
* Various tests for Groovy scripting
|
||||
*/
|
||||
public class GroovyScriptTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testGroovyBigDecimalTransformation() {
|
||||
client().prepareIndex("test", "doc", "1").setSource("foo", 5).setRefresh(true).get();
|
||||
|
||||
// Test that something that would usually be a BigDecimal is transformed into a Double
|
||||
assertScript("def n = 1.23; assert n instanceof Double;");
|
||||
assertScript("def n = 1.23G; assert n instanceof Double;");
|
||||
assertScript("def n = BigDecimal.ONE; assert n instanceof BigDecimal;");
|
||||
}
|
||||
|
||||
public void assertScript(String script) {
|
||||
SearchResponse resp = client().prepareSearch("test")
|
||||
.setSource("{\"query\": {\"match_all\": {}}," +
|
||||
"\"sort\":{\"_script\": {\"script\": \""+ script +
|
||||
"; 1\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get();
|
||||
assertNoFailures(resp);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue