티스토리 뷰

Java

Jackson의 모든 것 - 일반편

Jaime.Lee 2019. 11. 22. 12:19
모든 소스는 여기서 확인하실 수 있습니다.

@JsonProperty

JSON에서의 속성 이름을 나타냅니다. 필드 변수 또는 getter/setter 메소드에 사용할 수 있습니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

public class BeanWithJsonProperty {
    @Getter
    @Setter
    @JsonProperty("identity")
    private int id;
    private String name;

    @JsonProperty("nickname")
    public String getName() {
        return name;
    }

    @JsonProperty("nickname")
    public void setName(String name) {
        this.name = name;
    }
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;

public class BeanWithJsonPropertyTests {
    @Test
    public void WhenJsonPropertyProvided_ThenSerialize_ExpectCorrect() throws JsonProcessingException {
        // when
        BeanWithJsonProperty bean = new BeanWithJsonProperty();
        bean.setId(1);
        bean.setName("name");

        // then
        String json = new ObjectMapper().writeValueAsString(bean);

        // expected
        System.out.println(json);
        assertThat(json, containsString("nickname"));
        assertThat(json, containsString("identity"));
    }
}

 

Testing started at 3:51 PM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes
> Task :jackson:compileTestJava
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses
> Task :jackson:test
{"identity":1,"nickname":"name"}
BUILD SUCCESSFUL in 2s
4 actionable tasks: 4 executed
3:51:17 PM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithJsonPropertyTests.WhenJsonPropertyProvided_ThenSerialize_ExpectCorrect"'.

@JsonFormat

직렬화시 Date나 Time에 사용할 형식을 지정합니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.Date;

@Data
public class BeanWithJsonFormat {
    private String name;

    @JsonFormat(
            shape = JsonFormat.Shape.STRING,
            pattern = "yyyy-MM-dd HH:mm:ss"
    )
    private Date date;
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;

public class BeanWithJsonFormatTests {
    @Test
    public void WhenJsonFormatProvided_ThenSerialize_ExpectCorrect() throws ParseException, JsonProcessingException {
        // when
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        format.setTimeZone(TimeZone.getTimeZone("UTC"));
        String dateToParse = "2019-11-23 19:00:30";
        Date parsedDate = format.parse(dateToParse);
        BeanWithJsonFormat bean = new BeanWithJsonFormat();
        bean.setName("bean");
        bean.setDate(parsedDate);

        // then
        String json = new ObjectMapper().writeValueAsString(bean);

        // expected
        System.out.println(json);
        assertThat(json, containsString(dateToParse));
    }
}
Testing started at 7:04 PM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava UP-TO-DATE
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes UP-TO-DATE
> Task :jackson:compileTestJava
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses
> Task :jackson:test
{"name":"bean","date":"2019-11-23 19:00:30"}
BUILD SUCCESSFUL in 1s
4 actionable tasks: 3 executed, 1 up-to-date
7:04:01 PM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithJsonFormatTests.WhenJsonFormatProvided_ThenSerialize_ExpectCorrect"'.

@JsonUnwrapped

직렬화/역직렬화시 객체로 쌓여있지 않게(unwrapped, flattened) 합니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonUnwrapped;
import lombok.Data;

@Data
public class BeanWithJsonUnwrapped {
    private int id;

    @JsonUnwrapped
    public Name name;

    @Data
    public static class Name {
        private String firstName;
        private String lastName;
    }
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;

public class BeanWithJsonUnwrappedTests {
    @Test
    public void WhenJsonUnwrappedProvided_ThenSerialize_ExpectCorrect() throws JsonProcessingException {
        // when
        BeanWithJsonUnwrapped bean = new BeanWithJsonUnwrapped();
        bean.setId(1);
        BeanWithJsonUnwrapped.Name name = new BeanWithJsonUnwrapped.Name();
        name.setFirstName("firstName");
        name.setLastName("lastName");
        bean.setName(name);

        // then
        String json = new ObjectMapper().writeValueAsString(bean);

        // expected
        System.out.println(json);
        assertThat(json, not(containsString("name")));
    }

