{"id":20721623,"url":"https://github.com/fslev/json-compare","last_synced_at":"2025-04-06T06:09:15.649Z","repository":{"id":38302068,"uuid":"136750453","full_name":"fslev/json-compare","owner":"fslev","description":"A Java library for comparing JSONs","archived":false,"fork":false,"pushed_at":"2025-03-28T19:12:05.000Z","size":726,"stargazers_count":68,"open_issues_count":1,"forks_count":13,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-30T05:05:33.299Z","etag":null,"topics":["assertion","compare","diff","java","json","match","regex"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fslev.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","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":"2018-06-09T19:05:58.000Z","updated_at":"2025-03-28T19:12:09.000Z","dependencies_parsed_at":"2023-02-16T12:16:03.633Z","dependency_job_id":"30de7313-9f81-49bd-b391-afa93af07f0a","html_url":"https://github.com/fslev/json-compare","commit_stats":null,"previous_names":[],"tags_count":61,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fjson-compare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fjson-compare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fjson-compare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fjson-compare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fslev","download_url":"https://codeload.github.com/fslev/json-compare/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247441052,"owners_count":20939239,"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":["assertion","compare","diff","java","json","match","regex"],"created_at":"2024-11-17T03:28:44.233Z","updated_at":"2025-04-06T06:09:15.641Z","avatar_url":"https://github.com/fslev.png","language":"Java","readme":"# JSON Compare \u003csup\u003e[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://vshymanskyy.github.io/StandWithUkraine)\u003c/sup\u003e\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.fslev/json-compare.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.fslev%22%20AND%20a:%22json-compare%22)\n![Build status](https://github.com/fslev/json-compare/actions/workflows/maven.yml/badge.svg?branch=main)\n[![Coverage Status](https://coveralls.io/repos/github/fslev/json-compare/badge.svg?branch=main)](https://coveralls.io/github/fslev/json-compare?branch=main)\n\n\n\nA Java library for matching JSONs, with some tweaks !\n\n## Brief\nCompare any JSON convertible Java objects and check the differences between them when matching fails.  \nThe library has some tweaks which helps you make assertions without writing any code at all.  \n\n# Features\n- **[Compare modes](#compare-modes)**\n- **[Regex support](#regex)**\n- **[Differences](#differences)**\n- **[Tweaks](#tweaks)**\n- **[Json Path support](#json-path)**\n- **[Extended](#extended)**\n## Based on\n\n1. Junit Jupiter API\n2. Jackson\n3. Jayway json-path\n\n## Central Repository\n\n#### Apache Maven\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.fslev\u003c/groupId\u003e\n    \u003cartifactId\u003ejson-compare\u003c/artifactId\u003e\n    \u003cversion\u003e${version.from.maven.central}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n#### Gradle/Grails\n```\ncompile 'com.github.fslev:json-compare:\u003cversion.from.maven.central\u003e'\n```\n\n### Match JSONs\nJSONCompare will automatically try to convert any given expected or actual Java objects to [Jackson JsonNode](https://fasterxml.github.io/jackson-databind/javadoc/2.7/com/fasterxml/jackson/databind/JsonNode.html)s and match them.  \n```javascript\n// expected as String with regex\nString expectedString = \n\"\"\"\n    {\n      \"string\": \"I'm on a seafood diet. I see food and I eat it!\",\n      \"number\": \"\\\\\\\\d+.\\\\\\\\d+\",\n      \"object\": {\n        \"pun\": \"\\\\\\\\QWhy don't skeletons fight each other? They don't have the guts!\\\\\\\\E\"\n      },\n      \"array\": [\".*\", \"\\\\\\\\d+\"],\n      \"boolean\": \"true|false\"\n    }\n\"\"\";\n\n// actual as String\nString actualString = \n\"\"\"\n    {\n      \"string\": \"I'm on a seafood diet. I see food and I eat it!\",\n      \"number\": 0.99,\n      \"object\": {\n        \"pun\": \"Why don't skeletons fight each other? They don't have the guts!\"\n      },\n      \"array\": [\"pancake\", 18, true, null],\n      \"boolean\": true\n    }\n\"\"\";\n\nJSONCompare.assertMatches(expectedString, actualString); // assertion passes\n```\n\nBoth expected and actual can be represented as any JSON convertible object:  \n```javascript\nString expectedString = \"{\\\"a\\\":1, \\\"b\\\": [4, \\\"ipsum\\\", \\\"\\\\\\\\d+\\\"]}\";\n\n// actual represented as Map\nMap\u003cString, Object\u003e actualMap = new HashMap\u003c\u003e();\nactualMap.put(\"a\", 1);\nactualMap.put(\"b\", Arrays.asList(\"ipsum\", 4, 5));\nactualMap.put(\"c\", true);\n\nJSONCompare.assertMatches(expectedString, actualMap); // assertion passes\n```\n\n# \u003ca name=\"compare-modes\"\u003e\u003c/a\u003eCompare modes\n\nBy default, [JSONCompare](https://github.com/fslev/json-compare) rules out the Json sizes and also the order of elements from an array. \nThis behaviour can be overridden by using the following compare modes:  \n* JSON_OBJECT_NON_EXTENSIBLE\n* JSON_ARRAY_NON_EXTENSIBLE\n* JSON_ARRAY_STRICT_ORDER\n\n_Example of **JSON_OBJECT_NON_EXTENSIBLE**:_\n```javascript\n// Expected Json is included in actual Json\nString expected = \"{\\\"b\\\": \\\"val1\\\"}\";\nString actual = \"{\\\"a\\\":\\\"val2\\\", \\\"b\\\":\\\"val1\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n\n// JSON objects MUST have same sizes\nString expected1 = \"{\\\"b\\\": \\\"val1\\\"}\";\nString actual1 = \"{\\\"a\\\":\\\"val2\\\", \\\"b\\\":\\\"val1\\\"}\";\nJSONCompare.assertNotMatches(expected1, actual1, Set.of(CompareMode.JSON_OBJECT_NON_EXTENSIBLE)); // assertion passes\nJSONCompare.assertMatches(expected1, actual1, Set.of(CompareMode.JSON_OBJECT_NON_EXTENSIBLE)); // assertion fails\n\n==\u003e                             \norg.opentest4j.AssertionFailedError: FOUND 1 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$ -\u003e Actual JSON OBJECT has extra fields\n```\n...same for **JSON_ARRAY_NON_EXTENSIBLE**  \n\n_Example of **JSON_ARRAY_STRICT_ORDER**:_\n```javascript\n// JSON array strict order is by default ignored\nString expected = \"[\\\"lorem\\\", 2, false]\";\nString actual = \"[false, 2, \\\"lorem\\\", 5, 4]\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n\n// Check JSON array strict order\nString expected1 = \"[\\\"lorem\\\", 2, false]\";\nString actual1 = \"[false, 2, \\\"lorem\\\", 5, 4]\";\nJSONCompare.assertNotMatches(expected1, actual1, Set.of(CompareMode.JSON_ARRAY_STRICT_ORDER)); // assertion passes\nJSONCompare.assertMatches(expected1, actual1, Set.of(CompareMode.JSON_ARRAY_STRICT_ORDER)); // assertion fails\n\n==\u003e\norg.opentest4j.AssertionFailedError: FOUND 2 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$[0]\nExpected value: \"lorem\" But got: false\n\n_________________________DIFF__________________________\n$[2]\nExpected boolean: false But got: \"lorem\"\n```\n\n# \u003ca name=\"regex\"\u003e\u003c/a\u003e Regular expression support\n\nYou can use regular expressions on expected JSON values:\n```javascript\nString expected = \"{\\\"a\\\": \\\".*me.*\\\"}\";\nString actual = \"{\\\"a\\\": \\\"some text\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n```\n, but also on expected JSON object fields:\n\n```javascript\nString expected = \"{\\\".*oba.*\\\": \\\"some value\\\"}\";\nString actual = \"{\\\"foobar\\\": \\\"some value\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n```\n\n[JSONCompare](https://github.com/fslev/json-compare) is by default case-sensitive and supports regular expressions on JSON fields and values.  \nIf you have unintentional regex characters inside either expected values or expected fields, then you can quote them:  \n\n```javascript\nString expected = \"{\\\"a\\\":\\\"\\\\\\\\Qd+\\\\\\\\E\\\"}\";\nString actual = \"{\\\"a\\\":\\\"d+\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n```\n\nBy quoting special characters, using \\Q and \\E, you disable the regex mechanism for that corresponding sequence.  \nFrom Java _Pattern_ docs:  \n```\n\\Q\tNothing, but quotes all characters until \\E\n\\E\tNothing, but ends quoting started by \\Q\n```\n\nIf you want to enable case-insensitivity, then use `(?i)` and `(?-i)` modifiers.  \nHowever, you can ignore the default regular expression compare mode, by using a ***custom comparator***\n```javascript\nString expected = \"{\\\"a\\\": \\\"\\\\\\\\d+\\\"}\";\nString actual = \"{\\\"a\\\": \\\"\\\\\\\\d+\\\"}\";\nJSONCompare.assertMatches(expected, actual, new JsonComparator() {\n    public boolean compareValues(Object expected, Object actual) {\n        return expected.equals(actual);\n    }\n\n    public boolean compareFields(String expected, String actual) {\n        return expected.equals(actual);\n    }\n}); // assertion passes\n```\nOR, use CompareMode.REGEX_DISABLED:\n```javascript\nString expected = \"{\\\"a\\\":\\\"(some value)\\\"}\";\nString actual = \"{\\\"a\\\":\\\"(some value)\\\"}\";\nJSONCompare.assertMatches(expected, actual, new HashSet\u003c\u003e(Collections.singletonList(CompareMode.REGEX_DISABLED))); // assertion passes\nJSONCompare.assertMatches(expected, actual); // assertion fails\n```\n\n# \u003ca name=\"differences\"\u003e\u003c/a\u003eDifferences\nMatching is based on soft assertion. It does not stop at first encountered difference, but it continues until expected JSON is depleted. \nAll differences are displayed via the AssertionError message from `JSONCompare.assertMatches()` or can be obtained as a List of Strings by using `JSONCompare.diffs()`:    \n## Differences inside AssertionError message\n```javascript\nString expected = \n    \"\"\"\n    {\n      \"caught\": false,\n      \"pain\": {\n        \"range\": [\n          \"bell\",\n          \"blue\",\n          -2059921070\n        ],\n        \"not_anyone\": -1760889549.4041045,\n        \"flat\": -2099670336\n      }\n    }\n    \"\"\";\n        \nString actual = \n    \"\"\"\n    {\n      \"caught\": true,\n      \"pain\": {\n        \"range\": [\n          \"bell\",\n          \"red\",\n          -2059921075\n        ],\n        \"anyone\": -1760889549.4041045,\n        \"flat\": -2099670336\n      },\n      \"broad\": \"invented\"\n    }\n    \"\"\";\n\nJSONCompare.assertMatches(expected, actual); // assertion fails\n```\n#### Output\n```javascript\norg.opentest4j.AssertionFailedError: FOUND 4 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$.caught\nExpected value: false But got: true\n\n_________________________DIFF__________________________\n$.pain.range[1] was not found:\n\"blue\"\n\n_________________________DIFF__________________________\n$.pain.range[2] was not found:\n-2059921070\n\n_________________________DIFF__________________________\n$.pain.not_anyone was not found\n\n\nJson matching by default uses regular expressions.\nIn case expected json contains any unintentional regexes, then quote them between \\Q and \\E delimiters or use a custom comparator.\n ==\u003e \n\u003cClick to see difference\u003e\n```\n## Differences as a list of Strings  \n```\nList\u003cString\u003e diffs = JSONCompare.diffs(expected, actual);\n```\n\n# \u003ca name=\"tweaks\"\u003e\u003c/a\u003eMatching with some tweaks\n\n[JSONCompare](https://github.com/fslev/json-compare) has some tweaks which help you to _fine tune_ the matching mechanism.  \nThese tweaks can be directly **embedded inside the expected JSON**, thus \u003cins\u003eyou don't have to write any code at all\u003cins\u003e:  \n\n- DO_NOT_MATCH  `!`\n- DO_NOT_MATCH_ANY  `!.*`\n- MATCH_ANY  `.*`\n- JSON PATH expressions `#(..)`\n\n### DO NOT MATCH `!`\nBy using the `!` **DO NOT MATCH** option, the comparison between JSON values will be negated:    \n\n```javascript\nString expected = \"{\\\"a\\\": \\\"!test\\\"}\";\nString actual = \"{\\\"a\\\": \\\"testing\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n```\nor, between JSON object fields\n```javascript\nString expected = \"{\\\"!a\\\": \\\"value does not matter\\\"}\";\nString actual = \"{\\\"b\\\": \\\"of course value does not matter\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n```\n\nNegating a field name, it means that the actual JSON object should not have any field with same name on same level.\n**In this particular case, field values are ignored**.  \n\nOf course, you can use negative lookahead or lookbehind regular expressions\n```javascript\nString expected = \"{\\\"(?!lorem.*).*\\\": \\\"valorem\\\"}\";\nString actual = \"{\\\"ipsum\\\": \\\"valorem\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion passes\n```\nThe assertion will pass if the actual JSON has a field which does not contain _'lorem'_ and which points to value _'valorem'_.  \nSame goes for JSON arrays.  \n\n### DO NOT MATCH ANY `!.*`\nCheck for extra JSON values or fields by using the power of `regex` and **DO_NOT_MATCH_ANY** use case  \n```javascript\n// actual JSON object should NOT contain any extra fields\nString expected = \"{\\\"b\\\": \\\"val1\\\", \\\"!.*\\\": \\\".*\\\"}\";\nString actual = \"{\\\"a\\\": \\\"val2\\\", \\\"b\\\": \\\"val1\\\"}\";\nJSONCompare.assertMatches(expected, actual); //assertion fails\n\n==\u003e\norg.opentest4j.AssertionFailedError: FOUND 1 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$.\"!.*\" condition was not met. Actual JSON OBJECT has extra fields\n```\n```javascript\n// actual JSON array should NOT contain any extra elements\nString expected = \"[false, \\\"test\\\", 4, \\\"!.*\\\"]\";\nString actual = \"[4, false, \\\"test\\\", 1]\";\nJSONCompare.assertNotMatches(expected, actual); // assertion fails\n==\u003e\norg.opentest4j.AssertionFailedError: FOUND 1 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$[3] -\u003e Expected condition \"!.*\" was not met. Actual JSON ARRAY has extra elements\n```\n\n### MATCH ANY `.*`\nCheck actual Json should have extra fields or elements.  \n```javascript\n// Actual JSON object should have extra fields\nString expected = \"{\\\"b\\\": \\\"val1\\\", \\\".*\\\": \\\".*\\\"}\";\nString actual = \"{\\\"b\\\": \\\"val1\\\"}\";\nJSONCompare.assertMatches(expected, actual); // assertion fails\n\n==\u003e\norg.opentest4j.AssertionFailedError: FOUND 1 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$..* was not found\n```\n```javascript\n// Actual JSON array should have extra elements\nString expected = \"[false, \\\"test\\\", 4, \\\".*\\\"]\";\nString actual = \"[4, false, \\\"test\\\"]\";\nJSONCompare.assertMatches(expected, actual); // assertion fails\n\n==\u003e\norg.opentest4j.AssertionFailedError: FOUND 1 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$[3] -\u003e Expected condition \".*\" was not met. Actual JSON ARRAY has no extra elements\n```\n# \u003ca name=\"json-path\"\u003e\u003c/a\u003eEmbedded json path expression\nPowered by [JsonPath](https://github.com/json-path/JsonPath)  \nThe expected JSON can contain json path expressions delimited by `#(` and `)` together with the expected results:  \n```javascript\n// Select the 'isbn' values of store books and match with expected ones  \nString expected = \"{\\\"#($.store..isbn)\\\":[\\\"0-395-19395-8\\\", \\\"0-553-21311-1\\\", \\\"!.*\\\"]}\";\nString actual = \"{\\n\" +\n    \"    \\\"store\\\": {\\n\" +\n    \"        \\\"book\\\": [\\n\" +\n    \"            {\\n\" +\n    \"                \\\"category\\\": \\\"reference\\\",\\n\" +\n    \"                \\\"author\\\": \\\"Nigel Rees\\\",\\n\" +\n    \"                \\\"title\\\": \\\"Sayings of the Century\\\",\\n\" +\n    \"                \\\"price\\\": 8.95\\n\" +\n    \"            },\\n\" +\n    \"            {\\n\" +\n    \"                \\\"category\\\": \\\"fiction\\\",\\n\" +\n    \"                \\\"author\\\": \\\"Herman Melville\\\",\\n\" +\n    \"                \\\"title\\\": \\\"Moby Dick\\\",\\n\" +\n    \"                \\\"isbn\\\": \\\"0-553-21311-3\\\",\\n\" +\n    \"                \\\"price\\\": 8.99\\n\" +\n    \"            },\\n\" +\n    \"            {\\n\" +\n    \"                \\\"category\\\": \\\"fiction\\\",\\n\" +\n    \"                \\\"author\\\": \\\"J. R. R. Tolkien\\\",\\n\" +\n    \"                \\\"title\\\": \\\"The Lord of the Rings\\\",\\n\" +\n    \"                \\\"isbn\\\": \\\"0-395-19395-8\\\",\\n\" +\n    \"                \\\"price\\\": 22.99\\n\" +\n    \"            }\\n\" +\n    \"        ]\\n\" +\n    \"    }\\n\" +\n    \"}\";\nJSONCompare.assertMatches(expected, actual); // assertion fails\n\n==\u003e\norg.opentest4j.AssertionFailedError: FOUND 1 DIFFERENCE(S):\n\n\n_________________________DIFF__________________________\n$.#($.store..isbn)[1] was not found:\n\"0-553-21311-1\"\nExpected json path result:\n[\"0-395-19395-8\",\"0-553-21311-1\",\"!.*\"]\nBut got:\n[\"0-553-21311-3\",\"0-395-19395-8\"]\n```\n\n# \u003ca name=\"extended\"\u003e\u003c/a\u003e Extended\nYou might be also interested in looking into [JTest-Utils](https://github.com/fslev/jtest-utils) which uses JSONCompare with data capture support: \nhttps://github.com/fslev/jtest-utils?tab=readme-ov-file#17-match-and-capture\n\n## Website\nhttps://fslev.github.io/json-compare  \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffslev%2Fjson-compare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffslev%2Fjson-compare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffslev%2Fjson-compare/lists"}