{"id":50592158,"url":"https://github.com/thiagolvlsantos/json-predicate","last_synced_at":"2026-06-05T11:03:11.910Z","repository":{"id":57735023,"uuid":"381218830","full_name":"thiagolvlsantos/json-predicate","owner":"thiagolvlsantos","description":"Create a filter Predicate\u003cObject\u003e using a JSON specification.","archived":false,"fork":false,"pushed_at":"2024-10-13T22:52:03.000Z","size":149,"stargazers_count":5,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-07T06:19:06.484Z","etag":null,"topics":["dsl","json"],"latest_commit_sha":null,"homepage":"https://thiagolvlsantos.github.io/json-predicate","language":"Java","has_issues":true,"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/thiagolvlsantos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-29T02:43:18.000Z","updated_at":"2024-10-13T22:52:06.000Z","dependencies_parsed_at":"2024-02-18T16:45:04.356Z","dependency_job_id":null,"html_url":"https://github.com/thiagolvlsantos/json-predicate","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/thiagolvlsantos/json-predicate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thiagolvlsantos%2Fjson-predicate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thiagolvlsantos%2Fjson-predicate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thiagolvlsantos%2Fjson-predicate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thiagolvlsantos%2Fjson-predicate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thiagolvlsantos","download_url":"https://codeload.github.com/thiagolvlsantos/json-predicate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thiagolvlsantos%2Fjson-predicate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33939227,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["dsl","json"],"created_at":"2026-06-05T11:03:10.626Z","updated_at":"2026-06-05T11:03:11.904Z","avatar_url":"https://github.com/thiagolvlsantos.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# json-predicate\n\n[![CI with Maven](https://github.com/thiagolvlsantos/json-predicate/actions/workflows/maven.yml/badge.svg)](https://github.com/thiagolvlsantos/json-predicate/actions/workflows/maven.yml)\n[![CI with CodeQL](https://github.com/thiagolvlsantos/json-predicate/actions/workflows/codeql.yml/badge.svg)](https://github.com/thiagolvlsantos/json-predicate/actions/workflows/codeql.yml)\n[![CI with Sonar](https://github.com/thiagolvlsantos/json-predicate/actions/workflows/sonar.yml/badge.svg)](https://github.com/thiagolvlsantos/json-predicate/actions/workflows/sonar.yml)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=thiagolvlsantos_json-predicate\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=thiagolvlsantos_json-predicate)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=thiagolvlsantos_json-predicate\u0026metric=coverage)](https://sonarcloud.io/dashboard?id=thiagolvlsantos_json-predicate)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.thiagolvlsantos/json-predicate/badge.svg)](https://repo1.maven.org/maven2/io/github/thiagolvlsantos/json-predicate/)\n[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0)\n\nSpecify a predicate in a JSON format and check it against a given object.\n\n## Usage\n\nInclude latest version [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.thiagolvlsantos/json-predicate/badge.svg)](https://repo1.maven.org/maven2/io/github/thiagolvlsantos/json-predicate/) to your project.\n\n```xml\n\t\t\u003cdependency\u003e\n\t\t\t\u003cgroupId\u003eio.github.thiagolvlsantos\u003c/groupId\u003e\n\t\t\t\u003cartifactId\u003ejson-predicate\u003c/artifactId\u003e\n\t\t\t\u003cversion\u003e${latestVersion}\u003c/version\u003e\n\t\t\u003c/dependency\u003e\n```\n\n## Predicates\n\nThe objective of this library is to create a `Predicate\u003cObject\u003e` based on a JSON specification which includes different types of predicates. The general idea is that these JSON predicates can be build using a GUI and be used in `filter` operations. \n\nThe general form of a predicate is:\n```json\n{ \n\t\"\u003cpath1\u003e\" : { \"$\u003coperator\u003e\": \"\u003cvalue\u003e | @\u003cpath2\u003e\" } \n}\n```\nwhere:\n- ```path1``` and ```path2```: stands for references like that the ones provided by Jakarta ```BeanUtils|PropertyUtils``` expressions (you can change it by implementing the interface ``IAccess``);\n- ```operator``` : is one of the possible operators predefined, or loaded by your code;\n- ```value```: is a string to be converted for comparison;\n\nAn example of a JSON predicate filtering objects (or maps) whose field/key called 'name' contains the String 'project':\n```json\n{\n   \"name\": {\n     \"$contains\": \"project\"\n   }\n}\n```\n\nSuppose there is a `List\u003cProject\u003e` where each project has a `String:name` attribute, the following code will filter only those with `project` in its attribute 'name'.\n\n```java\n\tIPredicateFactory factory = new PredicateFactoryJson();\n\n\tString filter = \"{\\\"name\\\":{\\\"$contains\\\": \\\"project\\\"}}\";\n\tPredicate\u003cObject\u003e p = factory.read(filter.getBytes());\n\n\tList\u003cProject\u003e projects = ...// loaded list from somewhere\n\treturn projects.stream().filter(p).collect(Collectors.toList());\n\n```\nIn this example, if we provide the filter value using a GUI the underlying Java code remains unchanged.\n\n## Syntatic suggars (rewrite engine)\nThere is an interface named ``IRewriter`` to \nrewrite a Json structure before processing.\nThere is a default implementation,\n by suggestion of [@vampireslove](https://github.com/vampireslove) a predicate like:``{\"name\":\"json-predicate\"}`` is automatically rewritten to the normal form as ``{\"name\": {\"$eq\":\"json-predicate\"} }``.\n\nTo replace this rewriter set your instante to the ``PredicateJsonFactory`` instante.\n\n## Converters\nBased on ```path1``` type the ```value``` is converted according to it. i.e for comparison with date the [`IConverter`](https://github.com/thiagolvlsantos/json-predicate/blob/master/src/main/java/io/github/thiagolvlsantos/json/predicate/value/impl/ConverterDefault.java) takes place and convert for types:\n| Attribute type | Value converted to compariosn using |\n| -- | -- |\n| ```java.util.Date``` | ```yyyy-MM-dd HH:mm:ss.SSS``` |\n| ```java.time.LocalDate``` | ```yyyy-MM-dd``` |\n| ```java.time.LocalDateTime``` | ```yyyy-MM-dd HH:mm:ss.SSS``` |\n\nThese converters can be replaced using respective set method in the predicate manager describe bellow.\n\n## Predefined constructors\n\nThere is a list of the built-in provided predicates, \nyou can register you own predicate. Checkout the interface \n[`IPredicateManager`](https://github.com/thiagolvlsantos/json-predicate/blob/master/src/main/java/io/github/thiagolvlsantos/json/predicate/impl/PredicateManagerDefault.java) implementation which load operators from properties. \n\nOperators names are case-insensitive, table camel-case names are only to help on reading.\n\n```properties\n$and,$\u0026=io.github.thiagolvlsantos.json.predicate.array.impl.PredicateAnd\n```\n\nThis class loads files in classpath (```json-predicate.properties```) with operators mappings, such as the example bellow. A default mapping ([json-predicate_default.properties]((https://github.com/thiagolvlsantos/json-predicate/blob/master/src/main/resources/json-predicate_default.properties))) is provided with the following built-in operators.\n\n### Logical operators\n\n| Type | Example |\n| -- | -- |\n|and, \u0026 | ``` { \"$and\": [ {\"name\": {\"$contains\": \"project\"} }, { \"created\": {\"$gt\": \"2021-06-29 00:31:45.000\"} ] }``` |\n|or, \\\\| | ``` { \"$or\": [ {\"name\": {\"$contains\": \"project\"} }, { \"id\": {\"$gt\": \"10\"} ] }``` |\n|not, ! | ``` { \"$not\": {\"name\": {\"$eq\": \"null\"} } }``` |\n\n### Relational operators\n| Type | Example |\n| -- | -- |\n|eq, ==, equals | ``` {\"name\": {\"$eq\": \"projectA\"} } ```|\n|ne, !=, notEquals | ``` {\"name\": {\"$ne\": \"projectB\"} }```|\n|lt, \\\u003c, lowerThan | ``` {\"revision\": {\"$lt\": 10} }```|\n|le, lte, \\\u003c=, lowerThanEquals, lowerEqualsThan | ``` {\"revision\": {\"$le\": 1} }```|\n|gt, \\\u003e, greaterThan | ``` {\"revision\": {\"$gt\": 1} }```|\n|ge, gte, \\\u003e=, greaterThanEquals, greaterEqualsThan | ``` {\"revision\": {\"$ge\": 2} }```|\n\n### String operators\n| Type | Example |\n| -- | -- |\n|contains, c, regex | ``` {\"name\": {\"$contains\": \"proj\"} }```|\n|nContains, nc, notContains, nRegex, !contains, !c, !regex  | ``` {\"name\": {\"$ncontains\": \"A\"} }```|\n|match, m | ``` {\"name\": {\"$match\": \"\\d{8}\"} }```|\n|nMatch, nm, notMatch, !match, !m | ``` {\"name\": {\"$nmatch\": \"\\d{8}\"} }```|\n\n### Set operators \n| | |\n| -- | -- |\n|contains, c | ``` {\"tags\": {\"$contains\": \"debug\"} }``` |\n|ncontains, nc, notContains, !contains, !c  | ``` {\"tags\": {\"$ncontains\": \"git\"} }``` |\n|memberOf, mo, in | ``` {\"role\": {\"$memberOf\": [\"admin\",\"user\"]} }``` |\n|nMemberOf, nmo, notMemberOf, !memberOf, !mo, !in | ``` {\"role\": {\"$notMemberOf\": [\"po\"]} }``` |\n\n### Variable operators \nYou can use values referring to another variables. i.e. if project changed date is greater than project creation date.\n\n|  |  |\n| -- | -- |\n| \"path1\" { \"operator\":\"@path2\" }  | ``` {\"changed\": {\"$\u003e\": \"@created\"} }```|\n\n## Overriding operators\nIf you want to override an operator add its mapping to the file ```json-predicate.properties``` together with an ```order``` key which is used to define precedence. The default file has ```order=0```.\n\nFor example, if you want to override ```$and``` in your file ```json-predicate.properties``` do:\n\n```properties\norder=1\n$and,$\u0026=mypackage.MyPredicate\n```\n\n## Deserialization\n\nA class can have an attribute annotated with `@JsonDeserializer` to read a `Predicate\u003cObject\u003e` straightforward.\n\n```java\n@Data\npublic class Rule {\n\n\tprivate String name;\n\n\t@JsonDeserialize(using = PredicateDeserializer.class)\n\tprivate Predicate\u003cObject\u003e condition;\n}\n```\n\nA file `example_rule.json`:\n\n```json\n{\n\t\"name\": \"Filter projects with A\",\n\t\"condition\": {\n\t\t\"name\": {\n\t\t\t\"$contains\": \"A\"\n\t\t}\n\t}\n}\n```\ncan be read by a Jackson `ObjectMapper` just like this:\n```java\n\tObjectMapper mapper = new ObjectMapper();\n\tRule rule = mapper.readValue(Files.readAllBytes(Paths.get(\"example_rule.json\")), Rule.class);\n\tPredicate\u003cObject\u003e condition = rule.getCondition(); // condition ready to apply\n```\n The resulting instance of `Rule` has the `condition` attribute already set to a `Predicate\u003cObject\u003e`.\n \n Notice that this approach can be used for deserializing REST calls where `@Payload` is an object of type `Rule`. On the other hand the serialization process is not defined, unless you write a serializer for a generic predicate (next steps?). \n \n As a generic solution there could be a `Rule` class with `condition` as `String` for storage/serialization/deserialization in CRUD features, and a `RuleExec` with `condition` as `Predicate\u003cObject\u003e` to the moments where the rule is expected to be processed. It`s up to you use what fit your needs.\n\n## Building\n\nLocaly, from this root directory call Maven commands or `bin/\u003cscript name\u003e` at your will.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthiagolvlsantos%2Fjson-predicate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthiagolvlsantos%2Fjson-predicate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthiagolvlsantos%2Fjson-predicate/lists"}