Search code examples
elasticsearchelasticsearch-painless

Why Painless compiler complains about `new` keyword?


I am trying to create string from bytes in Painless script, as below, but ending up with error around new keyword. Our Elasticsearch is 6.2.8.

(Length check at the end is just for brevity so the script returns boolean.)

{
    "size": 1,
    "query": {
        "bool" : {
            "filter" : {
                "script" : {
                    "script" : {
                        "source": "byte[] a = new byte[]{65, 66, 67}; String b = new String(a, StandardCharsets.UTF_8); b.length() > 0",
                        "lang": "painless"
                     }
                }
            }
        }
    }
}

Error as below:

"script_stack": [
    "... {65, 66, 67}; String b = new String(a, StandardCha ...",
    "                             ^---- HERE"
],
"lang": "painless",
"type": "illegal_argument_exception",
"reason": "Unknown new call on type [java.lang.String]."

I have to admit I am confused. This is my first adventure with Painless but I saw dozens of examples with new keyword in them. Documentation clearly states that this is the way. Duh, it is even in the same script above. What am I missing? Why it is OK to create array but not string?


Solution

  • Post discussion via chat and after further digging, I figured out that String doesn't expose constructors via painless as specified in this link.

    This link would help you understand what all classes or packages are currently supported by ES painless.

    The error is appearing because StandardCharsets.UTF_8 belongs to package import java.nio.charset.StandardCharsets; and from the above link it appears that this class is not currently supported or mentioned as per the earlier link shared.

    Also I don't think painless allows you to make use of import statements. However, what you can try is as mentioned in this link which states the below:

    As of 6.2, painless can now have it's whitelist extended by plugins. Unfortunately this is not well documented yet, but we do have an example plugin.

    The basic idea is to create a plugin that "extends" painless, and tells painless about additional whitelist elements through SPI. The whitelist is per script context, so you will need to add these elements for any types of scripts you use. There is no central list of script contexts, but it looks like in this case you are using an update script? So that would be the update context. In your script, you can then use the classes, no importing necessary.

    If you have any plans to write your own plugin, you may want to look into section for plugin authors in the Introduction to plugins page.