JsonPath learning notes

Posted by JakeTheSnake3.0 on Mon, 10 Jan 2022 15:48:00 +0100

summary

introduce

JsonPath is used to extract the content in json documents. It is a path expression just as xpath is used to extract the content in html or xml.

The json path package in the Java language is mentioned here. Other languages such as JavaScript can also use JsonPath, but the third package related to parsing is different. The package used below is supported by the Java language, but the syntax of json path expression is general.

If you use Gson to parse json and extract individual values, the code will be a lot of trouble, while JsonPath only needs a simple path expression to extract values, and the code is concise.

Generally, crawlers need to extract the content in json.

Its official website address: JsonPath

install

Its maven coordinates are as follows:

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.6.0</version>
</dependency>

If an error is reported, caused by: Java Lang.noclassdeffounderror: Net / minidev / JSON / writer / jsonreaderi needs to add the following dependencies:

<dependency>
    <groupId>net.minidev</groupId>
    <artifactId>asm</artifactId>
    <version>1.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.2.1</version>
<scope>test</scope>
</dependency>

introduction

The root member object in JsonPath is $. There are two ways for JsonPath to obtain data:

  • Point representation: $ store.book[0].title
  • Bracket notation: $['store']['book'][0]['title ']

Examples of getting started are as follows:

public class Test {
    @Test
    public void hello() {
        String json = "{\"msg\":\"hello world\"}";
        String msg = JsonPath.read(json, "$.msg");
        System.out.println(msg);
    }
}    

grammar

The json string used for the test is as follows:

{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    },
    "expensive": 10
}

Operator

The operators supported by JsonPath are as follows:

operationexplain
$Query the root element. This starts all path expressions.
@The current node is processed by the filter predicate.
*Wildcard, use names or numbers anywhere if necessary.
..Deep scan. Names can be used anywhere necessary.
.<name>Points, representing child nodes
['<name>' (, '<name>')]Parentheses indicate children
[<number> (, <number>)]Array index or index, index starts from 0
[start:end]Array slicing operation
[?(<expression>)]Filter expressions. The expression must evaluate to a Boolean value.

