private ์์ฑ์๋ ์ด๊ฑฐ ํ์ ์ผ๋ก ์ฑ๊ธํด์์ ๋ณด์ฆํ๋ผ
- ์๋ฐ ์์คํ ๋ด๋ถ์์ ์ฌ์ฉ๋๋ ๊ฐ์ฒด ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ถ์ ์๋ฐ ์์คํ ์์๋ ์ฌ์ฉํ ์ ์๋๋ก ๋ฐ์ดํธ(byte) ํํ๋ก ํ ์ดํฐ ๋ณํํ๋ ๊ธฐ์ ๊ณผ ๋ฐ์ดํธ๋ก ๋ณํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ฒด๋ก ๋ณํํ๋ ๊ธฐ์ (์ญ์ง๋ ฌํ)๋ฅผ ํต์นญํ๋ ๋ง์ ์๋ฏธํ๋ค.
- ๋์ ์๋ฆฌ๋ฅผ ๋งํ์๋ฉด ๋ฐํ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ(ํ) ์ ์์ฃผํ๊ณ ์๋ ๊ฐ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํธ ํํ๋ก ๋ณํํ๋ ๊ธฐ์ ๊ณผ ๋ฐ์ดํธ ํํ์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ฒด๋ก ๋ณํํด ๋ฐํ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์์ฃผ์ํค๋ ๊ธฐ์ ์ ์๋ฏธํ๋ค.
์ฐธ๊ณ ) DB์ Serializable๊ณผ์ ์ฐจ์ด์ ์? DB์ Serializable์ ์ฌ๋ฌ๊ฐ์ ํธ๋์ญ์ ์ด ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ์ ๊ทผํ ๋ ํธ๋์ญ์ ์ ๊ฒฐ๊ณผ๊ฐ ๋ง์น ํ๋์ฉ ์ฒ๋ฆฌ๋ ๊ฒ์ฒ๋ผ ๋์ค๋ ๊ฒฉ๋ฆฌ ์์ค์ ์๋ฏธํ๋ค. ์ผ๋ ฌ๋ก ํ๋์ฉ ์ฒ๋ฆฌ๋ ๊ฒ์ฒ๋ผ ๋์ค๋ ํ์์ ์๋ฏธ๊ฐ ํฌ๋ค. ๋จ์ ์ ๋์์ ์ฌ๋ฌ ํธ๋์ญ์ ์ ์ฒ๋ฆฌํ ์ ์์ผ๋ ์ฑ๋ฅ ์ด์๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฉฐ ์ฐ๊ธฐ๊ฐ ๋ถ๊ฐ๋ฅํ๋ค.
/*
* ์๋ฐ ์ง๋ ฌํ : ObjectOutputStream์ ์ด์ฉํ๋ค
*/
Account account = Account.of("jack", "010-7720-7954", 28);
byte[] serializedAccount;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(account);
serializedAccount = baos.toByteArray();
// ๋ฐ์ดํธ๋ก ๋ณํ๋ (์ง๋ ฌํ๋) ๊ฒฐ๊ณผ๋ฅผ String์ผ๋ก ์ธ์ฝ๋ฉ
System.out.println(Base64.getEncoder().encodeToString(serializedAccount));
}
} catch (IOException e) {
e.printStackTrace();
}- ์ง๋ ฌํ ๋์์ด ๋ ๊ฐ์ฒด์ ํด๋์ค๊ฐ ํด๋์ค ํจ์ค์ ์กด์ฌํด์ผ ํ๋ฉฐ import ๋์ด ์์ด์ผ ํ๋ค.
- ์๋ฐ ์ง๋ ฌํ ๋์ ๊ฐ์ฒด๋ ๋์ผํ serialVersionUID๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ค.
// seialVersionUID
private static final long serialVersionUID = 1L; /*
* ์๋ฐ ์ญ์ง๋ ฌํ : ObjectInputStream์ ์ด์ฉํ๋ค.
*/
try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedAccount)) {
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
Object objectAccount = ois.readObject();
Account accountFromSerialized = (Account) objectAccount;
System.out.println(accountFromSerialized);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}- ์ง๋ ฌํ ๋ฐฉ๋ฒ์ ๋ค์ํ๋ค. ์๋ฐ ๊ฐ์ฒด๋ฅผ CSV, XML, JSON์ผ๋ก ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ๋ ์ง๋ ฌํ ๋ฐฉ๋ฒ์ด๋ค. ๊ทธ๋ผ ๊ทธ๋ฅ JSON ํ์์ผ๋ก ์ง๋ ฌํ๋ฅผ ํด์ ์์คํ ๊ฐ ์ํต์ ํ๋ฉด ๋ ํ ๋ฐ ์ ์๋ฐ ์ง๋ ฌํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๊น?
๋ฌผ๋ก ์ฌ์ฉํด๋ ๋๋ค. ๋ชฉ์ ์ ๋ฐ๋ผ ์ ์ฌ์ฉํ๋ฉด ๋๋ค. ๊ทธ๋ผ ์๋ฐ ์ง๋ ฌํ์ ์ฅ์ ์ ์ดํด๋ณด์
- ์๋ฐ ์ง๋ ฌํ๋ ์๋ฐ ์์คํ ์์ ๊ฐ๋ฐ์ ์ต์ ํ๋์ด ์๋ค. ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ํด๋์ค๋ผ๋ ์ง๋ ฌํ๊ฐ ์ฝ๊ฒ ๊ฐ๋ฅํ๋ค.
- ์ญ์ง๋ ฌํ ์ ๊ฐ์ฒด ๋ฐ์ดํฐ์ ๊ตฌ์กฐ๊ฐ ๋ฐ๋๋ฉด ์ง๋ ฌํ๊ฐ ์คํจํ ์ ์๋ค. -> ์ง์ serialVersionUID ๊ฐ์ ๊ด๋ฆฌํด์ฃผ์ด์ผ ํด๋์ค ๋ณ๊ฒฝ ์ ํผ๋์ ์ค์ผ ์ ์๋ค. ๋ง์ฝ serialVersionUID๊ฐ ์๋ค๋ฉด ๋ด๋ถ์ ์ผ๋ก ํด๋์ค์ ๊ตฌ์กฐ์ ๋ณด๋ก ํด์ฌ๊ฐ์ด ๋ง๋ค์ด์ ธ์ serialVersionUID๋ก ์ง์ ๋๋ค. ์ฌ์ฉ์๊ฐ ์ง์ ์ง์ ํ์ง ์๊ณ ํด๋์ค ๊ตฌ์กฐ๊ฐ ๋ฐ๋๋ฉด serialVersionUID๊ฐ ๋ฐ๋๋ค.
- ์ง์ serialVersionUID๋ฅผ ๊ด๋ฆฌํ๋๋ผ๋ ๊ฐ์ฒด ํ๋์ ํ์ ์ด ๋ณ๊ฒฝ๋๋ฉด ์ญ์ง๋ ฌํ๊ฐ ์คํจํ๋ค.
์๋ฐ ์ง๋ ฌํ๊ฐ ์ฐ๋ฆฌ๋ ๋ฌด์จ ์๊ด์ผ๊น? (์ค์ํ ๊ธฐ์ ์์๋ ์ ๋ชฐ๋๋ ์ด์ ๋?)
- ๋ฐํ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์๋ง ์์ฃผํ๊ณ ์๋ ๊ฐ์ฒด ๋ฐ์ดํฐ๋ฅผ ์์ํ(Persistence)ํ ๋ ํ์ํ๋ค. ์์คํ ์ด ์ข ๋ฃ๋๋๋ผ๋ ์์ด์ง์ง ์๋ ์ฅ์ ์ด ์๊ณ ๋คํธ์ํฌ๋ก ์ฃผ๊ณ ๋ฐ์ ์๋ ์๋ค.
- ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ์คํ๋ง์์๋ ์๋ฐ ์ง๋ ฌํ๋ฅผ ์ง์ํ๊ณ ์๋ค.
@RestController์ฌ์ฉ ์ ์๋ฐ ๊ฐ์ฒด๋ฅผ JSON ํํ๋ก ๋ณํํด์ฃผ๋๋ฐ ์ด ๋ ํด๋น ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก ๋ฐ๊พธ๋ ๊ณผ์ ์๋ ์ง๋ ฌํ๊ฐ ์ผ์ด๋๋ค. (์์ธํ ๋ด์ฉ์ ๊ณต๋ถ๊ฐ ํ์..)
@RestController๋ @Controller์ @ResponseBody๊ฐ ํฉ์ณ์ ธ ์๋ค. @ResponseBody ์ด๋ ธํ ์ด์ ์ ํตํด ๋ฐํ๋๋ ๊ฐ์ฒด๊ฐ ์๋์ผ๋ก ์ง๋ ฌํ๋์ด HttpResponse์ ๋ด๊ธด๋ค.
- ์ธ๋ถ์ ์ค๋ ์๊ฐ ์ ์ฅํ๋(์์ํ) ๋ฐ์ดํฐ๋ ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ์๊ธฐ ๋๋ฌธ์ ์ง๋ ฌํ๋ฅผ ๊ตฌํํ์ง ์๋๊ฒ ์ข๋ค.
- ํด๋น ๋ฐ์ดํฐ(๊ฐ์ฒด ๋ฑ)์ ์ง๋ ฌํํ ๋ ์ ์ธํ๊ณ ์ถ์ ๊ฒฝ์ฐ ์ ์ธํ๋ ํค์๋์ด๋ค.
- ํจ์ค์๋์ ๊ฐ์ ๋ณด์์ ๋ณด๊ฐ ์ง๋ ฌํ๋๋ ๊ฒ์ ๋ง์ ๋ ์ฌ์ฉํ ์ ์๋ค.
- name ํ๋์ transient ์ถ๊ฐ
@Getter
public class Account implements Serializable {
private transient String name;
private String phoneNumber;
private int age;- Account ๊ฐ์ฒด ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํ ์งํ
public static void main(String[] args) {
/*
* ์๋ฐ ์ง๋ ฌํ : ObjectOutputStream์ ์ด์ฉํ๋ค
*/
Account account = Account.of("jack", "010-7720-7954", 28);
byte[] serializedAccount = new byte[1000];
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(account);
serializedAccount = baos.toByteArray();
// ๋ฐ์ดํธ๋ก ๋ณํ๋ (์ง๋ ฌํ๋) ๊ฒฐ๊ณผ๋ฅผ String์ผ๋ก ์ธ์ฝ๋ฉ
System.out.println(Base64.getEncoder().encodeToString(serializedAccount));
}
} catch (IOException e) {
e.printStackTrace();
}
/*
* ์๋ฐ ์ญ์ง๋ ฌํ : ObjectInputStream์ ์ด์ฉํ๋ค.
*/
try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedAccount)) {
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
Object objectAccount = ois.readObject();
Account accountFromSerialized = (Account) objectAccount;
System.out.println(accountFromSerialized);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}- transient ํ๋๊ฐ null๋ก ์ญ์ง๋ ฌํ๋๋ค.
- ์ฑ๊ธํด์ผ๋ก ๊ตฌํํ ๊ฐ์ฒด๋ฅผ ์ญ์ง๋ ฌํํ ๋ ๋ค๋ฅธ ์ธ์คํด์ค๊ฐ ๋ฐํ๋๋ ๊ฒ์ ๋ง๋ ๊ธฐ๋ฅ์ด๋ค. ๋ง์ฝ readResolve()๋ฅผ ์ฑ๊ธํด ๊ฐ์ฒด์ ๊ตฌํํ์ง ์์ผ๋ฉด ์ฑ๊ธํด์ด๋ผ๋ ์ญ์ง๋ ฌํํ ๋ ๋ค๋ฅธ ์ธ์คํด์ค๊ฐ ๋ฐํ๋๋ค.
- ์ฑ๊ธํด ๊ฐ์ฒด ์์ฑ
public class JackSingleton implements Serializable {
private static final JackSingleton INSTANCE = new JackSingleton();
public JackSingleton() {
}
public static JackSingleton getInstance() {
return INSTANCE;
}
}- Serializer ํด๋์ค ๊ตฌํ
package com.titanic.javatest.serializable;
import java.io.*;
import java.util.Base64;
public class Serializer {
public String serialize(Object object) {
/*
* ์๋ฐ ์ง๋ ฌํ : ObjectOutputStream์ ์ด์ฉํ๋ค
*/
byte[] serialized;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
serialized = baos.toByteArray();
// ๋ฐ์ดํธ๋ก ๋ณํ๋ (์ง๋ ฌํ๋) ๊ฒฐ๊ณผ๋ฅผ String์ผ๋ก ์ธ์ฝ๋ฉ
return Base64.getEncoder().encodeToString(serialized);
}
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public Object deserialize(String serialized) {
/*
* ์๋ฐ ์ญ์ง๋ ฌํ : ObjectInputStream์ ์ด์ฉํ๋ค.
*/
byte[] serializedSingleton = Base64.getDecoder().decode(serialized);
try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedSingleton)) {
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
Object objectAccount = ois.readObject();
return objectAccount;
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}- readResolveTest ๊ตฌํ
package com.titanic.javatest.serializable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class readResolveTest {
private JackSingleton jackSingleton;
private Serializer serializer;
@BeforeEach
void setUp() {
this.jackSingleton = JackSingleton.getInstance();
this.serializer = new Serializer();
}
@Test
void ์ผ๋ฐ์ง๋ ฌํ๋ฅผ_ํ
์คํธํ๋ค() throws Exception {
// when
String serialized = serializer.serialize(jackSingleton);
JackSingleton deserialized = (JackSingleton) serializer.deserialize(serialized);
// then
assertThat(deserialized).isSameAs(jackSingleton);
assertThat(deserialized).isEqualTo(jackSingleton);
}
@Test
void readResolve๋ฅผ_ํ
์คํธํ๋ค() throws Exception {
// when
String serialized = serializer.serialize(jackSingleton);
JackSingleton deserialized = (JackSingleton) serializer.deserialize(serialized);
// then
assertThat(deserialized).isSameAs(jackSingleton);
assertThat(deserialized).isEqualTo(jackSingleton);
}
}- readResove() ๊ตฌํํ ์ฑ๊ธํค ๊ฐ์ฒด
package com.titanic.javatest.serializable;
import java.io.Serializable;
public class JackSingleton implements Serializable {
private static final JackSingleton INSTANCE = new JackSingleton();
public JackSingleton() {
}
public static JackSingleton getInstance() {
return INSTANCE;
}
private Object readResolve() {
return INSTANCE;
}
}-
์ฑ๊ธํด ๊ฐ์ฒด๋ฅผ ์ญ์ง๋ ฌํํ๋ฉด ์ฑ๊ธํด ์ธ์คํด์ค์ ๋ค๋ฅด๋ค๊ณ ๋์จ๋ค.

