Skip to content

Commit

Permalink
Improve wrapping of lists.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jpountz committed Nov 27, 2014
1 parent 4549a3b commit 7417814
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,10 @@ public CustomWrapFactory() {

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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -66,10 +67,10 @@ public String getClassName() {
*/

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);
}
}

Expand All @@ -78,7 +79,7 @@ public Object get(String name, Scriptable start) {
*/

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);
Expand All @@ -89,10 +90,7 @@ public Object get(int index, Scriptable start) {
*/

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)
Expand All @@ -103,15 +101,6 @@ public boolean has(int index, Scriptable start) {
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)
*/
Expand All @@ -124,14 +113,6 @@ public void put(int index, Scriptable start, Object value) {
}
}

/* (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)
*/
Expand All @@ -140,59 +121,20 @@ public void delete(int index) {
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)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static NativeMap wrap(Scriptable scope, Map<Object, Object> map) {
* @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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public static Object wrapValue(Scriptable scope, Object value) {
// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
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;

Expand Down Expand Up @@ -285,4 +286,16 @@ public void testScriptScoresWithAgg() throws IOException {
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));
}
}

0 comments on commit 7417814

Please sign in to comment.