Programming/Java

F018 - Serializable (직렬화, 역직렬화)

osean 2021. 6. 16. 01:12
✍️ 업무λ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ Domain ν΄λž˜μŠ€μ— Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 경우λ₯Ό 봀던 κ²½ν—˜μ΄ μžˆλŠ”λ°, λ‹Ήμ‹œμ—λŠ” μ™œ κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ”μ§€ 찾아보지 μ•Šκ³  κ°œλ°œν–ˆμ—ˆλ‹€.

이번 μ‹œκ°„μ—λŠ” Serializable μΈν„°νŽ˜μ΄μŠ€λŠ” μ–΄λ–€ μš©λ„λ‘œ μ‚¬μš©ν•˜λŠ”μ§€ κ³΅λΆ€ν•΄λ³΄μž

Serializable

public class SerializableTest implements Serializable {
	...
}

사전적 μ˜λ―Έλ‘œλŠ” μ§λ ¬ν™”λΌλŠ” λœ»μ„ 가진닀. μ§λ ¬ν™”λŠ” λ¬΄μ—‡μΌκΉŒ?

λͺ¨λž˜μ‹œκ³„ μ•ˆμ— μžˆλŠ” λͺ¨λž˜λ­‰μΉ˜κ°€ 쒁은 ν†΅λ‘œλ₯Ό 톡과 ν•  λ•Œ 각각의 μ•Œκ°±μ΄λ‘œ λ‚˜λ‰˜μ–΄μ Έ μ§€λ‚˜κ°€λŠ” 것을 λ³Ό 수 μžˆλŠ”λ°, μ΄λŠ” Serializable κ³Ό λΉ„μŠ·ν•˜λ‹€κ³  μƒκ°λœλ‹€.

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ 외뢀와 데이터λ₯Ό μ£Όκ³  λ°›κΈ° μœ„ν•΄μ„œ Stream μ΄μš©ν•˜μ—¬ ν†΅μ‹ ν•˜λŠ”λ°, 이 λ•Œ Stream은 byte ν˜Ήμ€ byte[] 만 톡과 ν•  수 μžˆλ‹€κ³  λ°°μ› λ‹€.

이 말은 데이터λ₯Ό byte λ‹¨μœ„λ‘œ λ‚˜λˆ„μ–΄μ•Όλ§Œ Stream을 톡해 외뢀에 데이터λ₯Ό 전솑 ν•  수 μžˆλ‹€λŠ” 말이닀.

즉, 데이터(λͺ¨λž˜λ­‰μΉ˜)λ₯Ό 쒁은 ν†΅λ‘œ(Stream)에 μ§€λ‚˜κ°€κ²Œ ν•˜λ €λ©΄ λͺ¨λž˜ μ•Œκ°±μ΄(byte ν˜Ήμ€ byte[])둜 λ‚˜λˆ„λŠ” 과정이 ν•„μš”ν•œλ°, Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 ν•΄κ²° ν•  수 μžˆλ‹€.

πŸ“ ν˜„μž¬ λ™μž‘ 쀑인 JVMμ—μ„œ μƒˆλ‘­κ²Œ λ§Œλ“  객체λ₯Ό JVM 외뢀에 파일둜 μ €μž₯ν•΄μ•Ό ν•˜λŠ” 경우

πŸ“ μ €μž₯μž₯μΉ˜μ— μ €μž₯λ˜μ–΄ μžˆλŠ” 객체 νŒŒμΌμ„ 읽어야 ν•˜λŠ” 경우

πŸ“ λ‹€λ₯Έ μ„œλ²„μ—μ„œ μ „μ†‘ν•œ 객체 데이터λ₯Ό μ½κ±°λ‚˜, ν˜„μž¬ λ™μž‘ 쀑인 μ„œλ²„μ—μ„œ μ™ΈλΆ€ μ„œλ²„ ν˜Ήμ€ ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 객체 데이터λ₯Ό 전솑해야 ν•˜λŠ” 경우

μœ„μ˜ 경우 μ™Έμ—μ„œλ„ λ‹€μ–‘ν•œ μƒν™©μ—μ„œ μ‚¬μš©λ˜λŠ”λ°, μ΄λ ‡κ²Œ μ™ΈλΆ€λ‘œ 객체 데이터λ₯Ό μ „μ†‘ν•˜λ €κ³  ν•  λ•Œ Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ InvalidClassException μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

μ΄λŠ” κ°„λ‹¨νžˆ 예λ₯Ό λ“€λ©΄ Stream을 ν†΅κ³Όν•˜λ €κ³  ν•˜λŠ” 데이터가 Stream μž…κ΅¬μ— λ§žμ§€ μ•Šμ•„ 톡과λ₯Ό λͺ»ν•˜λŠ” 것이닀.

SerialVersionUID - μ—­μ§λ ¬ν™”μ˜ 쑰건

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

    private static final long serialVersionUID = 362498820763181265L;
        ...
}

