eXtensible Markup Language의 약자로, 공유용 데이터를 배포할 경우 사용하는 파일을 의미한다.
기존 데이터 공유 방식
기존에는 데이터를 공유(전송)하기 위해서는 문자열을 이용하였다.(구분자를 사용)
홍길동-24-181.2-1233
위 처럼 전송할 경우 문자열 조작을 통해 원하는 데이터를 가져올 수 있었다.
하지만 위의 방식의 경우 데이터의 정보를 알 수가 없다.(즉, 해당 데이터가 무엇을 의미하는지 알 수 없다) 이러한 문제를 해결하기위해 나온 것이 XML이다.xml 태그
xml은 tag를 사용하여 데이터의 정보를 명시할 수 있다.
<사람> <이름>홍길동</이름> <이름>성춘향</이름> <이름>마동석</이름> </사람>
태그의 경우 사용자가 직접 정의하여 사용한다.(html처럼 지정된 tag가 있는 것이 아니다.)
xml 구조
xml의 구조는 root로부터 시작해서 leave로 뻗어나가는 트리구조의 형태이다.
위 예시에서는 root태그는 사람이다.(root태그의 경우 1개만 존재할 수 있다)
또한 root는 3개의 자식요소(노드)를 가진다.
json은 xml을 대체하기 위해 나온 방식이다.
<?xml version="1.0"?> <company> <employee id="1001"> <firstname>Tony</firstname> <lastname>Black</lastname> <salary>100000</salary> </employee> <employee id="2001"> <firstname>Amy</firstname> <lastname>Green</lastname> <salary>200000</salary> </employee> </company>
eElement.getElementsByTagName("firstname").item(0).getTextContent();
위의 예시는 Amy를 가져오기 위한 코드이다.
{ "company": { "employee": [ { "id": 1001, "firstname": "Tony", "lastname": "Black", "salary": 100000 }, { "id": 2001, "firstname": "Amy", "lastname": "Green", "salary": 200000 } ] } }
해당 예시는 위의 xml을 json으로 변환한 것이다.
만약 json을 사용한다면, 아래 코드와 같다.public class MainClass { public static void main(String[] args) throws Exception { Reader reader = new FileReader("C:\\InteliJ\\sample_docekr_mysql\\src\\test.json"); // reader를 Object로 parse JSONParser jsonParser = new JSONParser(); JSONObject obj = (JSONObject) jsonParser.parse(reader); JSONObject jsonObj = (JSONObject)obj; JSONObject jsonObj1 = (JSONObject)jsonObj.get("company"); JSONObject jsonObj2 = (JSONObject)((JSONArray)(jsonObj1.get("emplvoyee"))).get(1); System.out.println(jsonObj2.get("firstname")); } }
위 코드는 SimpleJSON을 사용한 코드이다.
java에서는 json을 다루는 라이브러리가 여러개 존재하는데, 가장 대표적인 라이브러리가 바로 Jackson이다.
아래는 Jackson을 사용한 코드이다.(jackson을 사용하는 이유를 알겠다)public class MainClass { public static void main(String[] args) throws Exception { File file = new File("C:\\InteliJ\\sample_docekr_mysql\\src\\test.json"); ObjectMapper objectMapper = new ObjectMapper(); root student = objectMapper.readValue(file, root.class); System.out.println(student.getCompany().getEmployee()[1].getFirstname()); } }
Jackson 사용법
Jackson은 java에서 json을 다루기 위해 사용되는 대표적인 라이브러리이다.
Jackson은 JSON문자열을 Java object로 변환(역도 가능)하여 json을 다룰 수 있게 도와준다.JSON 문자열(file) -> Java Object (역직렬화)
우선 JSON문자열을 Object로 변환하기 위해서는 JSON형식에 맞는 class를 갖춰야한다.
위의 예시 JSON의 구조는 3가지의 class가 필요하다.(편의상 getter는 생략)// rootClass public class root { private Company company; public root() { } public root(Company company) { this.company = company; } }
// company class public class Company { private Employee[] employee; public Company(Employee[] employee) { this.employee = employee; } public Company() { } }
public class Employee { private int id; private String firstname; private String lastname; private int salary; public Employee(){} public Employee(int id, String firstname, String lastname, int salary) { this.id = id; this.firstname = firstname; this.lastname = lastname; this.salary = salary; } }
json문자열을 Object로 변환하기 위해서는 objectMapper객체가 필요하며, readValue메서드를 사용한다.
중요한것은 매핑을 할때, 리플렉션 기술을 사용하기 때문에 반드시 모든 class에 기본 생성자와getter(private,protected맴버변수)가 있어야 한다.(리플렉션API에는 생성자의 매개변수를 가져오는 메서드는 없기 때문에)getter가 필요한 이유
getter가 필요한 이유는 stackoverflow에서 찾을 수 있었다.
그 이유는 Jackson의 경우 해당 object를 찾기위해 리플렉션 기술을 사용하는데, private과 protected 속성(멤버변수)를 접근하기 위해서 getter를 사용한다고 한다.
기본생성자로 인해 해당 object를 생성했어도, private,protected 속성은 getter이외에 접근이 불가능하기 때문에 해당 속성들을 접근(알기)위해서는 getter가 꼭 필요하다.Java Object -> JSON문자열 (직렬화)
public class MainClass { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); Employee employee = new Employee(1,"Amy","Golden",12000); Employee[] employees = {employee}; Company testcompany = new Company(employees); root testroot = new root(testcompany); System.out.println(objectMapper.writeValueAsString(testroot)); } }
직렬화의 경우 3가지 메서드를 사용할 수 있다.
writeValue()
writeValueAsString()
writeValueAsBytes()주의
- 역직렬화의 경우 Json의 key값은 Object의 속성(멤버변수)와 동일해야한다.
동일하지 않을 경우 에러발생
- getter 사용시 주의
직렬화를 할 경우 Object를 매핑 시 get메서드를 활용하기 때문에, Object에 없는 속성에 대해 get메서드가 있을 경우 없는 속성에 대해서도 인식을 하게 된다.
아래 코드는 잘못된 코드의 예시이다.public class MainClass { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); Employee employee1 = new Employee(1,"Amy","Golden",12000); Employee employee2 = new Employee(2,"Tom","Guss",13214); Employee[] employees = {employee1,employee2}; Company testcompany = new Company(employees); root testroot = new root(testcompany); System.out.println(objectMapper.writeValueAsString(testroot)); } } // Employee class에 public String getUnkwo(){return "blabla";} 추가
해당 코드의 결과는 아래와 같고, Employee에 없는 속성인 unkwo가 추가된 것을 볼 수 있다.
{"company":{"employee":[{"id":1,"firstname":"Amy","lastname":"Golden","salary":12000,"unkwo":"blabla"},{"id":2,"firstname":"Tom","lastname":"Guss","salary":13214,"unkwo":"blabla"}]}}
- lombok 사용시 @Getter 주의
@Getter를 사용할 경우 Jackson이 해당 속성을 찾지 못하기 때문에 @Getter를 사용할 경우 @JsonProperty를 해당 속성위에 사용해야 한다.@JsonProperty("company") private Company company;
MAVEN과 같이 의존성을 관리해주는 도구를 사용하지 않을 경우, JAR파일을 다운받아서, 하나씩 라이브러리를 추가해주어야 한다. (3가지를 추가하는 것을 추천)
Jackson Annotations : https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
jackson-databind : https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
Jackson Core : https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core