-
readResolve()๋ฅผ ๊ตฌํํ ๊ฒฐ๊ณผ : ํ ์คํธ๋ฅผ ํต๊ณผํ๋ค

- ๋ฆฌํ๋์ ์ ์๋ฐ ์ธ์ด๊ฐ ๊ฐ์ง ํน์ง์ด๋ค. ๋ฆฌํ๋์ ์ ์๋ฐ ํ๋ก๊ทธ๋จ์ด ์๊ธฐ ์์ (๊ฐ์ฒด)์ด๋ ํ๋ก๊ทธ๋จ ๋ด ์์ฑ์ ์กฐ์ฌ,๋ถ์ํ๋๋ฐ ๋์์ฃผ๋ ๊ธฐ์ ์ด๋ค. ์๋ฅผ ๋ค์ด, ์๋ฐ ํด๋์ค๊ฐ ํด๋์ค ๋ด ๋ฉค๋ฒ ๋ณ์์ ๋ํ ์ ๋ณด์ ํด๋น ๋ฉค๋ฒ ๋ณ์๋ฅผ display(ํํ?)ํ๊ฒ ๋์์ค๋ค.
- ์ค์ฉ์ ์ธ ๋ด์ฉ์ผ๋ก๋ ์ด๋ฏธ ๋ก๋ฉ์ด ์๋ฃ๋ ํด๋์ค์์ ๋ ๋ค๋ฅธ ํด๋์ค๋ฅผ ๋์ ์ผ๋ก ๋ก๋ฉ(Dynamic Loading)ํ์ฌ ์์ฑ์, ๋ฉค๋ฒ ํ๋, ๋ฉค๋ฒ ๋ฉ์๋ ๋ฑ์ ์ฌ์ฉํ ์ ์๊ฒ ๋์์ค๋ค.
- ๋ฐ์ฌ, ํฌ์์ด๋ผ๋ ์ฌ์ ์ ์ธ ์๋ฏธ๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ ๊ฐ์ฒด(์ธ์คํด์ค)๋ฅผ ํตํด ํด๋์ค์ ์ ๋ณด๋ฅผ ๋ถ์ํด ๋ด๋ ํ๋ก๊ทธ๋จ ๊ธฐ๋ฒ์ ์๋ฏธํ๋ค.
- ๋์ ๋ก๋ฉ์ ๋ํ ๊ธฐ์ ์ ์ง์ํ๋ ์๋ฐ ํ๋ก๊ทธ๋จ์ ์ ์ฐํ๊ฒ ์ด์ํ ์ ์๋ค. (๋คํ์ฑ ๋ฑ)
- ์ธ๋ถ์ ๊ณต๊ฐ๋์ง ์๋ private ๋ฉค๋ฒ๋ ์ ๊ทผ๊ณผ ์กฐ์๋ ๊ฐ๋ฅํ๋ ์ฃผ์ํด์ผ ํ๋ค. private ๋ฉค๋ฒ๋ Field.setAccessible() ๋ฉ์๋๋ฅผ true๋ก ์ง์ ํ๋ฉด ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค๊ณ ํ๋ค.
- ๋ฐํํ๋ ์ธ์คํด์ค์ ์ฃผ์๊ฐ ๊ฐ์์ง ๋ค๋ฅธ์ง ํ์ ํ๋ฉด ๋๋ค.
- ์คํ๋ง์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๋น์ ์ฑ๊ธํด์ผ๋ก ์์ฑํ๋ค.
2. getInstance()๋ก ๊ตฌํํ ์ฑ๊ธํด์ ์ฅ์ ์ ์ธ์ ๋ ์ฑ๊ธํด์ด ์๋ ๋ค๋ฅธ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค๋ ์๋ฏธ๋?
- public static ์์๋ก ๊ตฌํํ ์ฑ๊ธํด์ ์ฑ๊ธํด ์ธ์คํด์ค ์ธ์ ๋ค๋ฅธ ์ธ์คํด์ค๋ฅผ ๋ฐ๊ฟ ๋ฐฉ๋ฒ์ด ์์ง๋ง getInstance()๋ ๋ฐํํ์ ์ ๋ฐ๊ฟ ์ ์๋ค. ์ด์ ๋ ๋ฉ์๋๋ก ๊ตฌํํ๊ธฐ ๋๋ฌธ์ ๋ก์ง์ ์ถ๊ฐํ ์ ์๋ค.
- ์ ์๋ฐ์ Serializable ๋ด์ฉ์ ์์ธํ ๊ธฐ๋ก๋์ด ์์.
- ๊ฐ์ Java ์์คํ ๊ฐ์ ๊ฐ์ฅ ์ฝ๊ฒ ๋ฐ์ดํฐ๋ฅผ ํต์ ํ ์ ์๋ ๋ฐฉ์
- ์ธ์ ์ฌ์ฉํ ๊น?
- DB์ ์์ํ ํ ๋, ์ด๋ byteStream์ผ๋ก ๋ฐ๊ฟ์ ๋ค์ด๊ฐ
- byteStream -> ์ง๋ ฌํ(์ข ๋ ๋ณต์กํ ๋ฐฉ์์ด ์์) -> DB
4. p.24 public ํ๋ ๋ฐฉ์์ ํฐ ์ฅ์ ์ ํด๋น ํด๋์ค๊ฐ ์ฑ๊ธํด์์ด API์ ๋ช ๋ฐฑํ ๋๋ฌ๋๋ค๋ ๊ฒ์ด๋ค.์ ์๋ฏธ๋?
- public ํ๋ ๋ฐฉ์์ ๋ฉ์๋๋ฅผ ํตํ์ง ์๊ณ .(dot) ์ฐ์ฐ์๋ก ๋ฐ๋ก ์ธ์คํด์ค๋ฅผ ๊ฐ์ ธ์ค๋ ๋ค๋ฅธ ๋ก์ง์ด ์ถ๊ฐ๋์ง ์๊ณ ์ธ์คํด์ค๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.