Java API 내뢀에 μžˆλŠ” ν΄λž˜μŠ€λ“€μ„ μ‚΄νŽ΄λ³΄λ©΄ μ’…μ’… μœ„μ˜ μ½”λ“œμ²˜λŸΌ UIDκ°€ 멀버 ν•„λ“œλ‘œ μ„ μ–Έλ˜μ–΄ μžˆλŠ” 것을 확인 ν•  수 μžˆλ‹€. ν•΄λ‹Ή λ³€μˆ˜μ˜ μ˜λ―ΈλŠ” λ¬΄μ—‡μΌκΉŒ?

μ•„λž˜μ™€ 같은 객체이 μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

public static class SerialDto implements Serializable {
        private String name;
        private String address;
        private String phoneNumber;
        private String sex;

        public SerialDto(String name, String address, String phoneNumber, String sex) {
            super();
            this.name = name;
            this.address = address;
            this.phoneNumber = phoneNumber;
            this.sex = sex;
        }

        @Override
        public String toString() {
            return "이름 : " + name + " / μ£Όμ†Œ : " + address + " / μ „ν™”λ²ˆν˜Έ : " + phoneNumber + " / 성별 : " + sex;
        }
    }

ν•΄λ‹Ή κ°μ²΄λŠ” Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν–ˆκΈ° λ•Œλ¬Έμ— μ •μƒμ μœΌλ‘œ JVM 외뢀에 데이터λ₯Ό μ“°κ±°λ‚˜ λ™μΌν•œ 객체 데이터λ₯Ό μ½μ–΄μ˜¬ 수 μžˆλ‹€.

그런데 λ§Œμ•½ μ™ΈλΆ€μ—μ„œ μ½μ–΄μ˜¨ SerialDto 클래슀의 멀버 λ³€μˆ˜κ°€ ν˜„μž¬ μˆ˜ν–‰ 쀑인 JVM에 μ‘΄μž¬ν•˜λŠ” SerialDto 클래슀의 멀버 λ³€μˆ˜κ°€ λ‹€λ₯΄λ‹€λ©΄ μ–΄λ–»κ²Œ 될까?

이 λ•Œ, μ‚¬λžŒμ˜ μž…μž₯μ—μ„œλŠ” 멀버 ν•„λ“œκ°€ 쑰금 λ‹€λ₯΄κΈ°λŠ” ν•˜μ§€λ§Œ 같은 SerialDto이닀. ν•˜μ§€λ§Œ JVM μž…μž₯μ—μ„œλŠ” 멀버 ν•„λ“œκ°€ λ‹€λ₯΄κΈ° λ•Œλ¬Έμ— μ „ν˜€ λ‹€λ₯Έ 객체둜 μΈμ‹ν•œλ‹€.
μ΄λŠ” λ³€μˆ˜μ˜ μΆ”κ°€λ‚˜ λ³€κ²½ λ“±μ˜ μž‘μ—…μ΄ μ§„ν–‰λ˜λ©΄ serialVersionUID의 값이 μžλ™μœΌλ‘œ λ³€κ²½λ˜κΈ° λ•Œλ¬Έμ— 같은 객체둜 μΈμ‹ν•˜μ§€ λͺ»ν•˜λŠ” 것이닀.

μ΄λ ‡κ²Œ 변경이 자주 μΌμ–΄λ‚˜λŠ” κ²½μš°μ— λ°œμƒν•˜λŠ” 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œ serialVersionUID λ³€μˆ˜λ₯Ό 멀버 ν•„λ“œλ‘œ μ„ μ–Έν•œλ‹€.

public static class SerialDto implements Serializable {
                final static long serialVersionUID = 1L;

        private String name;
        private String address;
        private String phoneNumber;
        private String sex;

                ...
}

μ΄λ ‡κ²Œ 클래슀의 멀버 ν•„λ“œλ‘œ serialVersionUID λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜λ©΄ λ³€μˆ˜μ˜ μΆ”κ°€λ‚˜ λ³€κ²½ 등에 영ν–₯ 받지 μ•Šκ³  같은 객체둜 인식 ν•  수 있게 λœλ‹€.

trasient

직렬화 된 객체 쀑 νŠΉμ • 멀버 ν•„λ“œλŠ” μ œμ™Έν•˜κ³  μ €μž₯ν•˜μ—¬ μ™ΈλΆ€μ—μ„œ ν•΄λ‹Ή 객체λ₯Ό 역직렬화 ν•  λ•Œ μ œμ™Έλœ 멀버 ν•„λ“œλŠ” 확인 ν•  수 μ—†κ²Œ κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ μ‘΄μž¬ν•œλ‹€.

μ΄λŸ¬ν•œ κ²½μš°μ—λŠ” 멀버 ν•„λ“œμ— ν•œν•΄ transient μ˜ˆμ•½μ–΄λ₯Ό μ„ μ–Έν•΄μ£Όλ©΄ ν•΄λ‹Ή 멀버 ν•„λ“œλŠ” 객체 μ§λ ¬ν™”μ—μ„œ μ œμ™Έλœλ‹€.