Examples are as follows:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Get all author values under store and book in json
        List<String> authors = JsonPath.read(json, "$.store.book[*].author");
        System.out.println(authors);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
    }

    @Test
    public void test02() {
        // Get the values of all author s in all json
        List<String> authors = JsonPath.read(json, "$..author");
        System.out.println(authors);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
    }

    @Test
    public void test03() {
        // Get all the books and bicycles
        Object obj = JsonPath.read(json, "$.store.*");
        System.out.println(obj);// [[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95}]
    }

    @Test
    public void test04() {
        // Get the values of all price s under store in json
        List<Float> prices = JsonPath.read(json, "$.store..price");
        System.out.println(prices);// [8.95,12.99,8.99,22.99,19.95]
    }

    @Test
    public void test05() {
        // Get the third book of the book array in json. Note that the index starts from 0, but also note that it returns an array rather than a Map collection
        List<Map<String, Object>> book = JsonPath.read(json, "$..book[2]");
        System.out.println(book);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
    }

    @Test
    public void test06() {
        // Get the penultimate book, that is, support reverse indexing, starting from - 1
        List<Map<String, Object>> book = JsonPath.read(json, "$..book[-2]");
        System.out.println(book);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
    }

    @Test
    public void test07() {
        // Get the first two books, that is, the two books with indexes 0 and 1 in the array
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[0,1]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]
    }

    @Test
    public void test08() {
        // Get all books from index 0 (included) to index 2 (excluded), i.e. [0,2])
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[:2]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]
    }

    @Test
    public void test09() {
        // Get all books from index 1 (included) to index 2 (excluded), i.e. [1,2])
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[1:2]");
        System.out.println(books);// [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]
    }

    @Test
    public void test10() {
        // Gets the last two values of the book array in json
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[-2:]");
        System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test11() {
        // Get the interval value from the third to the last of the book array in json, including the last one
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[2:]");
        System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test12() {
        // Gets all the values of isbn contained in the book array in json
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[?(@.isbn)]");
        System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test13() {
        // Get all the values of price < 10 in the book array in json
        List<Map<String, Object>> books = JsonPath.read(json, "$..book[?(@.price < 10)]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
    }
}

function

JsonPath also supports some functions that can be called at the end of the path. The output of the function is the output of the path expression. The output of the function is determined by the function itself. The following table:

functiondescribeoutput
min()Provides the minimum value of a numeric arrayDouble
max()Provides the maximum value of a numeric arrayDouble
avg()Provides the average value of an array of numbersDouble
stddev()Provides the standard deviation value of a numeric arrayDouble
length()Provide the length of the arrayInteger
sum()Provides the sum of all native in the arrayDouble
keys()Provide all key namesSet
concat(X)Provides a concatinated version of the path output with a new itemlike input
append(X)Adds an entry to the output array of the path expressionlike input

Examples are as follows:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // How many books are there
        int length = JsonPath.read(json, "$..book.length()");
        System.out.println(length);
    }

    @Test
    public void test02() {
        // Get the minimum book price
        double min = JsonPath.read(json, "$..book..price.min()");
        System.out.println(min);// 8.95
    }

    @Test
    public void test03() {
        // Get the maximum book price
        double max = JsonPath.read(json, "$..book..price.max()");
        System.out.println(max);// 22.99
    }

    @Test
    public void test04() {
        // Get average book price
        double avg = JsonPath.read(json, "$..book..price.avg()");
        System.out.println(avg);// 13.48
    }

    @Test
    public void test05() {
        // It is a statistical concept to obtain the standard deviation of the book price
        Object obj = JsonPath.read(json, "$..book..price.stddev()");
        System.out.println(obj);
    }

    @Test
    public void test06() {
        // Get the total price of all books
        double sum = JsonPath.read(json, "$..book..price.sum()");
        System.out.println(sum);// 53.92
    }

    @Test
    public void test07() {
        // Get all the attribute key names of the second book
        Set<String> set = JsonPath.read(json, "$.store.book[2].keys()");
        System.out.println(set);// [category, author, title, isbn, price]
    }
}

Filter operator

A filter is a logical expression used to filter an array. A typical filter would be [? (@. Age > 18)], where @ represents the current item being processed. You can use the logical operators & & and | (representing and or, respectively) to create more complex filters. String literals must be enclosed in single or double quotation marks ([? (@. Color = ='Blue ')] or [? (@. color == "blue")])

Operatordescribe
==left equals right (note that 1 is not equal to '1')
!=Not equal to
<less than
<=Less than or equal to
>greater than
>=Greater than or equal to
=~Match regular expressions, such as [? (@. name =~ /foo.*?/i)]
inThe left exists on the right, such as [? (@. Size in ['s','m ']]]
ninThe left does not exist on the right
subsetofOn the left is a subset on the right, such as [? (@. sizes subsetof ['S','M','L ']]]
anyofThe set on the left intersects the set on the right, such as [? (@. sizes anyof ['M','L']]]
noneofThe left and right sets do not intersect with the right set, such as [? (@. sizes noneof ['M','L']]]
sizeThe length of the left (array or string) should match the value on the right
emptyThe left (array or string) is empty

Examples are as follows:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Find books with category equal to "fiction"
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category=='fiction')]");
        System.out.println(books);// [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test02() {
        // Find books whose category is not equal to "fiction"
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category!='fiction')]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95}]
    }

    @Test
    public void test03() {
        // Find books with price less than 10
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.price<10)]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
    }

    @Test
    public void test04() {
        // Find books with a price greater than 10
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.price>10)]");
        System.out.println(books);// [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test05() {
        // Use regular expressions to match books with "of the" in title
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.title =~ /.*of the.*/i)]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test06() {
        // Query the books whose category exists in ["reference","abc"]
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category in ['reference','abc'])]");
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95}]
    }

    @Test
    public void test07() {
        // Query category does not exist in books of ["reference","abc"]
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category nin ['reference','abc'])]");
        System.out.println(books);// [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
    }

    @Test
    public void test08() {
        // ['S','M '] is a subset of ['S','M','L '], so it is matched
        String json = "{\"sizes\":[\"S\",\"M\"]}";
        Object result = JsonPath.read(json, "$[?(@.sizes subsetof ['S','M','L'])]");
        System.out.println(result);// [{"sizes":["S","M"]}]
    }

    @Test
    public void test09() {
        // ['S','M '] intersects with ['M','L '], where'M' is the intersecting value
        String json = "{\"sizes\":[\"S\",\"M\"]}";
        Object result = JsonPath.read(json, "$[?(@.sizes anyof ['M','L'])]");
        System.out.println(result);// [{"sizes":["S","M"]}]
    }

    @Test
    public void test10() {
        // ['S','X '] does not intersect with ['M','L '], so it is matched
        String json = "{\"sizes\":[\"S\",\"X\"]}";
        Object result = JsonPath.read(json, "$[?(@.sizes noneof ['M','L'])]");
        System.out.println(result);
    }

    @Test
    public void test11() {
        // Matching books with a title of only 9 characters
        List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.title size 9)]");
        System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
    }
}

extend

