Skip to content

Commit

Permalink
JEXL: improve example on filter/map;
Browse files Browse the repository at this point in the history
  • Loading branch information
Henri Biestro committed Nov 8, 2023
1 parent 31c0e31 commit 0c8b1ea
Showing 1 changed file with 103 additions and 5 deletions.
108 changes: 103 additions & 5 deletions src/test/java/org/apache/commons/jexl3/examples/StreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -40,7 +43,7 @@
*/
public class StreamTest {
/**
* A MapContext that can operate on streams.
* A MapContext that can operate on streams and collections.
*/
public static class StreamContext extends MapContext {
/**
Expand All @@ -62,6 +65,31 @@ public Stream<?> filter(final Stream<?> stream, final JexlScript filter) {
public Stream<?> map(final Stream<?> stream, final JexlScript mapper) {
return stream.map( x -> mapper.execute(this, x));
}

/**
* This allows using a JEXL lambda as a filter.
* @param collection the collection
* @param filter the lambda to use as filter
* @return the filtered result as a list
*/
public List<?> filter(Collection<?> collection, final JexlScript filter) {
return collection.stream()
.filter(x -> x != null && TRUE.equals(filter.execute(this, x)))
.collect(Collectors.toList());
}

/**
* This allows using a JEXL lambda as a mapper.
* @param collection the collection
* @param mapper the lambda to use as mapper
* @return the mapped result as a list
*/
public List<?> map(Collection<?> collection, final JexlScript mapper) {
return collection.stream()
.map(x -> mapper.execute(this, x))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

/** Our engine instance. */
Expand All @@ -76,13 +104,17 @@ public StreamTest() {
// Restricted permissions to a safe set but with URI allowed
final JexlPermissions permissions = new ClassPermissions(java.net.URI.class);
// Create the engine
jexl = new JexlBuilder().features(features).permissions(permissions).create();
jexl = new JexlBuilder()
.features(features)
.permissions(permissions)
.namespaces(Collections.singletonMap("URI", java.net.URI.class))
.create();
}

@Test
public void testURIStream() throws Exception {
public void testURIStream() {
// let's assume a collection of uris need to be processed and transformed to be simplified ;
// we want only http/https ones, only the host part and using an https scheme
// we want only http/https ones, only the host part and using a https scheme
final List<URI> uris = Arrays.asList(
URI.create("http://[email protected]:8000?qry=true"),
URI.create("https://commons.apache.org/releases/prepare.html"),
Expand All @@ -91,7 +123,7 @@ public void testURIStream() throws Exception {
// Create the test control, the expected result of our script evaluation
final List<?> control = uris.stream()
.map(uri -> uri.getScheme().startsWith("http")? "https://" + uri.getHost() : null)
.filter(x -> x != null)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Assert.assertEquals(2, control.size());

Expand All @@ -114,4 +146,70 @@ public void testURIStream() throws Exception {
Assert.assertTrue(transformed instanceof List<?>);
Assert.assertEquals(control, transformed);
}

/**
* A MapContext that can operate on streams and collections.
*/
public static class CollectionContext extends MapContext {
/**
* This allows using a JEXL lambda as a filter.
* @param collection the collection
* @param filter the lambda to use as filter
* @return the filtered result as a list
*/
public List<?> filter(Collection<?> collection, final JexlScript filter) {
return collection.stream()
.filter(x -> x != null && TRUE.equals(filter.execute(this, x)))
.collect(Collectors.toList());
}

/**
* This allows using a JEXL lambda as a mapper.
* @param collection the collection
* @param mapper the lambda to use as mapper
* @return the mapped result as a list
*/
public List<?> map(Collection<?> collection, final JexlScript mapper) {
return collection.stream()
.map(x -> mapper.execute(this, x))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

@Test
public void testURICollection() {
// A collection map/filter aware context
final JexlContext sctxt = new CollectionContext();
// Some uris
final List<URI> uris = Arrays.asList(
URI.create("http://[email protected]:8000?qry=true"),
URI.create("https://commons.apache.org/releases/prepare.html"),
URI.create("mailto:[email protected]")
);

// filter, all results schemes start with 'http'
final JexlScript filter = jexl.createScript(
"list.filter(uri -> uri.scheme =^ 'http')",
"list");
final Object filtered = filter.execute(sctxt, uris);
Assert.assertTrue(filtered instanceof List<?>);
List<URI> result = (List<URI>) filtered;
Assert.assertEquals(2, result.size());
for(URI uri : result) {
Assert.assertTrue(uri.getScheme().startsWith("http"));
}

// map, all results scheme now 'https'
final JexlScript mapper = jexl.createScript(
"list.map(uri -> uri.scheme =^ 'http'? URI:create(`https://${uri.host}`) : null)",
"list");
final Object transformed = mapper.execute(sctxt, uris);
Assert.assertTrue(transformed instanceof List<?>);
result = (List<URI>) transformed;
Assert.assertEquals(2, result.size());
for(URI uri : result) {
Assert.assertEquals("https", uri.getScheme());
}
}
}

0 comments on commit 0c8b1ea

Please sign in to comment.