Skip to content

Commit

Permalink
avoid the conversion to a map and go native
Browse files Browse the repository at this point in the history
  • Loading branch information
mbuckton committed Nov 16, 2023
1 parent 31dcd39 commit c81578b
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 3 deletions.
107 changes: 104 additions & 3 deletions src/main/java/io/mapsmessaging/selector/resolvers/JsonEvaluator.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,111 @@
package io.mapsmessaging.selector.resolvers;

import io.mapsmessaging.selector.IdentifierMutator;
import org.json.JSONArray;
import org.json.JSONObject;

public class JsonEvaluator extends MapEvaluator {
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public JsonEvaluator(JSONObject bean){
super(bean.toMap());
public class JsonEvaluator implements IdentifierMutator {

private final JSONObject jsonObject;

public JsonEvaluator(JSONObject jsonObject){
this.jsonObject = jsonObject;
}


@Override
public Object get(String key) {
String[] keyPath = getKeyPath(key);
Object lookup = locateObject(jsonObject, keyPath);
return parseJSON(lookup);
}

@Override
public Object remove(String key) {
return get(key);
}

@Override
public Object set(String key, Object value) {
return false;
}

private String[] getKeyPath(String key){
String[] keyPath;
if(key.contains(".")){
var stringTokenizer = new StringTokenizer(key, ".");
List<String> tmp = new ArrayList<>();
while(stringTokenizer.hasMoreElements()){
tmp.add(stringTokenizer.nextElement().toString());
}
var tmpPath = new String[tmp.size()];
keyPath = tmp.toArray(tmpPath);
}
else{
keyPath = new String[1];
keyPath[0] = key;
}
return keyPath;
}

private static Object locateObject(JSONObject json, String[] searchPath){
if(searchPath != null){
// Walk the JSON path first
for(var x=0;x<searchPath.length;x++){
var path = searchPath[x];
var jsonLookup = json.get(path);
if(jsonLookup instanceof JSONArray){
var sub = new String[searchPath.length-(x +1)];
System.arraycopy(searchPath, x+1, sub, 0, sub.length);
return arrayLookup(json.getJSONArray(path), sub);
}
else if(jsonLookup instanceof JSONObject){
json = (JSONObject) jsonLookup;
}
else{
return jsonLookup;
}
}
}
return null;
}

private static Object arrayLookup(JSONArray array, String[] path){
// We have an array, so the next element in the path must be an index ( ie number)
var idx = Integer.parseInt(path[0]);
Object lookup = array.get(idx);
if(lookup instanceof JSONObject){
var sub = new String[path.length-1];
System.arraycopy(path, 1, sub, 0, sub.length);
return locateObject( (JSONObject) lookup, sub);
}
else if(lookup instanceof JSONArray){
var sub = new String[path.length-1];
System.arraycopy(path, 1, sub, 0, sub.length);
return arrayLookup( (JSONArray) lookup, sub);
}
return lookup;
}

private static Object parseJSON(Object lookup){
if (lookup instanceof String ||
lookup instanceof Float ||
lookup instanceof Double ||
lookup instanceof Byte ||
lookup instanceof Short ||
lookup instanceof Integer ||
lookup instanceof Long) {
return lookup;
}
else if(lookup instanceof BigDecimal){
return ((BigDecimal)lookup).doubleValue();
}
return null;
}

}
32 changes: 32 additions & 0 deletions src/test/java/io/mapsmessaging/selector/JsonFilteringTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,39 @@ void simpleJsonFiltering() throws ParseException {
}
}
Assertions.assertEquals(alaskaCount, filtered);
}


@Test
void nestedJsonFiltering() throws ParseException {
Faker faker = new Faker();
JSONArray addressList = buildList();
JSONArray people = new JSONArray();
for(int x=0;x<addressList.length();x++){
JSONObject address = addressList.getJSONObject(x);
JSONObject person = new JSONObject();
person.put("address", address);
person.put("first", faker.name().firstName());
person.put("last", faker.name().lastName());
person.put("phone", faker.phoneNumber().phoneNumber());
person.put("email", faker.internet().emailAddress());
people.put(person);
}


int alaskaCount = 0;
int filtered = 0;
ParserExecutor executor = SelectorParser.compile("address.state = 'Alaska'");
for(int x=0;x<people.length();x++){
JSONObject person = people.getJSONObject(x);
if(person.getJSONObject("address").get("state").equals("Alaska")){
alaskaCount++;
}
if(executor.evaluate(person)){
filtered++;
}
}
Assertions.assertEquals(alaskaCount, filtered);
}


Expand Down

0 comments on commit c81578b

Please sign in to comment.