-
목차
Spring Boot에서의 사용자 정의 데이터 직렬화 및 역직렬화 기법
Spring Boot는 자바 기반의 프레임워크로, 웹 애플리케이션 개발을 간소화하고 효율적으로 만들어 줍니다. 이 프레임워크는 RESTful API를 구축하는 데 매우 유용하며, 데이터 직렬화 및 역직렬화는 이러한 API에서 중요한 역할을 합니다. 본 글에서는 Spring Boot에서 사용자 정의 데이터 직렬화 및 역직렬화 기법에 대해 깊이 있게 다루어 보겠습니다.
1. 데이터 직렬화와 역직렬화의 이해
데이터 직렬화는 객체를 바이트 스트림으로 변환하여 저장하거나 전송할 수 있도록 하는 과정입니다. 반대로 역직렬화는 바이트 스트림을 다시 객체로 변환하는 과정입니다. 이러한 과정은 네트워크를 통해 데이터를 전송하거나 파일에 데이터를 저장할 때 필수적입니다.
Java에서는 기본적으로 직렬화를 지원하는 Serializable 인터페이스를 제공합니다. 하지만, Spring Boot에서는 JSON 형식으로 데이터를 직렬화하고 역직렬화하는 것이 일반적입니다. 이를 위해 Jackson 라이브러리를 사용합니다.
Jackson은 Java 객체를 JSON으로 변환하고, JSON을 Java 객체로 변환하는 데 매우 유용한 라이브러리입니다. Spring Boot는 기본적으로 Jackson을 통합하여 제공하므로, 별도의 설정 없이도 쉽게 사용할 수 있습니다.
예를 들어, 다음과 같은 간단한 Java 클래스를 생각해 보겠습니다:
public class User {
private String name;
private int age;
// getters and setters
}
이 클래스를 JSON으로 직렬화하면 다음과 같은 결과를 얻을 수 있습니다:
{
"name": "John",
"age": 30
}
이제 JSON 데이터를 다시 User 객체로 역직렬화할 수 있습니다. 이러한 과정은 RESTful API에서 클라이언트와 서버 간의 데이터 전송에 매우 중요합니다.
2. Spring Boot에서의 기본 직렬화 및 역직렬화
Spring Boot에서는 기본적으로 Jackson 라이브러리를 사용하여 JSON 형식으로 데이터를 직렬화하고 역직렬화합니다. 이를 위해 특별한 설정 없이도 @RestController와 @RequestBody, @ResponseBody 어노테이션을 사용하여 쉽게 구현할 수 있습니다.
예를 들어, 다음과 같은 RESTful API를 구현할 수 있습니다:
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity createUser(@RequestBody User user) {
// 사용자 생성 로직
return ResponseEntity.ok(user);
}
@GetMapping("/{id}")
public ResponseEntity getUser(@PathVariable Long id) {
// 사용자 조회 로직
User user = new User("John", 30);
return ResponseEntity.ok(user);
}
}
위의 코드에서 @RequestBody 어노테이션은 클라이언트가 전송한 JSON 데이터를 User 객체로 자동으로 변환합니다. 반대로 @ResponseBody 어노테이션은 User 객체를 JSON으로 변환하여 클라이언트에 응답합니다.
이러한 기본적인 직렬화 및 역직렬화 기능은 매우 유용하지만, 때로는 사용자 정의 직렬화 및 역직렬화가 필요할 수 있습니다. 예를 들어, 특정 필드를 제외하거나, 필드 이름을 변경해야 할 경우가 있습니다.
3. 사용자 정의 직렬화
사용자 정의 직렬화를 구현하기 위해서는 Jackson의 JsonSerializer 클래스를 확장하여 커스터마이징할 수 있습니다. 이를 통해 특정 필드의 직렬화 방식을 변경할 수 있습니다.
예를 들어, User 클래스에서 age 필드를 직렬화할 때, 특정 조건에 따라 값을 변경하고 싶다고 가정해 보겠습니다. 이 경우 다음과 같이 JsonSerializer를 구현할 수 있습니다:
public class UserSerializer extends JsonSerializer {
@Override
public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", user.getName());
if (user.getAge() > 18) {
jsonGenerator.writeNumberField("age", user.getAge());
} else {
jsonGenerator.writeStringField("age", "미성년자");
}
jsonGenerator.writeEndObject();
}
}
이제 User 클래스에 @JsonSerialize 어노테이션을 추가하여 이 직렬화를 사용할 수 있습니다:
@JsonSerialize(using = UserSerializer.class)
public class User {
private String name;
private int age;
// getters and setters
}
이렇게 하면, User 객체가 직렬화될 때 age 필드의 값이 18세 이상일 경우 실제 나이를, 그렇지 않을 경우 “미성년자”라는 문자열로 직렬화됩니다.
4. 사용자 정의 역직렬화
역직렬화 또한 사용자 정의가 가능합니다. 이를 위해 Jackson의 JsonDeserializer 클래스를 확장하여 구현할 수 있습니다. 사용자 정의 역직렬화를 통해 JSON 데이터를 Java 객체로 변환할 때 특정 로직을 추가할 수 있습니다.
예를 들어, JSON 데이터에서 age 필드가 “미성년자”일 경우, User 객체의 age 필드를 17로 설정하고 싶다고 가정해 보겠습니다. 이 경우 다음과 같이 JsonDeserializer를 구현할 수 있습니다:
public class UserDeserializer extends JsonDeserializer {
@Override
public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonParser);
String name = node.get("name").asText();
String ageStr = node.get("age").asText();
int age = "미성년자".equals(ageStr) ? 17 : node.get("age").asInt();
return new User(name, age);
}
}
이제 User 클래스에 @JsonDeserialize 어노테이션을 추가하여 이 역직렬화를 사용할 수 있습니다:
@JsonDeserialize(using = UserDeserializer.class)
public class User {
private String name;
private int age;
// getters and setters
}
이렇게 하면, JSON 데이터에서 age 필드가 “미성년자”일 경우, User 객체의 age 필드는 17로 설정됩니다.
5. 복잡한 객체의 직렬화 및 역직렬화
복잡한 객체를 직렬화하고 역직렬화할 때는 여러 개의 필드와 중첩된 객체가 포함될 수 있습니다. 이 경우에도 사용자 정의 직렬화 및 역직렬화를 통해 원하는 방식으로 데이터를 처리할 수 있습니다.
예를 들어, User 클래스에 Address 클래스를 포함시키고 싶다고 가정해 보겠습니다:
public class Address {
private String city;
private String street;
// getters and setters
}
public class User {
private String name;
private int age;
private Address address;
// getters and setters
}
이제 Address 객체를 포함한 User 객체를 직렬화하고 역직렬화할 때, Address 클래스에 대한 사용자 정의 직렬화 및 역직렬화를 구현할 수 있습니다.
public class AddressSerializer extends JsonSerializer {
@Override
public void serialize(Address address, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("city", address.getCity());
jsonGenerator.writeStringField("street", address.getStreet());
jsonGenerator.writeEndObject();
}
}
public class AddressDeserializer extends JsonDeserializer {
@Override
public Address deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonParser);
String city = node.get("city").asText();
String street = node.get("street").asText();
return new Address(city, street);
}
}
User 클래스에서 Address 필드에 대한 직렬화 및 역직렬화를 설정하면 됩니다:
@JsonSerialize(using = AddressSerializer.class)
private Address address;
@JsonDeserialize(using = AddressDeserializer.class)
private Address address;
이렇게 하면, 복잡한 객체도 사용자 정의 방식으로 직렬화 및 역직렬화할 수 있습니다.
6. JSON 필드 이름 변경
때때로 JSON 데이터의 필드 이름이 Java 객체의 필드 이름과 다를 수 있습니다. 이 경우 @JsonProperty 어노테이션을 사용하여 필드 이름을 매핑할 수 있습니다.
예를 들어, JSON 데이터에서 “full_name”이라는 필드를 “name”이라는 Java 필드로 매핑하고 싶다고 가정해 보겠습니다:
public class User {
@JsonProperty("full_name")
private String name;
private int age;
// getters and setters
}
이렇게 하면, JSON 데이터에서 “full_name”이라는 필드가 자동으로 “name” 필드로 매핑됩니다. 이는 API와 클라이언트 간의 데이터 일관성을 유지하는 데 매우 유용합니다.
7. JSON 필드 제외
특정 필드를 JSON 데이터에서 제외하고 싶을 때는 @JsonIgnore 어노테이션을 사용할 수 있습니다. 이 어노테이션을 사용하면 해당 필드는 직렬화 및 역직렬화 과정에서 무시됩니다.
예를 들어, User 클래스에서 password 필드를 제외하고 싶다고 가정해 보겠습니다:
public class User {
private String name;
private int age;
@JsonIgnore
private String password;
// getters and setters
}
이렇게 하면, password 필드는 JSON 데이터에 포함되지 않으며, 클라이언트와의 데이터 전송 시 보안성을 높일 수 있습니다.
8. 결론
Spring Boot에서 사용자 정의 데이터 직렬화 및 역직렬화 기법은 RESTful API 개발에 있어 매우 중요한 요소입니다. 기본적인 직렬화 및 역직렬화 기능 외에도 사용자 정의 직렬화 및 역직렬화를 통해 다양한 요구사항을 충족할 수 있습니다.
본 글에서는 사용자 정의 직렬화 및 역직렬화를 구현하는 방법과 복잡한 객체 처리, JSON 필드 이름 변경 및 제외 방법 등을 다루었습니다. 이러한 기법들을 활용하면 더욱 유연하고 강력한 API를 구축할 수 있습니다.
Spring Boot와 Jackson을 활용하여 데이터 직렬화 및 역직렬화를 효과적으로 관리함으로써, 개발자는 더 나은 사용자 경험을 제공할 수 있을 것입니다. 앞으로도 이러한 기법들을 활용하여 더욱 발전된 애플리케이션을 개발해 나가길 바랍니다.