You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Henri Biestro (Jira)" <ji...@apache.org> on 2021/06/10 08:26:00 UTC

[jira] [Resolved] (JEXL-350) map[null] throws "unsolvable property" when a Sandbox is used

     [ https://issues.apache.org/jira/browse/JEXL-350?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Henri Biestro resolved JEXL-350.
--------------------------------
    Resolution: Fixed

Added to hotfix train.

> map[null] throws "unsolvable property" when a Sandbox is used
> -------------------------------------------------------------
>
>                 Key: JEXL-350
>                 URL: https://issues.apache.org/jira/browse/JEXL-350
>             Project: Commons JEXL
>          Issue Type: Improvement
>    Affects Versions: 3.1
>         Environment: jdk-11.0.5_10-hotspot
> JEXL git pull on 2021-06-03
>  
>            Reporter: David Costanzo
>            Assignee: Henri Biestro
>            Priority: Major
>             Fix For: 3.2.1
>
>
> In JEXL 3.2 SNAPSHOT, you can can access a null property in a map if you have no sandbox, but you cannot access a null property in a map if you have an "allow box" sandbox.  This asymmetry is weird and might be an oversight.
> The fix for JEXL-327 allows setting a null property in a map using the array syntax, but only for the case where there is no sandbox.  The fix for JEXL-291 allows array-style access to values in a map when using a sandbox.  What remains is the intersection of these two use cases: accessing a null property in a map using the array-access syntax when there's a sandbox.
>  
> *Impact:*
> In my domain (working with data from clinical trials), a null numeric value means "missing", which is a valid value.  Our JEXL programmers implement "switch" statements using a map, so you might see an expression that translates a coded variable named "DMSEX" into an English description like:
> {code:java}
> {
>    null : "Unknown",
>    1    : "MALE",
>    2    : "FEMALE"
> }[DMSEX]{code}
> Not being able to read the "Unknown" value when DMSEX=null is a problem that we've had to work around by copying the internal class SandboxUberspect and hacking it to allow this.
>  
> *Technical Details:*
> I think the problem starts in SandboxUbserspect.getPropertyGet() because identifier is null.  In this case, the most of the logic is skipped and null is returned, indicating that the property is undefined.
> {code:java}
> @Override
> public JexlPropertyGet getPropertyGet(final List<PropertyResolver> resolvers,
>                                       final Object obj,
>                                       final Object identifier) {
>     if (obj != null && identifier != null) {
>         final String property = identifier.toString();
>         final String actual = sandbox.read(obj.getClass(), property);
>         if (actual != null) {
>              // no transformation, strict equality: use identifier before string conversion
>             final Object pty = actual == property? identifier : actual;
>             return uberspect.getPropertyGet(resolvers, obj, pty);
>         }
>     }
>     return null;
> }
> {code}
> In my superficial understanding, the Sandbox.read() method doesn't have a way to distinguish between "null is the property you want to read" and "access is blocked" so in my hack, I had to always allow read access of null.
>  
> *Steps to Reproduce:*
> Below are some unit tests which show the four possibilities of with/without sandbox and get/set null.  I've included the behavior in JEXL 3.1 and a recent build of github as comments.
> {code:java}
> @Test
> public void testGetNullKeyWithNoSandbox() throws Exception {
>     JexlEngine jexl = new JexlBuilder().create();
>     JexlContext jc = new MapContext();
>     JexlExpression expression = jexl.createExpression("{null : 'foo'}[null]");
>     // JEXL 3.1, works
>     // JEXL 3.2, works
>     Object o = expression.evaluate(jc);
>     Assert.assertEquals("foo", o);
> }
>     
> @Test
> public void testGetNullKeyWithSandbox() throws Exception {
>     JexlEngine jexl = new JexlBuilder().sandbox(new JexlSandbox(true)).create();
>     JexlContext jc = new MapContext();
>     JexlExpression expression = jexl.createExpression("{null : 'foo'}[null]");
>     // JEXL 3.1, throws JexlException$Property "unsolvable property '<?>.<null>'"
>     // JEXL 3.2, throws JexlException$Property "undefined property '<?>.<null>'"
>     Object o = expression.evaluate(jc);
>     Assert.assertEquals("foo", o);
> }
> @Test
> public void testSetNullKeyWithNoSandbox() throws Exception {
>     JexlEngine jexl = new JexlBuilder().create();
>     JexlContext jc = new MapContext();
>     JexlExpression expression = jexl.createExpression("{null : 'foo'}[null] = 'bar'");
>     
>     // JEXL 3.1, throws JexlException$Property "unsolvable property '<?>.<null>'"
>     // JEXL 3.2, works
>     expression.evaluate(jc);
> }
> @Test
> public void testSetNullKeyWithSandbox() throws Exception {
>     JexlEngine jexl = new JexlBuilder().sandbox(new JexlSandbox(true)).create();
>     JexlContext jc = new MapContext();
>     JexlExpression expression = jexl.createExpression("{null : 'foo'}[null] = 'bar'");
>     // JEXL 3.1, throws JexlException$Property "unsolvable property '<?>.<null>'"
>     // JEXL 3.2, throws JexlException$Property "undefined property '<?>.<null>'"
>     expression.evaluate(jc);
> }{code}
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)