웹사이트 검색

Jackson JSON Java Parser API 예제 자습서


Jackson JSON Java Parser는 매우 인기가 있으며 Spring 프레임워크에서도 사용됩니다. Google Gson API를 사용하고 얼마나 쉽게 사용할 수 있는지 확인했습니다.

잭슨 JSON 자바 파서

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.2.3</version>
</dependency>

jackson-databind jar는 jackson-core 및 jackson-annotations 라이브러리에 의존하므로 빌드 경로에 직접 추가하는 경우 세 가지를 모두 추가해야 합니다. 그렇지 않으면 런타임 오류가 발생합니다. Jackson JSON Parser API는 JSON을 POJO 객체로 쉽게 변환할 수 있는 방법을 제공하고 JSON 데이터에서 Map으로 쉽게 변환할 수 있도록 지원합니다. Jackson은 제네릭도 지원하며 JSON에서 객체로 직접 변환합니다.

잭슨 JSON 예시

JSON에서 POJO/Java 객체로의 변환에 대한 예제에서는 중첩된 객체 및 배열이 있는 복잡한 예제를 사용합니다. 변환을 위해 Java 객체에서 배열, 목록 및 맵을 사용합니다. 우리의 복잡한 json은 아래 구조의 employee.txt 파일에 저장됩니다.

{
  "id": 123,
  "name": "Pankaj",
  "permanent": true,
  "address": {
    "street": "Albany Dr",
    "city": "San Jose",
    "zipcode": 95129
  },
  "phoneNumbers": [
    123456,
    987654
  ],
  "role": "Manager",
  "cities": [
    "Los Angeles",
    "New York"
  ],
  "properties": {
    "age": "29 years",
    "salary": "1000 USD"
  }
}

json 데이터에 해당하는 다음과 같은 Java 클래스가 있습니다.

package com.journaldev.jackson.model;

public class Address {
	
	private String street;
	private String city;
	private int zipcode;
	
	public String getStreet() {
		return street;
	}
	public void setStreet(String street) {
		this.street = street;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public int getZipcode() {
		return zipcode;
	}
	public void setZipcode(int zipcode) {
		this.zipcode = zipcode;
	}
	
	@Override
	public String toString(){
		return getStreet() + ", "+getCity()+", "+getZipcode();
	}
}

주소 클래스는 루트 json 데이터의 내부 개체에 해당합니다.

package com.journaldev.jackson.model;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Employee {

	private int id;
	private String name;
	private boolean permanent;
	private Address address;
	private long[] phoneNumbers;
	private String role;
	private List<String> cities;
	private Map<String, String> properties;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public boolean isPermanent() {
		return permanent;
	}
	public void setPermanent(boolean permanent) {
		this.permanent = permanent;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	public long[] getPhoneNumbers() {
		return phoneNumbers;
	}
	public void setPhoneNumbers(long[] phoneNumbers) {
		this.phoneNumbers = phoneNumbers;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	
	@Override
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("***** Employee Details *****\n");
		sb.append("ID="+getId()+"\n");
		sb.append("Name="+getName()+"\n");
		sb.append("Permanent="+isPermanent()+"\n");
		sb.append("Role="+getRole()+"\n");
		sb.append("Phone Numbers="+Arrays.toString(getPhoneNumbers())+"\n");
		sb.append("Address="+getAddress()+"\n");
		sb.append("Cities="+Arrays.toString(getCities().toArray())+"\n");
		sb.append("Properties="+getProperties()+"\n");
		sb.append("*****************************");
		
		return sb.toString();
	}
	public List<String> getCities() {
		return cities;
	}
	public void setCities(List<String> cities) {
		this.cities = cities;
	}
	public Map<String, String> getProperties() {
		return properties;
	}
	public void setProperties(Map<String, String> properties) {
		this.properties = properties;
	}
}

직원은 루트 json 객체를 나타내는 자바 빈입니다. 이제 Jackson JSON 파서 API를 사용하여 JSON을 Java 객체로 변환하는 방법을 살펴보겠습니다.

package com.journaldev.jackson.json;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.journaldev.jackson.model.Address;
import com.journaldev.jackson.model.Employee;


public class JacksonObjectMapperExample {

	public static void main(String[] args) throws IOException {
		
		//read json file data to String
		byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));
		
		//create ObjectMapper instance
		ObjectMapper objectMapper = new ObjectMapper();
		
		//convert json string to object
		Employee emp = objectMapper.readValue(jsonData, Employee.class);
		
		System.out.println("Employee Object\n"+emp);
		
		//convert Object to json string
		Employee emp1 = createEmployee();
		//configure Object mapper for pretty print
		objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
		
		//writing to console, can write to any output stream such as file
		StringWriter stringEmp = new StringWriter();
		objectMapper.writeValue(stringEmp, emp1);
		System.out.println("Employee JSON is\n"+stringEmp);
	}
	