The above syntax is enough for our daily use. Here are some extensions of JsonPath.

Reading documents

We all use jsonpath The read () method reads the content. If you only read it once, it is feasible. If you want to read it multiple times, it is not a good method, because this method needs to parse the entire json document every time, which consumes performance.

Therefore, if we need to read multiple paths, we can choose to parse the whole document first, and then parse the path to read the content.

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Read multiple paths by parsing multiple documents
        long start1 = System.currentTimeMillis();// You can see how long they take
        String author0 = JsonPath.read(json, "$.store.book[0].author");
        String author1 = JsonPath.read(json, "$.store.book[1].author");
        long end1 = System.currentTimeMillis();
        System.out.println(author0 + ", " + author1 + ", " + (end1 - start1));// Nigel Rees, Evelyn Waugh, 1218

        // Read multiple paths by parsing a document [recommended]
        long start2 = System.currentTimeMillis();
        Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
        String author2 = JsonPath.read(document, "$.store.book[0].author");
        String author3 = JsonPath.read(document, "$.store.book[1].author");
        long end2 = System.currentTimeMillis();
        System.out.println(author2 + ", " + author3 + ", " + (end2 - start2));// Nigel Rees, Evelyn Waugh, 1
    }
}

The core code is:

String json="...";
Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
String author2 = JsonPath.read(document, "$.store.book[0].author");

You can also use the following API, which makes the chain configuration flexible:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Resolve the path by reading the context
        ReadContext context = JsonPath.parse(json);
        List<String> authors = context.read("$.store.book..author");
        System.out.println(authors);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]

        // Or chain call
        List list = JsonPath
                .using(Configuration.defaultConfiguration())
                .parse(json)
                .read("$.store.book..author", List.class);
        System.out.println(list);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
    }
}

When to return

Return result type

When using JsonPath, you should know exactly what type the result of the path is. JsonPath will try to convert to the expected type, such as:

// Throw Java Lang.classcastexception exception
List<String> list = JsonPath.parse(json).read("$.store.book[0].author")// In fact, the returned string is a string, so it is not appropriate to use List to receive, so type conversion cannot be enforced

// normal
String author = JsonPath.parse(json).read("$.store.book[0].author")

When evaluating a path, you need to understand the concept of when the path is determined. The path is indeterminate if it contains the following:

  • ..: deep scan operation
  • ? (< expression >): expression
  • [< number >, < number > (, < number >)]: multiple array indexes

The total number of uncertain paths returns a List that can be received by the List.

Return result mapping

  • Simple object mapping
    By default, the MappingProvider SPI provides a simple object mapper. This allows you to specify the required return type, and the MappingProvider will attempt to perform the mapping. To convert a Long timestamp to a Date:
public class JsonPathTest {

    @Test
    public void test01() {
        String json = "{\"timestamp\":1641519588137}";
        Date date = JsonPath.parse(json).read("$.timestamp", Date.class);
        System.out.println(date);// Fri Jan 07 09:39:48 CST 2022
    }
}
  • POJO object mapping
    If it is a simple entity class mapping, such as Book, it can be as follows:
public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        Book book = JsonPath.parse(json).read("$.store.book[0]", Book.class);
        System.out.println(book);// Book{category='reference', author='Nigel Rees', title='Sayings of the Century', isbin='null', price=8.95}
    }
}

class Book {
    private String category;
    private String author;
    private String title;
    private String isbn;
    private float price;

    public Book() {
    }

    public Book(String category, String author, String title, String isbn, float price) {
        this.category = category;
        this.author = author;
        this.title = title;
        this.isbn = isbn;
        this.price = price;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "category='" + category + '\'' +
                ", author='" + author + '\'' +
                ", title='" + title + '\'' +
                ", isbin='" + isbn + '\'' +
                ", price=" + price +
                '}';
    }
}

