제육's 휘발성 코딩
article thumbnail
반응형

 

직렬화 - 역직렬화?

직렬화 - 역직렬화 (출처 :  https://www.geeksforgeeks.org/serialization-in-java/)

직렬화(Serialization)는 자바 객체를 파일, 디비, 메모리 등 외부 시스템과 통신할 수 있도록 바이트 상태인 데이터로 변환하는 것을 의미하며, 반대로 바이트 상태인 데이터를 객체로 변환하는 것을 역직렬화(De-Serialization)라고 합니다.
 
 


외부 시스템과 통신하기 위해 바이트로 변환하는 이유는 뭘까? 

자체 메모리 위에서만 통신한다면 JVM 힙 영역에 있는 주솟값으로 객체를 주고받을 수 있다.

하지만 외부 시스템과 통신하기 위해선 주솟값은 의미 없기 때문에 실제 값을 전송하기 위한 스트림 통로와 바이트 변환이 필요하게 된다.

Primitive 타입은 실제 값을 가지고 있기 때문에 직렬화하지 않아도 된다.

 
 

Serializable 

public interface Serializable {
}

자바에선 Serializable 인터페이스를 제공하여 자바에서 객체를 직렬화 및 역직렬화를 사용할 수 있도록 제공하고 있습니다. 근데 아무런 메서드가 선언되어 있지 않네요.
 

Serializable은 마커 인터페이스다.

Serializable 인터페이스 구현 내용을 보면 메서드가 선언되어 있지 않다.

마커 인터페이스 아무 메서드도 선언되어 있지 않는 인터페이스를 의미한다.

내부적으로 Serializable 인터페이스를 구현한 클래스는 ObjectOutputStream을 통해 객체를 직렬화할 수 있다.

Serializable 인터페이스를 구현하지 않은 객체가 직렬화하려고 하면, NotSerializableException이 발생한다.


 

Serializable 사용 예제 

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.io.*;

@Slf4j
public class SerializableMain {

    public static void main(String[] args) throws IOException {
        User writeUser = new User("sasca", 10, "sasca@naver.com";
        String fileName = "test.txt";
        writeUser.saveUser(fileName);
        writeUser.readUser(fileName);
    }


    @Getter
    @Setter
    @AllArgsConstructor
    @ToString
    @NoArgsConstructor
    static class User implements Serializable {
    
        private static final long serialVersionUID = 2834067204946389274L;
        
        private String name;
        private int age;
        private String email;
        
        public void saveUser(String fileName) {
            try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {
                ObjectMapper objectMapper = new ObjectMapper();
                String userToJson = objectMapper.writeValueAsString(this);
                log.info("object to json : {}", userToJson);
                oos.writeObject(userToJson);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


        public void readUser(String fileName) {
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
                Object object = ois.readObject();
                ObjectMapper objectMapper = new ObjectMapper();
                User user = objectMapper.readValue(String.valueOf(object), User.class);
                log.info("json to object : {}", user);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


ObjectOutPutStream과 Jackson ObjectMapper 라이브러리를 이용해서 User 객체를 json형태로 파일에 저장하고,   json형태를 다시 User 객체로 역직렬화하는 예제입니다.
 

 콘솔 로그를 확인해보면 결과가 정상 출력되는 것을 볼 수 있습니다.


 

빈 생성자(@NoArgsConstructor)가 필요한 이유?
jackson 라이브러리를 사용해서 json으로 변환할 때 빈 생성자는 필수로 적용해야 합니다. 그렇지 않으면  
(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) 오류가 발생합니다.

 

serialversionuid?

serialversionuid는 Serializable 클래스를 업데이트할 때 버전 충돌을 방지하기 위해 사용됩니다. 

 

Serializable 클래스를 업데이트하면서 serialversionuid가 변경되지 않을 경우, 타입 변경, 필드명 추가 등 이전 버전에서 저장된 객체를 읽어올 때 문제가 발생할 수 있습니다. 따라서, Serializable 클래스를 업데이트할 때는 serialversionuid를 새로 생성해 주는 것이 좋습니다.
 

serialVersionUID 자동생성 하기

IntelliJ에서 간단한 설정으로 serialVersionUID를 생성할 수 있습니다. 

File > Settings > Editor > Inspections > serializable 검색

JVM languages에서 Serializable class without serialVersionUID를 클릭해 주면 Serializable 인터페이스를 구현했을 때 알림 처리를 할 수 있도록 설정할 수 있습니다. 
 

클래스 부분에 마우스 지정

위의 기능을 설정하고 클래스 위치에 마우스를 올려두면 다음과 같이 선언할 수 있도록 IDE에서 도와줍니다. 
 

serialVersionUID 자동 생성

 

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^