	public static Employee createEmployee() {

		Employee emp = new Employee();
		emp.setId(100);
		emp.setName("David");
		emp.setPermanent(false);
		emp.setPhoneNumbers(new long[] { 123456, 987654 });
		emp.setRole("Manager");

		Address add = new Address();
		add.setCity("Bangalore");
		add.setStreet("BTM 1st Stage");
		add.setZipcode(560100);
		emp.setAddress(add);

		List<String> cities = new ArrayList<String>();
		cities.add("Los Angeles");
		cities.add("New York");
		emp.setCities(cities);

		Map<String, String> props = new HashMap<String, String>();
		props.put("salary", "1000 Rs");
		props.put("age", "28 years");
		emp.setProperties(props);

		return emp;
	}

}

위의 프로그램을 실행하면 다음과 같은 결과를 얻을 수 있습니다.

Employee Object
***** Employee Details *****
ID=123
Name=Pankaj
Permanent=true
Role=Manager
Phone Numbers=[123456, 987654]
Address=Albany Dr, San Jose, 95129
Cities=[Los Angeles, New York]
Properties={age=29 years, salary=1000 USD}
*****************************
Employee JSON is
//printing same as above json file data

com.fasterxml.jackson.databind.ObjectMapper는 JSON을 Java Object로, Java Object를 JSON으로 변환하는 readValue() 및 writeValue() 메서드를 제공하는 Jackson API에서 가장 중요한 클래스입니다. ObjectMapper 클래스는 재사용할 수 있으며 Singleton 객체로 한 번 초기화할 수 있습니다. 바이트 배열, 파일, 입력/출력 스트림 및 Reader/Writer 개체와 함께 작동하는 readValue() 및 writeValue() 메서드의 오버로드 버전이 너무 많습니다.

Jackson JSON - JSON을 지도로 변환

때로는 data.txt 파일에 아래와 같은 JSON 개체가 있습니다.

{
  "name": "David",
  "role": "Manager",
  "city": "Los Angeles"
}

동일한 속성과 키를 가진 Java 개체가 아닌 Map으로 변환하려고 합니다. 아래 코드를 사용하여 두 가지 방법을 사용하여 Jackson JSON API에서 매우 쉽게 수행할 수 있습니다.

//converting json to Map
byte[] mapData = Files.readAllBytes(Paths.get("data.txt"));
Map<String,String> myMap = new HashMap<String, String>();

ObjectMapper objectMapper = new ObjectMapper();
myMap = objectMapper.readValue(mapData, HashMap.class);
System.out.println("Map is: "+myMap);

//another way
myMap = objectMapper.readValue(mapData, new TypeReference<HashMap<String,String>>() {});
System.out.println("Map using TypeReference: "+myMap);

위 스니펫을 실행하면 다음과 같은 결과가 나타납니다.

Map is: {name=David, role=Manager, city=Los Angeles}
Map using TypeReference: {name=David, role=Manager, city=Los Angeles}

Jackson JSON - 특정 JSON 키 읽기

때로는 json 데이터가 있고 몇 가지 키 값에만 관심이 있으므로 이 경우 전체 JSON을 객체로 변환하는 것은 좋은 생각이 아닙니다. Jackson JSON API는 DOM Parser와 같이 json 데이터를 트리로 읽을 수 있는 옵션을 제공하며 이를 통해 JSON 객체의 특정 요소를 읽을 수 있습니다. 아래 코드는 json 파일에서 특정 항목을 읽는 스니펫을 제공합니다.

//read json file data to String
byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();

//read JSON like DOM Parser
JsonNode rootNode = objectMapper.readTree(jsonData);
JsonNode idNode = rootNode.path("id");
System.out.println("id = "+idNode.asInt());