However, in more complex cases, such as list < book >, you can consider configuring JsonPath to use JacksonMappingProvider or GsonMappingProvider, so that the output of JsonPath can be directly mapped to POJO s.

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // 1. Default configuration
        Configuration.setDefaults(new Configuration.Defaults() {
            // Note that GsonJsonProvider and GsonMappingProvider are created here, but the Gson package needs to be imported
            // You can also use jackson jsonprovider and jackson mapping provider, and you also need to import jackson package
            private final JsonProvider jsonProvider = new GsonJsonProvider();
            private final MappingProvider mappingProvider = new GsonMappingProvider();

            @Override
            public JsonProvider jsonProvider() {
                return jsonProvider;
            }

            @Override
            public Set<Option> options() {
                return EnumSet.noneOf(Option.class);
            }

            @Override
            public MappingProvider mappingProvider() {
                return mappingProvider;
            }
        });
        // 2. Set generics. List < book > generics cannot be directly passed in the read() method, so you need to set generics in typeref < >
        TypeRef<List<Book>> typeRef = new TypeRef<List<Book>>() {};
        // 3. Call the read() method to pass in the path expression and generic type and read the data
        List<Book> books = JsonPath.parse(json).read("$.store.book.*", typeRef);
        // 4. Print results
        for (Book book : books) {
            System.out.println(book);
        }
        // Book{category='reference', author='Nigel Rees', title='Sayings of the Century', isbin='null', price=8.95}
        // Book{category='fiction', author='Evelyn Waugh', title='Sword of Honour', isbin='null', price=12.99}
        // Book{category='fiction', author='Herman Melville', title='Moby Dick', isbin='0-553-21311-3', price=8.99}
        // Book{category='fiction', author='J. R. R. Tolkien', title='The Lord of the Rings', isbin='0-395-19395-8', price=22.99}
    }

}

class Book {
    private String category;
    private String author;
    private String title;
    private String isbn;
    private float price;

    public Book() {
    }

    public Book(String category, String author, String title, String isbn, float price) {
        this.category = category;
        this.author = author;
        this.title = title;
        this.isbn = isbn;
        this.price = price;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "category='" + category + '\'' +
                ", author='" + author + '\'' +
                ", title='" + title + '\'' +
                ", isbin='" + isbn + '\'' +
                ", price=" + price +
                '}';
    }
}

predicate

There are three different ways to create filter predicates in JsonPath.

Inline predicate

Inline predicates are predicates defined directly in the path. For example:

List<Map<String, Object>> books =  JsonPath.parse(json).read("$.store.book[?(@.price < 10)]");

Where [? (@. Price < 10)] is an inline predicate, which requires filtering books whose price is less than 10.

You can also use $$and |, that is, multiple filter conditions show the relationship between "and" and "or". For example, [? (@. Price < 10 & &@. Category = ='fiction ')] indicates books whose filter price is less than 10 and classified as fiction (multiple conditions are met at the same time) [? (@. Category = = 'reference' | @. Price > 10)] means filtering books classified as reference or with a price greater than 10 (as long as any condition is met).

One more! It means "not", for example [? (! (@. Price < 10 & &@. Category = ='fiction ')] means books whose price is neither less than 10 nor fiction.

Filter predicate

Predicates can be built using the Filter API, as follows:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Declare predicate filter
        Filter bookFilter = Filter.filter(
                // It is similar to the condition in SQL statement, that is, category = ='function '& & price < = 10
                Criteria.where("category").is("fiction").and("price").lte(10)
        );
        // Call the read method to pass in path expressions and predicate filters
        List<Map<String, Object>> books = JsonPath.parse(json).read("$.store.book[?]", bookFilter);
        System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
    }

}

be careful:

  • Path expression $ store.book[?] Placeholder used in? To represent the filter in the path.
  • When multiple filters are provided, they are applied in the order in which the number of placeholders matches the number of filters provided.
  • You can operate [?,?] in one filter Multiple predicate placeholders are specified in, both of which must match.
  • Filters can be used or(),. and(),. exists() to represent "or", "and" and "not".

Custom predicate

You can also implement your own predicates for more complex filtering.

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Custom predicate
        Predicate booksPredicate = new Predicate() {
            @Override
            public boolean apply(PredicateContext context) {
                // The author's name is required to be exactly 10 characters
                return context.item(Map.class).get("author").toString().length() == 10;
            }
        };

        // Call the read method to pass in path expressions and custom predicates
        List<Map<String, Object>> books = JsonPath.parse(json).read("$.store.book[?]", List.class, booksPredicate);
        System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95}]
    }
}

Path vs value

By default, JsonPath is a return value, but it can also be required to return the full path of the matching element. As follows:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // Configure and return the path
        Configuration conf = Configuration.builder().options(Option.AS_PATH_LIST).build();

        // Incoming configuration read path
        List<String> pathList = JsonPath.using(conf).parse(json).read("$..author");
        System.out.println(pathList);// ["$['store']['book'][0]['author']","$['store']['book'][1]['author']","$['store']['book'][2]['author']","$['store']['book'][3]['author']"]
    }
}

Adjust configuration

When creating a configuration with options, there are several option flags that can change the default behavior.

DEFAULT_PATH_LEAF_TO_NULL

This option causes JsonPath to return null for the missing leaf, as shown in the following json:

[
   {
      "name" : "john",
      "gender" : "male"
   },
   {
      "name" : "ben"
   }
]