    @Test
    public void WhenJsonWithFlatFieldsProvided_ThenDeserialize_ExpectCorrect() throws JsonProcessingException {
        // when
        String json = "{\"id\":0,\"firstName\":\"firstname\",\"lastName\":\"lastname\"}";

        // then
        BeanWithJsonUnwrapped bean = new ObjectMapper().readValue(json, BeanWithJsonUnwrapped.class);

        // expected
        System.out.println(bean);
        assertNotNull(bean.getName());
    }
}
Testing started at 1:21 AM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava UP-TO-DATE
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes UP-TO-DATE
> Task :jackson:compileTestJava UP-TO-DATE
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses UP-TO-DATE
> Task :jackson:test
BeanWithJsonUnwrapped(id=0, name=BeanWithJsonUnwrapped.Name(firstName=firstname, lastName=lastname))
{"id":1,"firstName":"firstName","lastName":"lastName"}
BUILD SUCCESSFUL in 1s
4 actionable tasks: 2 executed, 2 up-to-date
1:21:15 AM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithJsonUnwrappedTests"'.

@JsonView

직렬화/역직렬화시 속성이 포함될지 여부를 결정합니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonView;
import lombok.Data;

@Data
public class BeanWithJsonView {

    @JsonView(View.Public.class)
    private int id;
    @JsonView(View.Public.class)
    private String name;
    @JsonView(View.Internal.class)
    private String password;


    public static class View {
        public static class Public {
        }

        public static class Internal extends Public {
        }
    }
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

public class BeanWithJsonViewTests {
    @Test
    public void WhenJsonViewProvided_ThenSerialize_ExpectCorrect() throws JsonProcessingException {
        // when
        BeanWithJsonView bean = new BeanWithJsonView();
        bean.setId(1);
        bean.setName("name");
        bean.setPassword("password");

        // then
        String json = new ObjectMapper().writerWithView(BeanWithJsonView.View.Public.class).writeValueAsString(bean);

        // expected
        System.out.println(json);
        assertThat(json, not(containsString("password")));
    }
}
Testing started at 12:52 AM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava UP-TO-DATE
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes UP-TO-DATE
> Task :jackson:compileTestJava
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses
> Task :jackson:test
{"id":1,"name":"name"}
BUILD SUCCESSFUL in 0s
4 actionable tasks: 3 executed, 1 up-to-date
12:52:08 AM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithJsonViewTests"'.

@JsonManagedReference, @JsonBackReference

부모/자식 관계를 처리하고 루프를 해결할 수 있습니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.Data;

@Data
public class BeanWithJsonManagedReference {
    private int id;
    private String name;

    @JsonManagedReference
    private BeanWithJsonBackReference bean;
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.Data;

import java.util.List;

@Data
public class BeanWithJsonBackReference {
    private int id;
    private String name;
    @JsonBackReference
    private List<BeanWithJsonManagedReference> beans;
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

public class BeanWithReferenceTests {
    @Test
    public void WhenReferenceProvided_ThenSerialize_ExpectCorrect() throws JsonProcessingException {
        // when
        BeanWithJsonBackReference backBean = new BeanWithJsonBackReference();
        backBean.setId(1);
        backBean.setName("backBean");

        BeanWithJsonManagedReference managedBean = new BeanWithJsonManagedReference();
        managedBean.setId(2);
        managedBean.setName("managedBean");
        managedBean.setBean(backBean);

        List<BeanWithJsonManagedReference> beans = new ArrayList<>();
        beans.add(managedBean);
        backBean.setBeans(beans);

        // then
        String json1 = new ObjectMapper().writeValueAsString(backBean);
        String json2 = new ObjectMapper().writeValueAsString(managedBean);

        // expected
        System.out.println(json1);
        System.out.println(json2);

        assertThat(json1, not(containsString("beans")));
        assertThat(json2, containsString("backBean"));
    }
}
Testing started at 9:41 AM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava UP-TO-DATE
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes UP-TO-DATE
> Task :jackson:compileTestJava
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses
> Task :jackson:test
{"id":1,"name":"backBean"}
{"id":2,"name":"managedBean","bean":{"id":1,"name":"backBean"}}
BUILD SUCCESSFUL in 0s
4 actionable tasks: 3 executed, 1 up-to-date
9:41:33 AM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithReferenceTests.WhenReferenceProvided_ThenSerialize_ExpectCorrect"'.

@JsonIdentityInfo

직렬화/역직렬화 할 때 객체끼리 서로 무한으로 참조하지 않도록 ID를 사용합니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

public class BeanWithIdentity {
    @JsonIdentityInfo(
            generator = ObjectIdGenerators.PropertyGenerator.class,
            property = "id" // default
    )
    @Data
    public static class Item {
        private int id;
        private String name;
        private User owner;
    }