private transient String nickname;

직렬화λ₯Ό μ‚¬μš©ν•˜λŠ” 이유?

μ§λ ¬ν™”μ˜ λ°©λ²•μ—λŠ” λ¬Έμžμ—΄ 직렬화(csv, json)와 이진 직렬화 그리고 Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ΄μš©ν•œ 직렬화 방법이 μžˆλ‹€.
μœ„μ˜ 방법 쀑 상황에 맞게 μ‚¬μš©ν•˜λ©΄ λ˜μ§€λ§Œ, Java ν”„λ‘œκ·Έλž˜λ°μ—μ„œ μ™œ ꡳ이 Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ„œ μ‚¬μš©ν•˜λŠ”κ±ΈκΉŒ?

πŸ“ Java μ‹œμŠ€ν…œμ— μ΅œμ ν™”λ˜μ–΄ μžˆλŠ” ꡬ쑰
→ λ³„λ„μ˜ μž‘μ—…μ—†μ΄ 멀버 ν•„λ“œμ˜ νƒ€μž…μ„ μ•Œμ•„μ„œ 맀핑해주기 λ•Œλ¬Έμ— μ‹ κ²½ 써야 ν•˜λŠ” 뢀뢄이 쀄어든닀.

πŸ“ λ•Œλ¬Έμ— 역직렬화λ₯Ό μˆ˜ν–‰ν•˜κ³  λ°”λ‘œ 객체의 λ‚΄λΆ€ 데이터에 μ ‘κ·Ό ν•  수 μžˆλ‹€.
ν•˜μ§€λ§Œ SerialVersionUID 값을 λͺ¨λ“  객체에 λŒ€ν•΄ κ°œλ°œμžκ°€ 일일히 μž‘μ—…ν•΄μ€˜μ•Ό ν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ΄ μ‘΄μž¬ν•œλ‹€.

πŸ“ 이둜 인해 λ³„λ„λ‘œ SUIDλ₯Ό μ§€μ •ν•˜μ§€ μ•Šμ€ κ°μ²΄λŠ” ν•΄λ‹Ή 객체의 λ‚΄λΆ€ ꡬ쑰가 변경될 경우 μ‚¬μš© ν•  수 μ—†κ²Œ λœλ‹€.

μ΄λŸ¬ν•œ μ§λ ¬ν™”λŠ” JVM λ©”λͺ¨λ¦¬μ—λ§Œ μƒμ£Όν•˜κ³  μžˆλŠ” 객체 데이터λ₯Ό κ·ΈλŒ€λ‘œ μ˜μ†ν™”κ°€ ν•„μš”ν•  λ•Œ μ‚¬μš©λ˜λŠ”λ°QueryDSL 기술이 λ– μ˜€λ₯Έλ‹€.
μ΄λŠ” μ‹œμŠ€ν…œμ΄ μ’…λ£Œλ˜λ”λΌλ„ 객체 데이터가 없어지지 μ•ŠλŠ” μž₯점을 κ°€μ§€λŠ”λ°, 덕뢄에 λ„€νŠΈμ›Œν¬λ‘œμ˜ 전솑도 κ°€λŠ₯해진닀.


μ°Έκ³  μ‚¬μ΄νŠΈ

 

μžλ°” 직렬화, 그것이 μ•Œκ³ μ‹Άλ‹€. ν›‘μ–΄λ³΄κΈ°νŽΈ - μš°μ•„ν•œν˜•μ œλ“€ 기술 λΈ”λ‘œκ·Έ

μžλ°”μ˜ 직렬화 κΈ°μˆ μ— λŒ€ν•œ λŒ€ν•œ μ΄μ•ΌκΈ°μž…λ‹ˆλ‹€. κ°„λ‹¨ν•œ 질문과 λ‹΅λ³€ ν˜•νƒœλ‘œ μžλ°” 직렬화에 λŒ€ν•œ κ°„λ‹¨ν•œ μ„€λͺ…κ³Ό 직접 ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ κ²ͺ은 κ²½ν—˜μ— λŒ€ν•΄ 이야기해보렀 ν•©λ‹ˆλ‹€.

woowabros.github.io

 

 

μžλ°” 직렬화, 그것이 μ•Œκ³ μ‹Άλ‹€. μ‹€λ¬΄νŽΈ - μš°μ•„ν•œν˜•μ œλ“€ 기술 λΈ”λ‘œκ·Έ

μžλ°”μ˜ 직렬화 κΈ°μˆ μ— λŒ€ν•œ λŒ€ν•œ 두 번째 μ΄μ•ΌκΈ°μž…λ‹ˆλ‹€.μ‹€μ œ μžλ°” 직렬화λ₯Ό 싀무에 μ μš©ν•΄λ³΄λ©΄μ„œ μ£Όμ˜ν•΄μ•Ό ν•  뢀뢄에 λŒ€ν•΄ μ΄μ•ΌκΈ°ν•΄λ³΄λ €κ³ ν•©λ‹ˆλ‹€.

woowabros.github.io