Get the gender in the second object. If the default configuration item is followed, an exception will be thrown. We hope it can return null when it does not exist, so we can set DEFAULT_PATH_LEAF_TO_NULL.

public class JsonPathTest {
    @Test
    public void test01() {
        String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";

        Configuration conf = Configuration.defaultConfiguration();

        // normal
        String gender0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");
        // Exception pathnotfoundexception throw
        String gender1 = JsonPath.using(conf).parse(json).read("$[1]['gender']");// com.jayway.jsonpath.PathNotFoundException: No results for path: $[1]['gender']
        System.out.println(gender0 + ", " + gender1);
    }

    @Test
    public void test02() {
        String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";

        Configuration conf2 = Configuration.defaultConfiguration().addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

        // normal
        String gender0 = JsonPath.using(conf2).parse(json).read("$[0]['gender']");
        // Normal (return null)
        String gender1 = JsonPath.using(conf2).parse(json).read("$[1]['gender']");
        System.out.println(gender0 + ", " + gender1);// male, null
    }
}

ALWAYS_RETURN_LIST

This option configures JsonPath to return a list, even if the path is determined.

For example, the result of $[0]['gender '] is a String. We can use String to receive it, but if we want to use list < String > to receive this single String, we need to configure ALWAYS_RETURN_LIST options.

public class JsonPathTest {

    @Test
    public void test01() {
        String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";

        Configuration conf = Configuration.defaultConfiguration();

        List<String> genders0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");// java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
        System.out.println(genders0);
    }

    @Test
    public void test02() {
        String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";

        Configuration conf = Configuration.defaultConfiguration().addOptions(Option.ALWAYS_RETURN_LIST);// Set always return list

        List<String> genders0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");
        System.out.println(genders0);// ["male"]
    }
}

SUPPRESS_EXCEPTIONS

This option ensures that exceptions are not propagated from the path evaluation. Follow these simple rules:

  • If the option ALWAYS_RETURN_LIST exists, an empty list will be returned
  • If the option ALWAYS_RETURN_LIST does not exist and returns null

JsonProvider SPI

JsonPath comes with five different jsonproviders:

  • JsonSmartJsonProvider (default)
  • JacksonJsonProvider
  • JacksonJsonNodeJsonProvider
  • GsonJsonProvider
  • JsonOrgJsonProvider
  • JakartaJsonProvider

The demonstrated configuration defaults can only be changed when the application is initialized. Strongly opposed to making changes at run time, especially in multithreaded applications.

Configuration.setDefaults(new Configuration.Defaults() {

    private final JsonProvider jsonProvider = new JacksonJsonProvider();
    private final MappingProvider mappingProvider = new JacksonMappingProvider();
      
    @Override
    public JsonProvider jsonProvider() {
        return jsonProvider;
    }

    @Override
    public MappingProvider mappingProvider() {
        return mappingProvider;
    }
    
    @Override
    public Set<Option> options() {
        return EnumSet.noneOf(Option.class);
    }
});

Note: Jackson jsonprovider requires com fasterxml. jackson. Core: Jackson databind: 2.4.5, GsonJsonProvider needs to use COM. Com on your classpath google. code. Gson: gson: 2.3.1, that is, you need to import relevant jar packages to use.

Using JacksonJsonProvider or GsonJsonProvider, you can directly map the output of JsonPath to the entity class, as shown in the following example:

public class JsonPathTest {
    private String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void test01() {
        // 1. Default configuration
        Configuration.setDefaults(new Configuration.Defaults() {
            // Note that GsonJsonProvider and GsonMappingProvider are created here, but the Gson package needs to be imported
            // You can also use jackson jsonprovider and jackson mapping provider, and you also need to import jackson package
            private final JsonProvider jsonProvider = new GsonJsonProvider();
            private final MappingProvider mappingProvider = new GsonMappingProvider();

            @Override
            public JsonProvider jsonProvider() {
                return jsonProvider;
            }

            @Override
            public Set<Option> options() {
                return EnumSet.noneOf(Option.class);
            }

            @Override
            public MappingProvider mappingProvider() {
                return mappingProvider;
            }
        });
        // 2. Set generics. List < book > generics cannot be directly passed in the read() method, so you need to set generics in typeref < >
        TypeRef<List<Book>> typeRef = new TypeRef<List<Book>>() {};
        // 3. Call the read() method to pass in the path expression and generic type and read the data
        List<Book> books = JsonPath.parse(json).read("$.store.book.*", typeRef);
        // 4. Print results
        for (Book book : books) {
            System.out.println(book);
        }
        // Book{category='reference', author='Nigel Rees', title='Sayings of the Century', isbin='null', price=8.95}
        // Book{category='fiction', author='Evelyn Waugh', title='Sword of Honour', isbin='null', price=12.99}
        // Book{category='fiction', author='Herman Melville', title='Moby Dick', isbin='0-553-21311-3', price=8.99}
        // Book{category='fiction', author='J. R. R. Tolkien', title='The Lord of the Rings', isbin='0-395-19395-8', price=22.99}
    }

}

