Skip to content

Commit 7417814

Browse files
committed
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
1 parent 4549a3b commit 7417814

File tree

5 files changed

+34
-79
lines changed

5 files changed

+34
-79
lines changed

src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,10 @@ public CustomWrapFactory() {
292292

293293
public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class staticType) {
294294
if (javaObject instanceof Map) {
295-
return new NativeMap(scope, (Map) javaObject);
295+
return NativeMap.wrap(scope, (Map) javaObject);
296296
}
297297
if (javaObject instanceof List) {
298-
return new NativeList(scope, (List) javaObject);
298+
return NativeList.wrap(scope, (List) javaObject, staticType);
299299
}
300300
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
301301
}

src/main/java/org/elasticsearch/script/javascript/support/NativeList.java

+17-75
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,30 @@
1919

2020
package org.elasticsearch.script.javascript.support;
2121

22+
import org.mozilla.javascript.NativeJavaObject;
2223
import org.mozilla.javascript.Scriptable;
2324
import org.mozilla.javascript.Undefined;
2425
import org.mozilla.javascript.Wrapper;
2526

27+
import java.util.Arrays;
2628
import java.util.List;
2729

2830
/**
2931
*
3032
*/
31-
public class NativeList implements Scriptable, Wrapper {
33+
public class NativeList extends NativeJavaObject implements Scriptable, Wrapper {
3234
private static final long serialVersionUID = 3664761893203964569L;
35+
private static final String LENGTH_PROPERTY = "length";
3336

34-
private List<Object> list;
35-
private Scriptable parentScope;
36-
private Scriptable prototype;
37+
private final List<Object> list;
3738

3839

39-
public static NativeList wrap(Scriptable scope, List<Object> list) {
40-
return new NativeList(scope, list);
40+
public static NativeList wrap(Scriptable scope, List<Object> list, Class<?> staticType) {
41+
return new NativeList(scope, list, staticType);
4142
}
4243

43-
public NativeList(Scriptable scope, List<Object> list) {
44-
this.parentScope = scope;
44+
private NativeList(Scriptable scope, List<Object> list, Class<?> staticType) {
45+
super(scope, list, staticType);
4546
this.list = list;
4647
}
4748

@@ -66,10 +67,10 @@ public String getClassName() {
6667
*/
6768

6869
public Object get(String name, Scriptable start) {
69-
if ("length".equals(name)) {
70+
if (LENGTH_PROPERTY.equals(name)) {
7071
return list.size();
7172
} else {
72-
return Undefined.instance;
73+
return super.get(name, start);
7374
}
7475
}
7576

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

8081
public Object get(int index, Scriptable start) {
81-
if (index < 0 || index >= list.size()) {
82+
if (has(index, start) == false) {
8283
return Undefined.instance;
8384
}
8485
return list.get(index);
@@ -89,10 +90,7 @@ public Object get(int index, Scriptable start) {
8990
*/
9091

9192
public boolean has(String name, Scriptable start) {
92-
if ("length".equals(name)) {
93-
return true;
94-
}
95-
return false;
93+
return super.has(name, start) || LENGTH_PROPERTY.equals(name);
9694
}
9795

9896
/* (non-Javadoc)
@@ -103,15 +101,6 @@ public boolean has(int index, Scriptable start) {
103101
return index >= 0 && index < list.size();
104102
}
105103

106-
/* (non-Javadoc)
107-
* @see org.mozilla.javascript.Scriptable#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object)
108-
*/
109-
110-
@SuppressWarnings("unchecked")
111-
public void put(String name, Scriptable start, Object value) {
112-
// do nothing here...
113-
}
114-
115104
/* (non-Javadoc)
116105
* @see org.mozilla.javascript.Scriptable#put(int, org.mozilla.javascript.Scriptable, java.lang.Object)
117106
*/
@@ -124,14 +113,6 @@ public void put(int index, Scriptable start, Object value) {
124113
}
125114
}
126115

127-
/* (non-Javadoc)
128-
* @see org.mozilla.javascript.Scriptable#delete(java.lang.String)
129-
*/
130-
131-
public void delete(String name) {
132-
// nothing here
133-
}
134-
135116
/* (non-Javadoc)
136117
* @see org.mozilla.javascript.Scriptable#delete(int)
137118
*/
@@ -140,59 +121,20 @@ public void delete(int index) {
140121
list.remove(index);
141122
}
142123

143-
/* (non-Javadoc)
144-
* @see org.mozilla.javascript.Scriptable#getPrototype()
145-
*/
146-
147-
public Scriptable getPrototype() {
148-
return this.prototype;
149-
}
150-
151-
/* (non-Javadoc)
152-
* @see org.mozilla.javascript.Scriptable#setPrototype(org.mozilla.javascript.Scriptable)
153-
*/
154-
155-
public void setPrototype(Scriptable prototype) {
156-
this.prototype = prototype;
157-
}
158-
159-
/* (non-Javadoc)
160-
* @see org.mozilla.javascript.Scriptable#getParentScope()
161-
*/
162-
163-
public Scriptable getParentScope() {
164-
return this.parentScope;
165-
}
166-
167-
/* (non-Javadoc)
168-
* @see org.mozilla.javascript.Scriptable#setParentScope(org.mozilla.javascript.Scriptable)
169-
*/
170-
171-
public void setParentScope(Scriptable parent) {
172-
this.parentScope = parent;
173-
}
174-
175124
/* (non-Javadoc)
176125
* @see org.mozilla.javascript.Scriptable#getIds()
177126
*/
178127

179128
public Object[] getIds() {
180-
int size = list.size();
181-
Object[] ids = new Object[size];
129+
final Object[] javaObjectIds = super.getIds();
130+
final int size = list.size();
131+
final Object[] ids = Arrays.copyOf(javaObjectIds, javaObjectIds.length + size);
182132
for (int i = 0; i < size; ++i) {
183-
ids[i] = i;
133+
ids[javaObjectIds.length + i] = i;
184134
}
185135
return ids;
186136
}
187137

188-
/* (non-Javadoc)
189-
* @see org.mozilla.javascript.Scriptable#getDefaultValue(java.lang.Class)
190-
*/
191-
192-
public Object getDefaultValue(Class hint) {
193-
return null;
194-
}
195-
196138
/* (non-Javadoc)
197139
* @see org.mozilla.javascript.Scriptable#hasInstance(org.mozilla.javascript.Scriptable)
198140
*/

src/main/java/org/elasticsearch/script/javascript/support/NativeMap.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public static NativeMap wrap(Scriptable scope, Map<Object, Object> map) {
5555
* @param scope
5656
* @param map
5757
*/
58-
public NativeMap(Scriptable scope, Map<Object, Object> map) {
58+
private NativeMap(Scriptable scope, Map<Object, Object> map) {
5959
this.parentScope = scope;
6060
this.map = map;
6161
}

src/main/java/org/elasticsearch/script/javascript/support/ScriptValueConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public static Object wrapValue(Scriptable scope, Object value) {
156156
// convert array to a native JavaScript Array
157157
value = Context.getCurrentContext().newArray(scope, array);
158158
} else if (value instanceof Map) {
159-
value = new NativeMap(scope, (Map) value);
159+
value = NativeMap.wrap(scope, (Map) value);
160160
}
161161

162162
// simple numbers, strings and booleans are wrapped automatically by Rhino

src/test/java/org/elasticsearch/script/javascript/JavaScriptScriptSearchTests.java

+13
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
4444
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
4545
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
46+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
4647
import static org.hamcrest.Matchers.equalTo;
4748
import static org.hamcrest.Matchers.is;
4849

@@ -285,4 +286,16 @@ public void testScriptScoresWithAgg() throws IOException {
285286
assertThat(((Terms) response.getAggregations().asMap().get("score_agg")).getBuckets().get(0).getKeyAsNumber().floatValue(), is(1f));
286287
assertThat(((Terms) response.getAggregations().asMap().get("score_agg")).getBuckets().get(0).getDocCount(), is(1l));
287288
}
289+
290+
@Test
291+
public void testUseListLengthInScripts() throws Exception {
292+
createIndex("index");
293+
index("index", "testtype", "1", jsonBuilder().startObject().field("f", 42).endObject());
294+
ensureSearchable("index");
295+
refresh();
296+
SearchResponse response = client().prepareSearch().addScriptField("foobar", "js", "doc['f'].values.length", null).get();
297+
assertSearchResponse(response);
298+
assertHitCount(response, 1);
299+
assertThat((Integer) response.getHits().getAt(0).getFields().get("foobar").value(), equalTo(1));
300+
}
288301
}

0 commit comments

Comments
 (0)