Improve wrapping of lists.
With the current way that Java lists are wrapped into a Scriptable, all methods that are not defined on the java.util.List interface are hidden. This pull request makes NativeList extend NativeJavaObject in order to use reflection in order to look up properties that would not be defined on the List interface. Close #32
This commit is contained in:
parent
4549a3b4ee
commit
7417814154
|
@ -292,10 +292,10 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements
|
|||
|
||||
public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class staticType) {
|
||||
if (javaObject instanceof Map) {
|
||||
return new NativeMap(scope, (Map) javaObject);
|
||||
return NativeMap.wrap(scope, (Map) javaObject);
|
||||
}
|
||||
if (javaObject instanceof List) {
|
||||
return new NativeList(scope, (List) javaObject);
|
||||
return NativeList.wrap(scope, (List) javaObject, staticType);
|
||||
}
|
||||
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
|
||||
}
|
||||
|
|
|
@ -19,29 +19,30 @@
|
|||
|
||||
package org.elasticsearch.script.javascript.support;
|
||||
|
||||
import org.mozilla.javascript.NativeJavaObject;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.Undefined;
|
||||
import org.mozilla.javascript.Wrapper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class NativeList implements Scriptable, Wrapper {
|
||||
public class NativeList extends NativeJavaObject implements Scriptable, Wrapper {
|
||||
private static final long serialVersionUID = 3664761893203964569L;
|
||||
private static final String LENGTH_PROPERTY = "length";
|
||||
|
||||
private List<Object> list;
|
||||
private Scriptable parentScope;
|
||||
private Scriptable prototype;
|
||||
private final List<Object> list;
|
||||
|
||||
|
||||
public static NativeList wrap(Scriptable scope, List<Object> list) {
|
||||
return new NativeList(scope, list);
|
||||
public static NativeList wrap(Scriptable scope, List<Object> list, Class<?> staticType) {
|
||||
return new NativeList(scope, list, staticType);
|
||||
}
|
||||
|
||||
public NativeList(Scriptable scope, List<Object> list) {
|
||||
this.parentScope = scope;
|
||||
private NativeList(Scriptable scope, List<Object> list, Class<?> staticType) {
|
||||
super(scope, list, staticType);
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
|
@ -66,10 +67,10 @@ public class NativeList implements Scriptable, Wrapper {
|
|||
*/
|
||||
|
||||
public Object get(String name, Scriptable start) {
|
||||
if ("length".equals(name)) {
|
||||
if (LENGTH_PROPERTY.equals(name)) {
|
||||
return list.size();
|
||||
} else {
|
||||
return Undefined.instance;
|
||||
return super.get(name, start);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ public class NativeList implements Scriptable, Wrapper {
|
|||
*/
|
||||
|
||||
public Object get(int index, Scriptable start) {
|
||||
if (index < 0 || index >= list.size()) {
|
||||
if (has(index, start) == false) {
|
||||
return Undefined.instance;
|
||||
}
|
||||
return list.get(index);
|
||||
|
@ -89,10 +90,7 @@ public class NativeList implements Scriptable, Wrapper {
|
|||
*/
|
||||
|
||||
public boolean has(String name, Scriptable start) {
|
||||
if ("length".equals(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return super.has(name, start) || LENGTH_PROPERTY.equals(name);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -103,15 +101,6 @@ public class NativeList implements Scriptable, Wrapper {
|
|||
return index >= 0 && index < list.size();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object)
|
||||
*/
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(String name, Scriptable start, Object value) {
|
||||
// do nothing here...
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#put(int, org.mozilla.javascript.Scriptable, java.lang.Object)
|
||||
*/
|
||||
|
@ -124,14 +113,6 @@ public class NativeList implements Scriptable, Wrapper {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#delete(java.lang.String)
|
||||
*/
|
||||
|
||||
public void delete(String name) {
|
||||
// nothing here
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#delete(int)
|
||||
*/
|
||||
|
@ -140,59 +121,20 @@ public class NativeList implements Scriptable, Wrapper {
|
|||
list.remove(index);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#getPrototype()
|
||||
*/
|
||||
|
||||
public Scriptable getPrototype() {
|
||||
return this.prototype;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#setPrototype(org.mozilla.javascript.Scriptable)
|
||||
*/
|
||||
|
||||
public void setPrototype(Scriptable prototype) {
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#getParentScope()
|
||||
*/
|
||||
|
||||
public Scriptable getParentScope() {
|
||||
return this.parentScope;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#setParentScope(org.mozilla.javascript.Scriptable)
|
||||
*/
|
||||
|
||||
public void setParentScope(Scriptable parent) {
|
||||
this.parentScope = parent;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#getIds()
|
||||
*/
|
||||
|
||||
public Object[] getIds() {
|
||||
int size = list.size();
|
||||
Object[] ids = new Object[size];
|
||||
final Object[] javaObjectIds = super.getIds();
|
||||
final int size = list.size();
|
||||
final Object[] ids = Arrays.copyOf(javaObjectIds, javaObjectIds.length + size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ids[i] = i;
|
||||
ids[javaObjectIds.length + i] = i;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#getDefaultValue(java.lang.Class)
|
||||
*/
|
||||
|
||||
public Object getDefaultValue(Class hint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mozilla.javascript.Scriptable#hasInstance(org.mozilla.javascript.Scriptable)
|
||||
*/
|
||||
|
|
|
@ -55,7 +55,7 @@ public class NativeMap implements Scriptable, Wrapper {
|
|||
* @param scope
|
||||
* @param map
|
||||
*/
|
||||
public NativeMap(Scriptable scope, Map<Object, Object> map) {
|
||||
private NativeMap(Scriptable scope, Map<Object, Object> map) {
|
||||
this.parentScope = scope;
|
||||
this.map = map;
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ public final class ScriptValueConverter {
|
|||
// convert array to a native JavaScript Array
|
||||
value = Context.getCurrentContext().newArray(scope, array);
|
||||
} else if (value instanceof Map) {
|
||||
value = new NativeMap(scope, (Map) value);
|
||||
value = NativeMap.wrap(scope, (Map) value);
|
||||
}
|
||||
|
||||
// simple numbers, strings and booleans are wrapped automatically by Rhino
|
||||
|
|
|
@ -43,6 +43,7 @@ import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.
|
|||
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
|
@ -285,4 +286,16 @@ public class JavaScriptScriptSearchTests extends ElasticsearchIntegrationTest {
|
|||
assertThat(((Terms) response.getAggregations().asMap().get("score_agg")).getBuckets().get(0).getKeyAsNumber().floatValue(), is(1f));
|
||||
assertThat(((Terms) response.getAggregations().asMap().get("score_agg")).getBuckets().get(0).getDocCount(), is(1l));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseListLengthInScripts() throws Exception {
|
||||
createIndex("index");
|
||||
index("index", "testtype", "1", jsonBuilder().startObject().field("f", 42).endObject());
|
||||
ensureSearchable("index");
|
||||
refresh();
|
||||
SearchResponse response = client().prepareSearch().addScriptField("foobar", "js", "doc['f'].values.length", null).get();
|
||||
assertSearchResponse(response);
|
||||
assertHitCount(response, 1);
|
||||
assertThat((Integer) response.getHits().getAt(0).getFields().get("foobar").value(), equalTo(1));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue