This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git

commit 4f4be9fff8f78d6a1960b263e7d0299ff832e485
Author: Gary D. Gregory <[email protected]>
AuthorDate: Sat Nov 1 08:46:37 2025 -0400

    Add Javadoc overview
---
 .../org/apache/commons/jexl3/doc-files/logo.png    | Bin 0 -> 9495 bytes
 src/main/javadoc/overview.html                     | 344 +++++++++++++++++++++
 2 files changed, 344 insertions(+)

diff --git a/src/main/java/org/apache/commons/jexl3/doc-files/logo.png 
b/src/main/java/org/apache/commons/jexl3/doc-files/logo.png
new file mode 100644
index 00000000..3f3ee8dc
Binary files /dev/null and 
b/src/main/java/org/apache/commons/jexl3/doc-files/logo.png differ
diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html
new file mode 100644
index 00000000..db5af069
--- /dev/null
+++ b/src/main/javadoc/overview.html
@@ -0,0 +1,344 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+     https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+</head>
+<body>
+  <img alt="Apache Commons IO" 
src="org/apache/commons/jexl3/doc-files/logo.png">
+  <h1>Apache Commons JEXL</h1>
+  <h2>Introduction</h2>
+  <p>JEXL is a library intended to facilitate the implementation of dynamic 
and scripting features in applications and frameworks written in Java.</p>
+  <p>JEXL implements an Expression Language based on some extensions to the 
JSTL Expression Language supporting most of the constructs seen in shell-script
+    or ECMAScript.</p>
+  <p>Its goal is to expose scripting features usable by technical operatives 
or consultants working with enterprise platforms. In many use cases, JEXL
+    allows end-users of an application to code their own scripts or 
expressions and ensure their execution within controlled functional 
constraints.</p>
+  <p>
+    The library exposes a small footprint API - the <a 
href="apidocs/org/apache/commons/jexl3/package-summary.html#usage">core 
features</a> fit in 3 classes and
+    10 methods - that can be used in various conditions:
+  </p>
+  <ul>
+    <li>Scripting features:
+      <ul>
+        <li>Your application lets (advanced) users evaluate or define some 
simple expressions like computation formulas.</li>
+      </ul>
+    </li>
+    <li>Module or component configuration:
+      <ul>
+        <li>Your application has configuration files (eventually generated by 
a design module) consumed by the end-user module that would benefit from
+          variables and expressions.</li>
+        <li>When it would be convenient to use IOC but overall complexity 
doesn't require (or can't depend upon) a full-blown library (Spring, 
Guice...).</li>
+      </ul>
+    </li>
+    <li>Loose-coupling of interfaces and implementations or duck-typing:
+      <ul>
+        <li>You have optional classes that your code cant consider as 
compilation dependencies.</li>
+        <li>You have to integrate and call "legacy" code or use components 
that you don't want to strongly depend upon.</li>
+      </ul>
+    </li>
+    <li>Simple template capabilities:
+      <ul>
+        <li>Your application has basic template requirements and JSPs or 
Velocity would be overkill or too inconvenient to deploy.</li>
+      </ul>
+    </li>
+  </ul>
+  <p>
+    JEXL name stands for Java EXpression Language, a simple expression 
language originally inspired by Apache Velocity and the Expression Language 
defined in
+    the JavaServer Pages Standard Tag Library version 1.1 (JSTL) and 
JavaServer Pages version 2.0 (JSP). JEXL 2.0 added features inspired by <a
+      href="https://en.wikipedia.org/wiki/Unified_Expression_Language";>Unified 
EL</a>. The syntax is now close to a mix of ECMAScript and "shell-script" making
+    it easy to master by technical operatives or consultants. The objects 
exposed and their behavior obviously need to be documented though...
+  </p>
+  <p>The API and the expression language exploit Java-beans naming patterns 
through introspection to expose property getters and setters. It also considers
+    public class fields as properties and allows to invoke any accessible 
method.</p>
+  <h2>A Detailed Example</h2>
+
+  <div class="container">
+    <div class="header">
+      <h1>StreamTest.java</h1>
+      <p class="meta">Package: org.apache.commons.jexl3.examples | Apache 
Commons JEXL3</p>
+    </div>
+    <div class="code-container">
+    <!-- TODO Using a style in the head doesn't override the Javadoc style. -->
+      <pre>
+        <code>
+          <span class="keyword">package</span> 
org.apache.commons.jexl3.examples;
+
+<span class="keyword">import static</span> java.lang.Boolean.TRUE;
+<span class="keyword">import static</span> 
org.junit.jupiter.api.Assertions.assertEquals;
+<span class="keyword">import static</span> 
org.junit.jupiter.api.Assertions.assertInstanceOf;
+<span class="keyword">import static</span> 
org.junit.jupiter.api.Assertions.assertTrue;
+
+<span class="keyword">import</span> java.net.URI;
+<span class="keyword">import</span> java.util.Arrays;
+<span class="keyword">import</span> java.util.Collection;
+<span class="keyword">import</span> java.util.Collections;
+<span class="keyword">import</span> java.util.List;
+<span class="keyword">import</span> java.util.Objects;
+<span class="keyword">import</span> java.util.stream.Collectors;
+<span class="keyword">import</span> java.util.stream.Stream;
+
+<span class="keyword">import</span> org.apache.commons.jexl3.JexlBuilder;
+<span class="keyword">import</span> org.apache.commons.jexl3.JexlContext;
+<span class="keyword">import</span> org.apache.commons.jexl3.JexlEngine;
+<span class="keyword">import</span> org.apache.commons.jexl3.JexlFeatures;
+<span class="keyword">import</span> org.apache.commons.jexl3.JexlScript;
+<span class="keyword">import</span> org.apache.commons.jexl3.MapContext;
+<span class="keyword">import</span> 
org.apache.commons.jexl3.introspection.JexlPermissions;
+<span class="keyword">import</span> 
org.apache.commons.jexl3.introspection.JexlPermissions.ClassPermissions;
+<span class="keyword">import</span> org.junit.jupiter.api.Test;
+
+<span class="comment">/**</span>
+<span class="comment"> * A test around scripting streams.</span>
+<span class="comment"> */</span>
+<span class="keyword">class</span> <span class="type">StreamTest</span> {
+
+    <span class="comment">/**</span>
+<span class="comment">     * A MapContext that can operate on streams and 
collections.</span>
+<span class="comment">     */</span>
+    <span class="keyword">public static class</span> <span 
class="type">CollectionContext</span> <span class="keyword">extends</span> 
<span class="type">MapContext</span> {
+
+        <span class="comment">/**</span>
+<span class="comment">         * This allows using a JEXL lambda as a 
filter.</span>
+<span class="comment">         *</span>
+<span class="comment">         * @param collection the collection</span>
+<span class="comment">         * @param filter the lambda to use as 
filter</span>
+<span class="comment">         * @return the filtered result as a list</span>
+<span class="comment">         */</span>
+        <span class="keyword">public</span> <span 
class="type">List</span>&lt;?&gt; <span class="method">filter</span>(<span 
class="keyword">final</span> <span
+            class="type">Collection</span>&lt;?&gt; collection, <span 
class="keyword">final</span> <span class="type">JexlScript</span> filter) {
+            <span class="keyword">return</span> collection.<span 
class="method">stream</span>()
+                .<span class="method">filter</span>(x -&gt; x != <span 
class="keyword">null</span> &amp;&amp; TRUE.<span 
class="method">equals</span>(filter.<span
+            class="method">execute</span>(<span class="keyword">this</span>, 
x)))
+                .<span class="method">collect</span>(Collectors.<span 
class="method">toList</span>());
+        }
+
+        <span class="comment">/**</span>
+<span class="comment">         * This allows using a JEXL lambda as a 
mapper.</span>
+<span class="comment">         *</span>
+<span class="comment">         * @param collection the collection</span>
+<span class="comment">         * @param mapper the lambda to use as 
mapper</span>
+<span class="comment">         * @return the mapped result as a list</span>
+<span class="comment">         */</span>
+        <span class="keyword">public</span> <span 
class="type">List</span>&lt;?&gt; <span class="method">map</span>(<span 
class="keyword">final</span> <span
+            class="type">Collection</span>&lt;?&gt; collection, <span 
class="keyword">final</span> <span class="type">JexlScript</span> mapper) {
+            <span class="keyword">return</span> collection.<span 
class="method">stream</span>()
+                .<span class="method">map</span>(x -&gt; mapper.<span 
class="method">execute</span>(<span class="keyword">this</span>, x))
+                .<span class="method">filter</span>(Objects::nonNull)
+                .<span class="method">collect</span>(Collectors.<span 
class="method">toList</span>());
+        }
+    }
+
+    <span class="comment">/**</span>
+<span class="comment">     * A MapContext that can operate on streams and 
collections.</span>
+<span class="comment">     */</span>
+    <span class="keyword">public static class</span> <span 
class="type">StreamContext</span> <span class="keyword">extends</span> <span 
class="type">MapContext</span> {
+
+        <span class="comment">/**</span>
+<span class="comment">         * This allows using a JEXL lambda as a 
filter.</span>
+<span class="comment">         *</span>
+<span class="comment">         * @param stream the stream</span>
+<span class="comment">         * @param filter the lambda to use as 
filter</span>
+<span class="comment">         * @return the filtered stream</span>
+<span class="comment">         */</span>
+        <span class="keyword">public</span> <span 
class="type">Stream</span>&lt;?&gt; <span class="method">filter</span>(<span 
class="keyword">final</span> <span
+            class="type">Stream</span>&lt;?&gt; stream, <span 
class="keyword">final</span> <span class="type">JexlScript</span> filter) {
+            <span class="keyword">return</span> stream.<span 
class="method">filter</span>(x -&gt; x != <span class="keyword">null</span> 
&amp;&amp; TRUE.<span
+            class="method">equals</span>(filter.<span 
class="method">execute</span>(<span class="keyword">this</span>, x)));
+        }
+
+        <span class="comment">/**</span>
+<span class="comment">         * This allows using a JEXL lambda as a 
mapper.</span>
+<span class="comment">         *</span>
+<span class="comment">         * @param stream the stream</span>
+<span class="comment">         * @param mapper the lambda to use as 
mapper</span>
+<span class="comment">         * @return the mapped stream</span>
+<span class="comment">         */</span>
+        <span class="keyword">public</span> <span 
class="type">Stream</span>&lt;?&gt; <span class="method">map</span>(<span 
class="keyword">final</span> <span
+            class="type">Stream</span>&lt;?&gt; stream, <span 
class="keyword">final</span> <span class="type">JexlScript</span> mapper) {
+            <span class="keyword">return</span> stream.<span 
class="method">map</span>(x -&gt; mapper.<span 
class="method">execute</span>(<span class="keyword">this</span>, x));
+        }
+    }
+
+    <span class="comment">/** Our engine instance. */</span>
+    <span class="keyword">private final</span> <span 
class="type">JexlEngine</span> jexl;
+
+    <span class="keyword">public</span> <span 
class="method">StreamTest</span>() {
+        <span class="comment">// Restricting features; no loops, no side 
effects</span>
+        <span class="keyword">final</span> <span 
class="type">JexlFeatures</span> features = <span class="keyword">new</span> 
<span class="type">JexlFeatures</span>()
+            .<span class="method">loops</span>(<span 
class="keyword">false</span>)
+            .<span class="method">sideEffectGlobal</span>(<span 
class="keyword">false</span>)
+            .<span class="method">sideEffect</span>(<span 
class="keyword">false</span>);
+        <span class="comment">// Restricted permissions to a safe set but with 
URI allowed</span>
+        <span class="keyword">final</span> <span 
class="type">JexlPermissions</span> permissions = <span 
class="keyword">new</span> <span 
class="type">ClassPermissions</span>(java.net.URI.<span
+            class="keyword">class</span>);
+        <span class="comment">// Create the engine</span>
+        jexl = <span class="keyword">new</span> <span 
class="type">JexlBuilder</span>()
+            .<span class="method">features</span>(features)
+            .<span class="method">permissions</span>(permissions)
+            .<span class="method">namespaces</span>(Collections.<span 
class="method">singletonMap</span>(<span class="string">"URI"</span>, 
java.net.URI.<span
+            class="keyword">class</span>))
+            .<span class="method">create</span>();
+    }
+
+    <span class="annotation">@Test</span>
+    <span class="keyword">void</span> <span 
class="method">testURICollection</span>() {
+        <span class="comment">// A collection map/filter aware context</span>
+        <span class="keyword">final</span> <span 
class="type">JexlContext</span> sctxt = <span class="keyword">new</span> <span 
class="type">CollectionContext</span>();
+        <span class="comment">// Some uris</span>
+        <span class="keyword">final</span> <span 
class="type">List</span>&lt;<span class="type">URI</span>&gt; uris = 
Arrays.<span class="method">asList</span>(
+            URI.<span class="method">create</span>(<span 
class="string">"http://[email protected]:8000?qry=true";</span>),
+            URI.<span class="method">create</span>(<span 
class="string">"https://commons.apache.org/releases/prepare.html";</span>),
+            URI.<span class="method">create</span>(<span 
class="string">"mailto:[email protected]";</span>)
+        );
+
+        <span class="comment">// filter, all results schemes start with 
'http'</span>
+        <span class="keyword">final</span> <span 
class="type">JexlScript</span> filter = jexl.<span 
class="method">createScript</span>(
+            <span class="string">"list.filter(uri -&gt; uri.scheme =^ 
'http')"</span>,
+            <span class="string">"list"</span>);
+        <span class="keyword">final</span> <span class="type">Object</span> 
filtered = filter.<span class="method">execute</span>(sctxt, uris);
+        <span class="method">assertInstanceOf</span>(List.<span 
class="keyword">class</span>, filtered);
+        <span class="type">List</span>&lt;<span class="type">URI</span>&gt; 
result = (<span class="type">List</span>&lt;<span class="type">URI</span>&gt;) 
filtered;
+        <span class="method">assertEquals</span>(<span 
class="number">2</span>, result.<span class="method">size</span>());
+        <span class="keyword">for</span>(<span class="keyword">final</span> 
<span class="type">URI</span> uri : result) {
+            <span class="method">assertTrue</span>(uri.<span 
class="method">getScheme</span>().<span class="method">startsWith</span>(<span 
class="string">"http"</span>));
+        }
+
+        <span class="comment">// map, all results scheme now 'https'</span>
+        <span class="keyword">final</span> <span 
class="type">JexlScript</span> mapper = jexl.<span 
class="method">createScript</span>(
+            <span class="string">"list.map(uri -&gt; uri.scheme =^ 'http'? 
URI:create(`https://${uri.host}`) : null)"</span>,
+            <span class="string">"list"</span>);
+        <span class="keyword">final</span> <span class="type">Object</span> 
transformed = mapper.<span class="method">execute</span>(sctxt, uris);
+        <span class="method">assertInstanceOf</span>(List.<span 
class="keyword">class</span>, transformed);
+        result = (<span class="type">List</span>&lt;<span 
class="type">URI</span>&gt;) transformed;
+        <span class="method">assertEquals</span>(<span 
class="number">2</span>, result.<span class="method">size</span>());
+        <span class="keyword">for</span> (<span class="keyword">final</span> 
<span class="type">URI</span> uri : result) {
+            <span class="method">assertEquals</span>(<span 
class="string">"https"</span>, uri.<span class="method">getScheme</span>());
+        }
+    }
+
+    <span class="annotation">@Test</span>
+    <span class="keyword">void</span> <span 
class="method">testURIStream</span>() {
+        <span class="comment">// Assume a collection of uris need to be 
processed and transformed to be simplified ;</span>
+        <span class="comment">// we want only http/https ones, only the host 
part and using a https scheme</span>
+        <span class="keyword">final</span> <span 
class="type">List</span>&lt;<span class="type">URI</span>&gt; uris = 
Arrays.<span class="method">asList</span>(
+                URI.<span class="method">create</span>(<span 
class="string">"http://[email protected]:8000?qry=true";</span>),
+                URI.<span class="method">create</span>(<span 
class="string">"https://commons.apache.org/releases/prepare.html";</span>),
+                URI.<span class="method">create</span>(<span 
class="string">"mailto:[email protected]";</span>)
+        );
+        <span class="comment">// Create the test control, the expected result 
of our script evaluation</span>
+        <span class="keyword">final</span> <span 
class="type">List</span>&lt;?&gt; control =  uris.<span 
class="method">stream</span>()
+                .<span class="method">map</span>(uri -&gt; uri.<span 
class="method">getScheme</span>().<span class="method">startsWith</span>(<span
+            class="string">"http"</span>)? <span 
class="string">"https://";</span> + uri.<span class="method">getHost</span>() : 
<span class="keyword">null</span>)
+                .<span class="method">filter</span>(Objects::nonNull)
+                .<span class="method">collect</span>(Collectors.<span 
class="method">toList</span>());
+        <span class="method">assertEquals</span>(<span 
class="number">2</span>, control.<span class="method">size</span>());
+
+        <span class="comment">// Create scripts:</span>
+        <span class="comment">// uri is the name of the variable used as 
parameter; the beans are exposed as properties</span>
+        <span class="comment">// note that it is also used in the backquoted 
string</span>
+        <span class="keyword">final</span> <span 
class="type">JexlScript</span> mapper = jexl.<span 
class="method">createScript</span>(<span class="string">"uri.scheme =^ 'http'? 
`https://${uri.host}` : null"</span>, <span
+            class="string">"uri"</span>);
+        <span class="comment">// using the bang-bang / !! - JScript like -  is 
the way to coerce to boolean in the filter</span>
+        <span class="keyword">final</span> <span 
class="type">JexlScript</span> transform = jexl.<span 
class="method">createScript</span>(
+                <span class="string">"list.stream().map(mapper).filter(x -&gt; 
!!x).collect(Collectors.toList())"</span>, <span class="string">"list"</span>);
+
+        <span class="comment">// Execute scripts:</span>
+        <span class="keyword">final</span> <span 
class="type">JexlContext</span> sctxt = <span class="keyword">new</span> <span 
class="type">StreamContext</span>();
+        <span class="comment">// expose the static methods of Collectors; 
java.util.* is allowed by permissions</span>
+        sctxt.<span class="method">set</span>(<span 
class="string">"Collectors"</span>, Collectors.<span 
class="keyword">class</span>);
+        <span class="comment">// expose the mapper script as a global variable 
in the context</span>
+        sctxt.<span class="method">set</span>(<span 
class="string">"mapper"</span>, mapper);
+
+        <span class="keyword">final</span> <span class="type">Object</span> 
transformed = transform.<span class="method">execute</span>(sctxt, uris);
+        <span class="method">assertInstanceOf</span>(List.<span 
class="keyword">class</span>, transformed);
+        <span class="method">assertEquals</span>(control, transformed);
+    }
+}
+</code>
+      </pre>
+    </div>
+  </div>
+
+  <h2>Extensions to JSTL Expression Language</h2>
+  <p>
+    JEXL attempts to bring some of the lessons learned by the Velocity 
community about expression languages in templating to a wider audience. <a
+      href="https://commons.apache.org/jelly";>Commons Jelly</a> needed 
Velocity-ish method access, it just had to have it.
+  </p>
+  <p>
+    It must be noted that JEXL is <strong>not</strong> a compatible 
implementation of EL as defined in JSTL 1.1 (JSR-052) or JSP 2.0 (JSR-152). For 
a compatible
+    implementation of these specifications, see the <a 
href="https://commons.apache.org/el";>Commons EL</a> project.
+  </p>
+  <p>While JEXL 3.3 is now closer to JScript (without prototypes), its roots 
are the expression language defined in JSTL and its has improved upon its
+    syntax in a few areas:</p>
+  <ul>
+    <li>Support for invocation of any accessible method (see example 
above).</li>
+    <li>Support for setting/getting any accessible public field.</li>
+    <li>A general <span class="literal">new()</span> method allowing to 
instantiate objects.
+    </li>
+    <li>A general <span class="literal">size()</span> method, which works on:
+      <ul>
+        <li><span class="literal">String</span> - returns length</li>
+        <li><span class="literal">Map</span> - returns number of keys</li>
+        <li><span class="literal">List</span> - returns number of 
elements.</li>
+      </ul>
+    </li>
+    <li>A general <span class="literal">empty()</span> method, which works on 
Collections and Strings.
+    </li>
+    <li>Support for the ternary operator 'a ? b : c' - and its GNU-C / "Elvis" 
variant 'a ?: c'.</li>
+    <li>Support for the Perl-like regex matching operators '=~' and '!~'</li>
+    <li>Support for the CSS3-inspired 'startsWith' and 'endsWith' operators 
'=^' and '=$'</li>
+    <li>Support for user-defined functions.</li>
+    <li>Misc : '+' has been overloaded to be use as a String concatenation 
operator</li>
+  </ul>
+
+  <h2>Related Resources</h2>
+  <p>JEXL is not a product of the Java Community Process (JCP), but it 
provides a similar expression syntax. For more information about JSP 2.0 EL and 
JSTL
+    1.1 EL:</p>
+  <ul>
+    <li><a 
href="http://www.oracle.com/technetwork/java/index-jsp-138231.html";>JSP 2.0</a> 
is covered by Java Specification Requests (JSR) <a
+      href="http://www.jcp.org/en/jsr/detail?id=152";>JSR-152: JavaServer Pages 
2.0 Specification</a>.</li>
+    <li>Apache has an implementation of the expression language for JSP 2.0, 
called <a href="https://commons.apache.org/el/index.html";>EL</a>
+    </li>
+    <li><a 
href="http://www.oracle.com/technetwork/java/index-jsp-135995.html";>JSTL 
1.1</a> is covered by <a href="http://jcp.org/en/jsr/detail?id=52";>JSR
+        52: A Standard Tag Library for JavaServer Pages</a>. See the <a 
href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/";>JSTL API</a>.</li>
+    <li>Apache has a <a href="http://tomcat.apache.org/taglibs/standard/";>JSTL 
Implementation</a>.
+    </li>
+  </ul>
+  <h3>Velocity</h3>
+  <p>
+    <a href="http://velocity.apache.org/";>Apache Velocity</a> implements a 
similar expression language.
+  </p>
+  <p>
+    In particular the <a 
href="http://velocity.apache.org/engine/devel/user-guide.html#References";>References</a>
 section of the User Guide has some good
+    information on properties and method which correlate directly to JEXL.
+  </p>
+
+  <h2>Projects Using Commons JEXL</h2>
+  <ul>
+    <li><a href="https://commons.apache.org/configuration";>Commons 
Configuration</a></li>
+    <li><a href="https://commons.apache.org/scxml";>Commons SCXML</a></li>
+    <li><a href="https://commons.apache.org/jelly";>Jelly</a></li>
+  </ul>
+
+  <h2>Requirements</h2>
+  <ul>
+    <li>Java 8 or above.</li>
+    <li>If using OSGi, R7 or above.</li>
+  </ul>
+</body>
+</html>

Reply via email to