{"id":18830161,"url":"https://github.com/gravitee-io/gravitee-expression-language","last_synced_at":"2025-07-24T14:06:32.539Z","repository":{"id":37395431,"uuid":"104226412","full_name":"gravitee-io/gravitee-expression-language","owner":"gravitee-io","description":"Expression Language used by Gravitee.io Components","archived":false,"fork":false,"pushed_at":"2025-04-03T15:03:08.000Z","size":335,"stargazers_count":3,"open_issues_count":2,"forks_count":4,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-04-03T16:22:15.699Z","etag":null,"topics":["product-platform","security-scan"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gravitee-io.png","metadata":{"files":{"readme":"README.adoc","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.adoc","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-20T14:29:42.000Z","updated_at":"2025-04-01T19:09:44.000Z","dependencies_parsed_at":"2024-03-18T12:03:40.973Z","dependency_job_id":"a0cc0e98-877a-4604-95d2-8beb7af0df7d","html_url":"https://github.com/gravitee-io/gravitee-expression-language","commit_stats":null,"previous_names":[],"tags_count":62,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravitee-io%2Fgravitee-expression-language","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravitee-io%2Fgravitee-expression-language/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravitee-io%2Fgravitee-expression-language/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravitee-io%2Fgravitee-expression-language/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gravitee-io","download_url":"https://codeload.github.com/gravitee-io/gravitee-expression-language/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248818719,"owners_count":21166468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["product-platform","security-scan"],"created_at":"2024-11-08T01:48:00.796Z","updated_at":"2025-04-14T03:42:04.959Z","avatar_url":"https://github.com/gravitee-io.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Gravitee Expression Language\n\nimage:https://img.shields.io/badge/License-Apache%202.0-blue.svg[\"License\", link=\"https://github.com/gravitee-io/gravitee-expression-language/blob/master/LICENSE.txt\"]\nimage:https://img.shields.io/badge/semantic--release-conventional%20commits-e10079?logo=semantic-release[\"Releases\", link=\"https://github.com/gravitee-io/gravitee-expression-language/releases\"]\nimage:https://circleci.com/gh/gravitee-io/gravitee-expression-language.svg?style=svg[\"CircleCI\", link=\"https://circleci.com/gh/gravitee-io/gravitee-expression-language\"]\nimage:https://f.hubspotusercontent40.net/hubfs/7600448/gravitee-github-button.jpg[\"Join the community forum\", link=\"https://community.gravitee.io?utm_source=readme\", height=20]\n\n== Description\n\nThis project provides a custom template engine for parsing https://documentation.gravitee.io/apim/getting-started/gravitee-expression-language[Expression Language] elements.\n\n== Usage\n\n=== Basic Usage\n\nEL expressions can be evaluated using a `TemplateEngine` instance:\n\n[source,java]\n----\nTemplateEngine engine = TemplateEngine.templateEngine();\n----\n\nTo pass variables to the `TemplateEngine`, use its context:\n\n[source,java]\n----\nTemplateEngine engine = TemplateEngine.templateEngine();\nTemplateContext context = engine.getTemplateContext();\n\ncontext.setVariable(\"myVar\", \"myValue\");\n----\n\nThe context remains available for any evaluated expression. You can evaluate an EL expression against your `TemplateEngine` instance. The first argument is the EL expression, and the second is the expected result type.\n\n[source,java]\n----\nTemplateEngine engine = TemplateEngine.templateEngine();\nTemplateContext context = engine.getTemplateContext();\n\ncontext.setVariable(\"myVar\", \"myValue\");\n\nengine.evalNow(\"{#myVar}\", String.class); // Result: \"myValue\"\nengine.evalNow(\"{#myVar.isEmpty()}\", Boolean.class); // Result: false\n----\n\nIMPORTANT: Ensure the expected result type matches the evaluated expression.\n\n=== Calling Functions\n\nA variable can be of any type and may expose functions:\n\n[source,java]\n----\n// Assign a user variable.\ncontext.setVariable(\"myUser\", new User(\"firstname\", \"lastname\"));\n\nengine.eval(\"{#myUser.getDisplayName()}\", String.class); // Calls getDisplayName() on the User instance.\n----\n\nIMPORTANT: You must explicitly declare the `User.getDisplayName()` function in the whitelist of authorized methods. See \u003c\u003cEL Sandbox\u003e\u003e for details.\n\n=== Reactive Usage\n\nTo evaluate an EL expression reactively, use `eval()` instead of `evalNow()`.\n\nIMPORTANT: evalNow() is not strictly equivalent to `eval()` as it does not rely on reactive stack and does not support deferred variables or reactive functions. Hence, `evalNow()` is not suitable for advanced usages such as evaluating an expression based on the content of the request or response body (e.g: `{#request.content}`). However, `evalNow()` remains suitable when evaluating expressions outside a request processing (e.g. API or Security Domain deployment, connector initialization, ...).\n\n[source,java]\n----\ncontext.setVariable(\"myVar\", \"myValue\");\n\nengine.eval(\"{#myVar}\", String.class); // Returns Maybe\u003cString\u003e\nengine.eval(\"{#myVar.isEmpty()}\", Boolean.class); // Returns Maybe\u003cBoolean\u003e\n----\n\n==== Deferred Variables\n\nThe `TemplateEngine` allows assigning **deferred variables**, useful for injecting values that must be fetched before evaluation. A deferred variable can be a `Maybe` or a `Single`.\n\n[source,java]\n----\n// Assigns a variable from an HTTP call.\ncontext.setDeferredVariable(\"myVar\", httpClient.fetch(\"https://somewhere.com\").flatMap(result::message));\n\nengine.eval(\"{#myVar}\", String.class); // Resolves myVar before evaluation.\n----\n\nTIP: A deferred variable is evaluated **only if used** in an expression. In the above example, `{#myVar}` triggers the HTTP call, while `{#anotherVar}` does not.\n\n==== Evaluating Functions Returning `Maybe` or `Single`\n\nIf you need to evaluate a function that returns a `Maybe` or `Single`, you must inject a specific implementation of `DeferredFunctionHolder` in the context:\n\n[source,java]\n----\nimport io.gravitee.el.spel.context.DeferredFunctionHolder;\n\nclass MyDeferredFunctionHolder implements DeferredFunctionHolder {\n    public Maybe\u003cString\u003e resolve(String param) {\n        // ... return a Maybe.\n    }\n\n    public Maybe\u003cString\u003e doSomethingReactive() {\n        // ... return a Maybe.\n    }\n};\n\n// Assigns myHolder in the context.\ncontext.setDeferredFunctionHolderVariable(\"myHolder\", new MyDeferredFunctionHolder());\n\nengine.eval(\"{#myHolder.resolve('something')}\", String.class); // Handles the Maybe returned by the function call and evaluates the final string.\n\nengine.eval(\"{#myHolder.doSomethingReactive()}\", String.class); // Handles the Maybe returned by the function call and evaluates the final string.\n----\n\n== EL Sandbox\n\nThe EL Template Engine includes a built-in sandbox feature, allowing safe execution of EL expressions. The sandbox operates based on a predefined whitelist of allowed methods, fields, and constructors.\n\n=== Whitelist Configuration\n\nThe sandbox provides the following configuration options:\n\n* `el.whitelist.mode`: Defines whether to `append` or `replace` the built-in whitelist.\n** `append` (default) - Adds new whitelisted definitions while keeping existing ones.\n** `replace` - Replaces the built-in list entirely (use with caution).\n\n  TIP: Always use `append` unless you are certain you need `replace`.\n\n* `el.whitelist.list`: Specifies additional methods, constructors, fields, or annotations to allow.\n** Prefix with `method` to allow a specific method (full signature required).\n** Prefix with `class` to allow an entire class (all methods, constructors, and fields will be accessible).\n\n==== Example Configuration\n\n[source,yaml]\n----\nel:\n  whitelist:\n    mode: append\n    list:\n      - method java.time.format.DateTimeFormatter ofLocalizedDate java.time.format.FormatStyle\n      - class java.time.format.DateTimeFormatter\n----\n\nWARNING: Be cautious when allowing entire classes or methods. Some classes may expose unintended methods, creating security risks.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgravitee-io%2Fgravitee-expression-language","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgravitee-io%2Fgravitee-expression-language","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgravitee-io%2Fgravitee-expression-language/lists"}