class Book {
    private String category;
    private String author;
    private String title;
    private String isbn;
    private float price;

    public Book() {
    }

    public Book(String category, String author, String title, String isbn, float price) {
        this.category = category;
        this.author = author;
        this.title = title;
        this.isbn = isbn;
        this.price = price;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "category='" + category + '\'' +
                ", author='" + author + '\'' +
                ", title='" + title + '\'' +
                ", isbin='" + isbn + '\'' +
                ", price=" + price +
                '}';
    }
}

other

Encapsulation tool class

For using JsonPath to extract the contents of json strings and then encapsulate them into entity classes, you can do some simple encapsulation:

package json;

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author lcl100
 * @desc JsonPath Tool class
 * @date 2022-01-10
 */
public class JsonPathUtil {

    /**
     * JsonPath to configure
     */
    private final static Configuration configuration = Configuration.defaultConfiguration().addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

    /**
     * Read the content in json according to the path expression
     *
     * @param json json string to be read
     * @param path JsonPath Path expression
     * @return Read results
     */
    private static Object readPath(String json, String path) {
        Object result = null;
        try {
            result = JsonPath.using(configuration).parse(json).read(path);
        } catch (Exception ignored) {

        }
        return result;
    }

    /**
     * Extract the corresponding content in json according to the json template string, and then fill it into the corresponding mapping field in the class to extract the entity class
     *
     * @param json     json string to be extracted
     * @param jsonPath json The template string stores the path relationship between the entity class attribute name and the corresponding content in json
     * @param clazz    Entity class to be mapped
     * @param <T>      Entity class generics
     * @return An entity class object that is extracted from the json string and assigned a value
     * @throws InstantiationException Exception creating instance object
     * @throws IllegalAccessException Field access permission exception
     */
    public static <T> T getJsonObject(String json, String jsonPath, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        // Extract all key value pairs in the json string jsonPath
        Map<String, Map<String, String>> arrayMap = new HashMap<>();
        Map<String, String> objectMap = new HashMap<>();
        // Determine whether the template string is a json object or a json array
        jsonPath = jsonPath.trim();
        char firstChar = jsonPath.charAt(0);
        boolean isArray = false;
        if (firstChar == '[') {
            isArray = true;
            // Read all json objects in the json array. Each json object is a Map collection, and then put it into the List
            List<Map<String, String>> mapList = (List<Map<String, String>>) readPath(jsonPath, "$");
            for (Map<String, String> map : mapList) {
                arrayMap.put(map.getOrDefault("NAME", null), map);
            }
        } else if (firstChar == '{') {
            isArray = false;
            // Read all key values into a Map set
            objectMap = (Map<String, String>) readPath(jsonPath, "$");
        }

        // Get all fields of the class and assign values in turn
        T t = clazz.newInstance();
        Class<?> tClass = t.getClass();
        Field[] fields = tClass.getDeclaredFields();
        for (Field field : fields) {
            // Extract the corresponding path expression according to the field name, and then extract the value in json according to the path expression
            String name = field.getName();
            // Due to different template strings, the way of extracting paths is different
            String path = isArray ? (arrayMap.getOrDefault(name, null) != null ? arrayMap.get(name).get("PATH") : null) : objectMap.getOrDefault(name, null);
            // Read value according to path
            Object value = readPath(json, path);
            // If you are using a template string with a regular expression, additional processing is required
            if (isArray) {
                // Regular extraction
                Matcher matcher = Pattern.compile(arrayMap.getOrDefault(name, null).getOrDefault("REGEXP", null)).matcher(String.valueOf(value));
                if (matcher.find()) {
                    value = matcher.group(1);
                }
            }
            // Assign values to fields
            setField(field, t, value);
        }

        return t;
    }