JsonNode phoneNosNode = rootNode.path("phoneNumbers");
Iterator<JsonNode> elements = phoneNosNode.elements();
while(elements.hasNext()){
	JsonNode phone = elements.next();
	System.out.println("Phone No = "+phone.asLong());
}

위의 코드 조각을 실행하면 다음과 같은 결과가 나타납니다.

id = 123
Phone No = 123456
Phone No = 987654

Jackson JSON - JSON 문서 편집

Jackson JSON Java API는 JSON 데이터에서 키를 추가, 편집 및 제거하는 유용한 방법을 제공한 다음 새 json 파일로 저장하거나 스트림에 쓸 수 있습니다. 아래 코드는 이 작업을 쉽게 수행하는 방법을 보여줍니다.

byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

ObjectMapper objectMapper = new ObjectMapper();

//create JsonNode
JsonNode rootNode = objectMapper.readTree(jsonData);

//update JSON data
((ObjectNode) rootNode).put("id", 500);
//add new key value
((ObjectNode) rootNode).put("test", "test value");
//remove existing key
((ObjectNode) rootNode).remove("role");
((ObjectNode) rootNode).remove("properties");
objectMapper.writeValue(new File("updated_emp.txt"), rootNode);

위의 코드를 실행하고 새 파일을 찾으면 "role\ 및 "properties\ 키가 없음을 알 수 있습니다. 또한 "id\ 값이 500으로 업데이트되고 새 키 "test\가 updated_emp.txt 파일에 추가되었음을 알 수 있습니다.

Jackson JSON 스트리밍 API 예제

Jackson JSON Java API는 전체 파일을 토큰으로 읽고 메모리를 덜 사용하기 때문에 대용량 json 데이터 작업에 도움이 되는 스트리밍 지원도 제공합니다. 스트리밍 API의 유일한 문제는 JSON 데이터를 구문 분석하는 동안 모든 토큰을 처리해야 한다는 것입니다. json 데이터가 {\role”:\Manager”}인 경우 {(개체 시작), \role(키 이름), \Manager(키 값) 및 순서대로 토큰을 얻습니다. } (객체 종료). 콜론(:)은 JSON의 구분 기호이므로 토큰으로 간주되지 않습니다.

package com.journaldev.jackson.json;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.journaldev.jackson.model.Address;
import com.journaldev.jackson.model.Employee;

public class JacksonStreamingReadExample {

	public static void main(String[] args) throws JsonParseException, IOException {
		
		//create JsonParser object
		JsonParser jsonParser = new JsonFactory().createParser(new File("employee.txt"));
		
		//loop through the tokens
		Employee emp = new Employee();
		Address address = new Address();
		emp.setAddress(address);
		emp.setCities(new ArrayList<String>());
		emp.setProperties(new HashMap<String, String>());
		List<Long> phoneNums = new ArrayList<Long>();
		boolean insidePropertiesObj=false;
		
		parseJSON(jsonParser, emp, phoneNums, insidePropertiesObj);
		
		long[] nums = new long[phoneNums.size()];
		int index = 0;
		for(Long l :phoneNums){
			nums[index++] = l;
		}
		emp.setPhoneNumbers(nums);
		
		jsonParser.close();
		//print employee object
		System.out.println("Employee Object\n\n"+emp);
	}