    @Data
    public static class User {
        private int id;
        private String name;
        private List<Item> items;

        public User() {
            items = new ArrayList<>();
        }
    }
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;

public class BeanWithIdentityTests {
    @Test
    public void WhenJsonIdentityInfoProvided_ThenSerialize_ExpectCorrect() throws JsonProcessingException {
        // when
        BeanWithIdentity.User user = new BeanWithIdentity.User();
        user.setId(1);
        user.setName("valkyrie");

        BeanWithIdentity.Item item = new BeanWithIdentity.Item();
        item.setId(2);
        item.setName("spear");
        item.setOwner(user);

        user.getItems().add(item);

        // then
        String json = new ObjectMapper().writeValueAsString(item);

        // expected
        System.out.println(json);
        assertThat(json, containsString("spear"));
        assertThat(json, containsString("valkyrie"));
        assertThat(json, containsString("items"));
    }
}
Testing started at 9:51 AM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava UP-TO-DATE
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes UP-TO-DATE
> Task :jackson:compileTestJava
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses
> Task :jackson:test
{"id":2,"name":"spear","owner":{"id":1,"name":"valkyrie","items":[2]}}
BUILD SUCCESSFUL in 0s
4 actionable tasks: 3 executed, 1 up-to-date
9:51:16 AM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithIdentityTests.WhenJsonIdentityInfoProvided_ThenSerialize_ExpectCorrect"'.

@JsonFilter

직렬화시 사용할 필터를 지정합니다.

package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.annotation.JsonFilter;
import lombok.Data;

@Data
@JsonFilter("myFilter")
public class BeanWithFilter {
    private int id;
    private String name;
}
package io.lcalmsky.jackson.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

public class BeanWithFilterTests {
    @Test
    public void WhenJsonFilterProvided_ThenSerialize_ExpectCorrect() throws JsonProcessingException {
        // when
        BeanWithFilter bean = new BeanWithFilter();
        bean.setId(1);
        bean.setName("myBean");

        FilterProvider filterProvider = new SimpleFilterProvider()
                .addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name"));

        // then
        String json = new ObjectMapper()
                .writer(filterProvider)
                .writeValueAsString(bean);

        // expected
        System.out.println(json);
        assertThat(json, containsString("myBean"));
        assertThat(json, not(containsString("id")));
    }
}
Testing started at 9:59 AM ...
> Task :jackson:cleanTest
> Task :jackson:compileJava UP-TO-DATE
> Task :jackson:processResources NO-SOURCE
> Task :jackson:classes UP-TO-DATE
> Task :jackson:compileTestJava
> Task :jackson:processTestResources NO-SOURCE
> Task :jackson:testClasses
> Task :jackson:test
{"name":"myBean"}
BUILD SUCCESSFUL in 0s
4 actionable tasks: 3 executed, 1 up-to-date
9:59:19 AM: Tasks execution finished ':jackson:cleanTest :jackson:test --tests "io.lcalmsky.jackson.domain.BeanWithFilterTests.WhenJsonFilterProvided_ThenSerialize_ExpectCorrect"'.

 

댓글