JSON 문서를 읽기 위한 Java DSL입니다.
Jayway JsonPath는 Stefan Goessner JsonPath 구현의 Java 포트입니다.
JsonPath는 Central Maven Repository에서 사용할 수 있습니다. Maven 사용자는 이것을 POM에 추가합니다.
< dependency >
< groupId >com.jayway.jsonpath</ groupId >
< artifactId >json-path</ artifactId >
< version >2.9.0</ version >
</ dependency >
도움이 필요하면 Stack Overflow에 질문하세요. 질문에 'jsonpath'와 'java'를 태그하세요.
JsonPath 표현식은 XPath 표현식이 XML 문서와 함께 사용되는 것과 동일한 방식으로 항상 JSON 구조를 참조합니다. JsonPath의 "루트 멤버 개체"는 개체인지 배열인지에 관계없이 항상 $
로 참조됩니다.
JsonPath 표현식은 점 표기법을 사용할 수 있습니다.
$.store.book[0].title
또는 대괄호 표기법
$['store']['book'][0]['title']
연산자 | 설명 |
---|---|
$ | 쿼리할 루트 요소입니다. 그러면 모든 경로 표현식이 시작됩니다. |
@ | 필터 조건자에 의해 처리되고 있는 현재 노드입니다. |
* | 와일드카드. 이름이나 숫자가 필요한 곳이면 어디든 사용할 수 있습니다. |
.. | 정밀 스캔. 이름이 필요한 곳이면 어디든 사용할 수 있습니다. |
.<name> | 점으로 표기된 아이 |
['<name>' (, '<name>')] | 괄호로 표시된 어린이 또는 어린이 |
[<number> (, <number>)] | 배열 인덱스 또는 인덱스 |
[start:end] | 배열 슬라이스 연산자 |
[?(<expression>)] | 필터 표현. 표현식은 부울 값으로 평가되어야 합니다. |
함수는 경로 끝에서 호출될 수 있습니다. 함수에 대한 입력은 경로 표현식의 출력입니다. 함수 출력은 함수 자체에 의해 결정됩니다.
기능 | 설명 | 출력 유형 |
---|---|---|
min() | 숫자 배열의 최소값을 제공합니다. | 더블 |
max() | 숫자 배열의 최대값을 제공합니다. | 더블 |
avg() | 숫자 배열의 평균값을 제공합니다. | 더블 |
stddev() | 숫자 배열의 표준 편차 값을 제공합니다. | 더블 |
length() | 배열의 길이를 제공합니다. | 정수 |
sum() | 숫자 배열의 합계 값을 제공합니다. | 더블 |
keys() | 속성 키 제공(터미널 물결표 ~ 에 대한 대안) | Set<E> |
concat(X) | 새 항목과 연결된 경로 출력 버전을 제공합니다. | 입력과 같은 |
append(X) | json 경로 출력 배열에 항목 추가 | 입력과 같은 |
first() | 배열의 첫 번째 항목을 제공합니다. | 어레이에 따라 다름 |
last() | 배열의 마지막 항목을 제공합니다. | 어레이에 따라 다름 |
index(X) | 인덱스 배열의 항목 제공: X, X가 음수이면 뒤에서부터 가져옴 | 어레이에 따라 다름 |
필터는 배열을 필터링하는 데 사용되는 논리식입니다. 일반적인 필터는 [?(@.age > 18)]
입니다. 여기서 @
현재 처리 중인 항목을 나타냅니다. 논리 연산자 &&
및 ||
를 사용하여 더 복잡한 필터를 만들 수 있습니다. . 문자열 리터럴은 작은따옴표나 큰따옴표( [?(@.color == 'blue')]
또는 [?(@.color == "blue")]
)로 묶어야 합니다.
연산자 | 설명 |
---|---|
== | 왼쪽은 오른쪽과 같습니다(1은 '1'과 같지 않음). |
!= | 왼쪽은 오른쪽과 같지 않다 |
< | 왼쪽이 오른쪽보다 작다 |
<= | 왼쪽이 오른쪽보다 작거나 같음 |
> | 왼쪽이 오른쪽보다 크다 |
>= | 왼쪽이 오른쪽보다 크거나 같음 |
=~ | 왼쪽은 정규식 [?(@.name =~ /foo.*?/i)]과 일치합니다. |
in | 왼쪽이 오른쪽에 존재함 [?(@.size in ['S', 'M'])] |
nin | 왼쪽은 오른쪽에 존재하지 않습니다 |
subsetof | 왼쪽은 오른쪽 [?(@.sizes subsetof ['S', 'M', 'L'])]의 하위 집합입니다. |
anyof | 왼쪽에는 오른쪽과 교차하는 부분이 있습니다 [?(@.sizes anyof ['M', 'L'])] |
noneof | 왼쪽에는 오른쪽과 교차하는 부분이 없습니다. [?(@.sizes noneof ['M', 'L'])] |
size | 왼쪽(배열 또는 문자열)의 크기가 오른쪽과 일치해야 합니다. |
empty | 왼쪽(배열 또는 문자열)은 비어 있어야 합니다. |
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
}
JsonPath | 결과 |
---|---|
$.store.book[*].author | 모든 책의 저자 |
$..author | 모든 저자 |
$.store.* | 책, 자전거 등 모든 것 |
$.store..price | 모든 것의 가격 |
$..book[2] | 세 번째 책 |
$..book[-2] | 마지막에서 두 번째 책 |
$..book[0,1] | 처음 두 권의 책 |
$..book[:2] | 인덱스 0(포함)부터 인덱스 2(제외)까지의 모든 도서 |
$..book[1:2] | 색인 1(포함)부터 색인 2(제외)까지의 모든 도서 |
$..book[-2:] | 마지막 두 권의 책 |
$..book[2:] | 색인 2(포함)부터 마지막까지의 모든 도서 |
$..book[?(@.isbn)] | ISBN 번호가 있는 모든 도서 |
$.store.book[?(@.price < 10)] | 매장의 모든 책은 10보다 저렴합니다. |
$..book[?(@.price <= $['expensive'])] | "비싸지 않은" 매장의 모든 책 |
$..book[?(@.author =~ /.*REES/i)] | 정규식과 일치하는 모든 도서(대소문자 무시) |
$..* | 나에게 모든 것을 줘 |
$..book.length() | 책의 수 |
JsonPath를 사용하는 가장 간단하고 직접적인 방법은 정적 읽기 API를 사용하는 것입니다.
String json = "..." ;
List < String > authors = JsonPath . read ( json , "$.store.book[*].author" );
한 번만 읽고 싶다면 괜찮습니다. 다른 경로도 읽어야 하는 경우에는 JsonPath.read(...)를 호출할 때마다 문서가 구문 분석되므로 이 방법은 적합하지 않습니다. 문제를 방지하려면 먼저 json을 구문 분석할 수 있습니다.
String json = "..." ;
Object document = Configuration . defaultConfiguration (). jsonProvider (). parse ( json );
String author0 = JsonPath . read ( document , "$.store.book[0].author" );
String author1 = JsonPath . read ( document , "$.store.book[1].author" );
JsonPath는 또한 유창한 API를 제공합니다. 이것은 또한 가장 유연한 것입니다.
String json = "..." ;
ReadContext ctx = JsonPath . parse ( json );
List < String > authorsOfBooksWithISBN = ctx . read ( "$.store.book[?(@.isbn)].author" );
List < Map < String , Object >> expensiveBooks = JsonPath
. using ( configuration )
. parse ( json )
. read ( "$.store.book[?(@.price > 10)]" , List . class );
Java에서 JsonPath를 사용할 때 결과에서 어떤 유형을 기대하는지 아는 것이 중요합니다. JsonPath는 호출자가 예상하는 유형으로 결과를 자동으로 캐스팅하려고 시도합니다.
//Will throw an java.lang.ClassCastException
List < String > list = JsonPath . parse ( json ). read ( "$.store.book[0].author" );
//Works fine
String author = JsonPath . parse ( json ). read ( "$.store.book[0].author" );
경로를 평가할 때 경로가 언제 definite
되는지에 대한 개념을 이해해야 합니다. 다음이 포함된 경우 경로는 indefinite
입니다.
..
- 딥 스캔 연산자?(<expression>)
- 표현식[<number>, <number> (, <number>)]
- 다중 배열 인덱스 Indefinite
경로는 항상 목록(현재 JsonProvider로 표시됨)을 반환합니다.
기본적으로 MappingProvider SPI는 간단한 객체 매퍼를 제공합니다. 이를 통해 원하는 반환 유형을 지정할 수 있으며 MappingProvider가 매핑을 수행하려고 시도합니다. 아래 예에서는 Long
과 Date
간의 매핑을 보여줍니다.
String json = "{ " date_as_long " : 1411455611975}" ;
Date date = JsonPath . parse ( json ). read ( "$['date_as_long']" , Date . class );
JacksonMappingProvider
, GsonMappingProvider
또는 JakartaJsonProvider
사용하도록 JsonPath를 구성하면 JsonPath 출력을 POJO에 직접 매핑할 수도 있습니다.
Book book = JsonPath . parse ( json ). read ( "$.store.book[0]" , Book . class );
전체 제네릭 유형 정보를 얻으려면 TypeRef를 사용하십시오.
TypeRef < List < String >> typeRef = new TypeRef < List < String >>() {};
List < String > titles = JsonPath . parse ( JSON_DOCUMENT ). read ( "$.store.book[*].title" , typeRef );
JsonPath에서 필터 조건자를 만드는 방법에는 세 가지가 있습니다.
인라인 조건자는 경로에 정의된 조건자입니다.
List < Map < String , Object >> books = JsonPath . parse ( json )
. read ( "$.store.book[?(@.price < 10)]" );
&&
및 ||
사용할 수 있습니다. 여러 술어를 결합하려면 [?(@.price < 10 && @.category == 'fiction')]
, [?(@.category == 'reference' || @.price > 10)]
.
당신은 사용할 수 있습니다 !
술어를 부정하려면 [?(!(@.price < 10 && @.category == 'fiction'))]
.
아래와 같이 필터 API를 사용하여 조건자를 작성할 수 있습니다.
import static com . jayway . jsonpath . JsonPath . parse ;
import static com . jayway . jsonpath . Criteria . where ;
import static com . jayway . jsonpath . Filter . filter ;
...
...
Filter cheapFictionFilter = filter (
where ( "category" ). is ( "fiction" ). and ( "price" ). lte ( 10D )
);
List < Map < String , Object >> books =
parse ( json ). read ( "$.store.book[?]" , cheapFictionFilter );
자리 표시자를 확인하세요 ?
경로의 필터에 대해. 여러 필터가 제공되면 자리 표시자 수가 제공된 필터 수와 일치해야 하는 순서대로 적용됩니다. 하나의 필터 작업 [?, ?]
에서 여러 조건자 자리 표시자를 지정할 수 있으며 두 조건자가 모두 일치해야 합니다.
필터는 'OR' 및 'AND'와 결합될 수도 있습니다.
Filter fooOrBar = filter (
where ( "foo" ). exists ( true )). or ( where ( "bar" ). exists ( true )
);
Filter fooAndBar = filter (
where ( "foo" ). exists ( true )). and ( where ( "bar" ). exists ( true )
);
세 번째 옵션은 자신만의 조건자를 구현하는 것입니다.
Predicate booksWithISBN = new Predicate () {
@ Override
public boolean apply ( PredicateContext ctx ) {
return ctx . item ( Map . class ). containsKey ( "isbn" );
}
};
List < Map < String , Object >> books =
reader . read ( "$.store.book[?].isbn" , List . class , booksWithISBN );
Goessner 구현에서 JsonPath는 Path
또는 Value
반환할 수 있습니다. Value
기본값이며 위의 모든 예제가 반환하는 값입니다. 쿼리가 실행되는 요소의 경로가 있는 경우 옵션을 사용하여 이를 달성할 수 있습니다.
Configuration conf = Configuration . builder ()
. options ( Option . AS_PATH_LIST ). build ();
List < String > pathList = using ( conf ). parse ( json ). read ( "$..author" );
assertThat ( pathList ). containsExactly (
"$['store']['book'][0]['author']" ,
"$['store']['book'][1]['author']" ,
"$['store']['book'][2]['author']" ,
"$['store']['book'][3]['author']" );
라이브러리는 값을 설정할 수 있는 가능성을 제공합니다.
String newJson = JsonPath . parse ( json ). set ( "$['store']['book'][0]['author']" , "Paul" ). jsonString ();
구성을 생성할 때 기본 동작을 변경할 수 있는 몇 가지 옵션 플래그가 있습니다.
DEFAULT_PATH_LEAF_TO_NULL
이 옵션을 사용하면 누락된 리프에 대해 JsonPath가 null을 반환하게 됩니다. 다음 JSON을 고려하십시오.
[
{
"name" : "john" ,
"gender" : "male"
} ,
{
"name" : "ben"
}
]
Configuration conf = Configuration . defaultConfiguration ();
//Works fine
String gender0 = JsonPath . using ( conf ). parse ( json ). read ( "$[0]['gender']" );
//PathNotFoundException thrown
String gender1 = JsonPath . using ( conf ). parse ( json ). read ( "$[1]['gender']" );
Configuration conf2 = conf . addOptions ( Option . DEFAULT_PATH_LEAF_TO_NULL );
//Works fine
String gender0 = JsonPath . using ( conf2 ). parse ( json ). read ( "$[0]['gender']" );
//Works fine (null is returned)
String gender1 = JsonPath . using ( conf2 ). parse ( json ). read ( "$[1]['gender']" );
ALWAYS_RETURN_LIST
이 옵션은 경로가 definite
경우에도 목록을 반환하도록 JsonPath를 구성합니다.
Configuration conf = Configuration . defaultConfiguration ();
//ClassCastException thrown
List < String > genders0 = JsonPath . using ( conf ). parse ( json ). read ( "$[0]['gender']" );
Configuration conf2 = conf . addOptions ( Option . ALWAYS_RETURN_LIST );
//Works fine
List < String > genders0 = JsonPath . using ( conf2 ). parse ( json ). read ( "$[0]['gender']" );
SUPPRESS_EXCEPTIONS
이 옵션을 사용하면 경로 평가에서 예외가 전파되지 않습니다. 다음과 같은 간단한 규칙을 따릅니다.
ALWAYS_RETURN_LIST
옵션이 있으면 빈 목록이 반환됩니다.ALWAYS_RETURN_LIST
옵션이 없으면 null이 반환됩니다. REQUIRE_PROPERTIES
이 옵션은 indefinite
경로가 평가될 때 path에 정의된 속성을 요구하도록 JsonPath를 구성합니다.
Configuration conf = Configuration . defaultConfiguration ();
//Works fine
List < String > genders = JsonPath . using ( conf ). parse ( json ). read ( "$[*]['gender']" );
Configuration conf2 = conf . addOptions ( Option . REQUIRE_PROPERTIES );
//PathNotFoundException thrown
List < String > genders = JsonPath . using ( conf2 ). parse ( json ). read ( "$[*]['gender']" );
JsonPath는 다섯 가지 JsonProvider와 함께 제공됩니다.
설명된 대로 구성 기본값을 변경하는 작업은 애플리케이션이 초기화될 때만 수행되어야 합니다. 특히 다중 스레드 애플리케이션에서는 런타임 중 변경을 권장하지 않습니다.
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 );
}
});
JacksonJsonProvider에는 클래스 경로에 com.fasterxml.jackson.core:jackson-databind:2.4.5
필요하고 GsonJsonProvider에는 com.google.code.gson:gson:2.3.1
이 필요합니다.
Jakarta EE 9 JSON-P(JSR-342) 및 JSON-B(JSR-367) 제공자 모두 최소 Java 8을 기대하며 애플리케이션 런타임 클래스 경로에 호환 가능한 JSON API 구현(예: Eclipse Glassfish 및 Eclipse Yasson)이 필요합니다. 이러한 구현은 Java EE 애플리케이션 컨테이너에 의해 제공될 수도 있습니다. 또한 Apache Johnzon은 아직 Jakarta EE 9 사양과 클래스 경로 호환되지 않으며 JSON-B 매핑 공급자를 선택한 경우 JSON-P 공급자도 구성하고 사용해야 합니다.
JSON 처리 및 데이터 바인딩(매핑)에 대한 Jakarta EE 9 사양의 한 가지 특징은 Json 배열 및 객체가 완전히 구문 분석되거나 기록되는 즉시 불변성입니다. API 사양을 준수하지만 JsonPath가 추가, 설정/넣기, 교체 및 삭제 작업을 통해 Json 문서를 수정할 수 있도록 허용하려면 JakartaJsonProvider
선택적인 true
인수로 초기화해야 합니다.
JsonProvider jsonProvider = new JakartaJsonProvider(true)
(변경 가능한 Json 배열 및 객체 활성화)JsonProvider jsonProvider = new JakartaJsonProvider()
(기본값, 엄격한 JSON-P API 준수)JsonPath를 사용한 모든 조회 및 읽기 작업은 초기화 모드에 관계없이 지원됩니다. 기본 모드는 또한 메모리가 덜 필요하고 성능이 더 좋습니다.
JsonPath 2.1.0에는 새로운 Cache SPI가 도입되었습니다. 이를 통해 API 소비자는 필요에 맞는 방식으로 경로 캐싱을 구성할 수 있습니다. 처음으로 액세스하기 전에 캐시를 구성해야 하며 그렇지 않으면 JsonPathException이 발생합니다. JsonPath에는 두 가지 캐시 구현이 함께 제공됩니다.
com.jayway.jsonpath.spi.cache.LRUCache
(기본값, 스레드 안전)com.jayway.jsonpath.spi.cache.NOOPCache
(캐시 없음)자신만의 캐시를 구현하려는 경우 API는 간단합니다.
CacheProvider . setCache ( new Cache () {
//Not thread safe simple cache
private Map < String , JsonPath > map = new HashMap < String , JsonPath >();
@ Override
public JsonPath get ( String key ) {
return map . get ( key );
}
@ Override
public void put ( String key , JsonPath jsonPath ) {
map . put ( key , jsonPath );
}
});