	private static void parseJSON(JsonParser jsonParser, Employee emp,
			List<Long> phoneNums, boolean insidePropertiesObj) throws JsonParseException, IOException {
		
		//loop through the JsonTokens
		while(jsonParser.nextToken() != JsonToken.END_OBJECT){
			String name = jsonParser.getCurrentName();
			if("id".equals(name)){
				jsonParser.nextToken();
				emp.setId(jsonParser.getIntValue());
			}else if("name".equals(name)){
				jsonParser.nextToken();
				emp.setName(jsonParser.getText());
			}else if("permanent".equals(name)){
				jsonParser.nextToken();
				emp.setPermanent(jsonParser.getBooleanValue());
			}else if("address".equals(name)){
				jsonParser.nextToken();
				//nested object, recursive call
				parseJSON(jsonParser, emp, phoneNums, insidePropertiesObj);
			}else if("street".equals(name)){
				jsonParser.nextToken();
				emp.getAddress().setStreet(jsonParser.getText());
			}else if("city".equals(name)){
				jsonParser.nextToken();
				emp.getAddress().setCity(jsonParser.getText());
			}else if("zipcode".equals(name)){
				jsonParser.nextToken();
				emp.getAddress().setZipcode(jsonParser.getIntValue());
			}else if("phoneNumbers".equals(name)){
				jsonParser.nextToken();
				while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
					phoneNums.add(jsonParser.getLongValue());
				}
			}else if("role".equals(name)){
				jsonParser.nextToken();
				emp.setRole(jsonParser.getText());
			}else if("cities".equals(name)){
				jsonParser.nextToken();
				while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
					emp.getCities().add(jsonParser.getText());
				}
			}else if("properties".equals(name)){
				jsonParser.nextToken();
				while(jsonParser.nextToken() != JsonToken.END_OBJECT){
					String key = jsonParser.getCurrentName();
					jsonParser.nextToken();
					String value = jsonParser.getText();
					emp.getProperties().put(key, value);
				}
			}
		}
	}

}

JsonParser는 json 데이터를 읽기 위한 jackson json 스트리밍 API입니다. 우리는 이를 사용하여 파일에서 데이터를 읽은 다음 parseJSON() 메서드를 사용하여 토큰을 반복하고 처리하여 Java 개체를 만듭니다. parseJSON() 메서드는 "address\에 대해 재귀적으로 호출됩니다. 이는 json 데이터의 중첩된 객체이기 때문입니다. 배열을 구문 분석하기 위해 json 문서를 반복합니다. JsonGenerator 클래스를 사용하여 스트리밍 API로 json 데이터를 생성할 수 있습니다.

package com.journaldev.jackson.json;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Set;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.journaldev.jackson.model.Employee;

public class JacksonStreamingWriteExample {

	public static void main(String[] args) throws IOException {
		Employee emp = JacksonObjectMapperExample.createEmployee();

		JsonGenerator jsonGenerator = new JsonFactory()
				.createGenerator(new FileOutputStream("stream_emp.txt"));
		//for pretty printing
		jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter());
		
		jsonGenerator.writeStartObject(); // start root object
		jsonGenerator.writeNumberField("id", emp.getId());
		jsonGenerator.writeStringField("name", emp.getName());
		jsonGenerator.writeBooleanField("permanent", emp.isPermanent());
		
		jsonGenerator.writeObjectFieldStart("address"); //start address object
			jsonGenerator.writeStringField("street", emp.getAddress().getStreet());
			jsonGenerator.writeStringField("city", emp.getAddress().getCity());
			jsonGenerator.writeNumberField("zipcode", emp.getAddress().getZipcode());
		jsonGenerator.writeEndObject(); //end address object
		
		jsonGenerator.writeArrayFieldStart("phoneNumbers");
			for(long num : emp.getPhoneNumbers())
				jsonGenerator.writeNumber(num);
		jsonGenerator.writeEndArray();
		
		jsonGenerator.writeStringField("role", emp.getRole());
		
		jsonGenerator.writeArrayFieldStart("cities"); //start cities array
		for(String city : emp.getCities())
			jsonGenerator.writeString(city);
		jsonGenerator.writeEndArray(); //closing cities array
		
		jsonGenerator.writeObjectFieldStart("properties");
			Set<String> keySet = emp.getProperties().keySet();
			for(String key : keySet){
				String value = emp.getProperties().get(key);
				jsonGenerator.writeStringField(key, value);
			}
		jsonGenerator.writeEndObject(); //closing properties
		jsonGenerator.writeEndObject(); //closing root object
		
		jsonGenerator.flush();
		jsonGenerator.close();
	}

}

JsonGenerator는 JsonParser에 비해 사용하기 쉽습니다. Jackson JSON Parser Java API에 대한 빠른 참조 튜토리얼은 여기까지입니다. Jackson JSON Java API는 사용하기 쉽고 개발자가 JSON 데이터로 쉽게 작업할 수 있도록 많은 옵션을 제공합니다. 아래 링크에서 프로젝트를 다운로드하고 가지고 놀면서 Jackson Json API에 대한 더 많은 옵션을 살펴보세요.

잭슨 JSON 프로젝트 다운로드

참조: Jackson GitHub 페이지