    /**
     * Extract the corresponding content in json according to the json template string, and then fill it into the corresponding mapping field in the class to extract the entity class collection
     *
     * @param json     json string to be extracted
     * @param jsonPath json The template string stores the path relationship between the entity class attribute name and the corresponding content in json
     * @param clazz    Entity class to be mapped
     * @param <T>      Entity class generics
     * @return Set of assigned entity classes
     * @throws InstantiationException Exception creating instance object
     * @throws IllegalAccessException Field access permission exception
     */
    public static <T> List<T> getJsonList(String json, String jsonPath, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        List<T> list = new ArrayList<>();
        Map<String, Map<String, String>> arrayMap = new HashMap<>();
        Map<String, String> objectMap = new HashMap<>();
        // Determine the mode of template string according to whether there is "DATA"
        boolean isArray = jsonPath.contains("DATA");
        if (isArray) {// This pattern uses regular expressions
            // It is directly an array containing multiple json objects, that is, multiple Map collections
            List<Map<String, String>> mapList = (List<Map<String, String>>) readPath(jsonPath, "$.DATA");
            for (int i = 0; i < mapList.size(); i++) {
                Map<String, String> map = mapList.get(i);
                String name = map.get("NAME");
                String path = map.get("PATH");
                if (name != null && !"".equals(name.trim()) && path != null && !"".equals(path.trim())) {
                    arrayMap.put(name, map);
                }
            }
        } else {// The pattern does not use regular expressions
            // It is directly a Map collection, including all key value pairs
            objectMap = (Map<String, String>) readPath(jsonPath, "$");
        }

        // Calculate root_ The length of the array represented by the path represented by list in the json string
        String rootPath = (String) readPath(jsonPath, "$.ROOT_LIST");
        int length = (int) readPath(json, rootPath + ".length()");
        for (int j = 0; j < length; j++) {
            // Create entity class object
            T t = clazz.newInstance();
            Class<?> tClass = t.getClass();
            // Get all declared fields
            Field[] fields = tClass.getDeclaredFields();
            for (Field field : fields) {
                // Field name
                String fieldName = field.getName();
                // The value to be assigned to the field
                Object value;
                if (isArray) {
                    // Filter out fields that do not need to be extracted
                    if (arrayMap.getOrDefault(fieldName, null) == null) {
                        continue;
                    }
                    // Reads the value of the specified path from json
                    value = readPath(json, rootPath + "[" + j + "]" + arrayMap.getOrDefault(fieldName, null).get("PATH"));
                    // Regular processing is required
                    Matcher matcher = Pattern.compile(arrayMap.getOrDefault(fieldName, null).getOrDefault("REGEXP", null)).matcher(String.valueOf(value));
                    if (matcher.find()) {
                        value = matcher.group(1);
                    }
                } else {
                    // Filter out fields that do not need to be extracted
                    if (objectMap.getOrDefault(fieldName, null) == null) {
                        continue;
                    }
                    // Reads the value of the specified path from json
                    value = readPath(json, rootPath + "[" + j + "]" + objectMap.getOrDefault(fieldName, null));
                }
                // Assign values to fields
                setField(field, t, value);
            }
            list.add(t);
        }
        return list;
    }

    /**
     * Assign values to the fields on the instance object according to the field type
     *
     * @param field Fields to be assigned
     * @param t     Instance object
     * @param value Value to be assigned
     * @throws IllegalAccessException Field access permission exception
     */
    private static void setField(Field field, Object t, Object value) throws IllegalAccessException {
        String typeName = field.getType().getTypeName();
        field.setAccessible(true);
        if (typeName.endsWith("String")) {
            field.set(t, String.valueOf(value));
        } else if (typeName.endsWith("byte")) {
            byte result = 0;
            try {
                result = Byte.parseByte(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Byte")) {
            Byte result = null;
            try {
                result = Byte.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("short")) {
            short result = 0;
            try {
                result = Short.parseShort(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Short")) {
            Short result = null;
            try {
                result = Short.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("int")) {
            int result = 0;
            try {
                result = Integer.parseInt(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Integer")) {
            Integer result = null;
            try {
                result = Integer.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("long")) {
            long result = 0L;
            try {
                result = Long.parseLong(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Long")) {
            Long result = null;
            try {
                result = Long.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("float")) {
            float result = 0F;
            try {
                result = Float.parseFloat(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Float")) {
            Float result = null;
            try {
                result = Float.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("double")) {
            double result = 0;
            try {
                result = Double.parseDouble(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Double")) {
            Double result = null;
            try {
                result = Double.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("boolean")) {
            boolean result = false;
            try {
                result = Boolean.parseBoolean(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Boolean")) {
            Boolean result = null;
            try {
                result = Boolean.valueOf(value.toString());
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("char")) {
            char result = '\u0000';
            try {
                result = value.toString().charAt(0);
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Character")) {
            Character result = null;
            try {
                result = value.toString().charAt(0);
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else if (typeName.endsWith("Date")) {
            Date result = null;
            // Only timestamp dates can be processed temporarily
            try {
                Matcher timestampMatcher = Pattern.compile("1[\\d]{9}").matcher(value.toString());
                if (timestampMatcher.find()) {
                    result = new Date(Long.parseLong(value.toString()));
                }
            } catch (Exception ignored) {

            }
            field.set(t, result);
        } else {
            System.out.println("Field type that cannot be converted: " + typeName);
        }
    }
}

The test classes are as follows:

public class JsonPathUtilTest {
    private final String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";

    @Test
    public void testGetJsonObject() throws InstantiationException, IllegalAccessException {
        // Note that in the jsonPath template expression, the key name is the attribute name in the entity class; The key value is the full path in the json string

        // Template string of the first form
        String jsonPath1 = "{\n" +
                "  \"category\": \"$.store.book[0].category\",\n" +
                "  \"author\": \"$.store.book[0].author\",\n" +
                "  \"title\": \"$.store.book[0].title\",\n" +
                "  \"isbn\": \"$.store.book[0].isbn\",\n" +
                "  \"price\": \"$.store.book[0].price\"\n" +
                "}";
        Book book1 = JsonPathUtil.getJsonObject(json, jsonPath1, Book.class);
        System.out.println(book1);

        // Template string of the second form
        String jsonPath2 = "[\n" +
                "  {\n" +
                "    \"NAME\": \"category\",\n" +
                "    \"PATH\": \"$.store.book[0].category\",\n" +
                "    \"REGEXP\": \"(.*)\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"NAME\": \"author\",\n" +
                "    \"PATH\": \"$.store.book[0].author\",\n" +
                "    \"REGEXP\": \"(.*)\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"NAME\": \"title\",\n" +
                "    \"PATH\": \"$.store.book[0].title\",\n" +
                "    \"REGEXP\": \"(.*)\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"NAME\": \"isbn\",\n" +
                "    \"PATH\": \"$.store.book[0].isbn\",\n" +
                "    \"REGEXP\": \"(.*)\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"NAME\": \"price\",\n" +
                "    \"PATH\": \"$.store.book[0].price\",\n" +
                "    \"REGEXP\": \"(\\\\d+\\\\.\\\\d+)\"\n" +
                "  }\n" +
                "]";
        Book book2 = JsonPathUtil.getJsonObject(json, jsonPath1, Book.class);
        System.out.println(book2);
    }

    @Test
    public void testGetJsonList() throws InstantiationException, IllegalAccessException {
        // Note, ROOT_LIST is a required field, indicating the root path of the list
        // Note that in the jsonPath template expression, the key name is the attribute name in the entity class; The key value is the relative path in the json string (relative to the root path of the list)

        // Template string of the first form
        String jsonPath1 = "{\n" +
                "  \"ROOT_LIST\": \"$.store.book\",\n" +
                "  \"category\": \".category\",\n" +
                "  \"author\": \".author\",\n" +
                "  \"title\": \".title\",\n" +
                "  \"isbn\": \".isbn\",\n" +
                "  \"price\": \".price\"\n" +
                "}";
        List<Book> bookList1 = JsonPathUtil.getJsonList(json, jsonPath1, Book.class);
        for (Book book : bookList1) {
            System.out.println(book);
        }

        // Template string of the second form
        String jsonPath2 = "{\n" +
                "  \"ROOT_LIST\": \"$.store.book\",\n" +
                "  \"DATA\": [\n" +
                "    {\n" +
                "      \"NAME\": \"category\",\n" +
                "      \"PATH\": \".category\",\n" +
                "      \"REGEXP\": \"(.*)\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"NAME\": \"author\",\n" +
                "      \"PATH\": \".author\",\n" +
                "      \"REGEXP\": \"(.*)\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"NAME\": \"title\",\n" +
                "      \"PATH\": \".title\",\n" +
                "      \"REGEXP\": \"(.*)\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"NAME\": \"isbn\",\n" +
                "      \"PATH\": \".isbn\",\n" +
                "      \"REGEXP\": \"(.*)\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"NAME\": \"price\",\n" +
                "      \"PATH\": \".price\",\n" +
                "      \"REGEXP\": \"(\\\\d+\\\\.\\\\d+)\"\n" +
                "    }\n" +
                "  ]\n" +
                "}";
        List<Book> bookList2 = JsonPathUtil.getJsonList(json, jsonPath2, Book.class);
        for (Book book : bookList2) {
            System.out.println(book);
        }
    }
}

Please refer to: GitHub documentation.

Online JsonPath test

Website address: Online JSONPath test

It can help us quickly judge whether jsonpath is written correctly and whether the result is what we expect, without writing code to verify.

reference material

Topics: Java JSON