0116 ~ 0129


# 0116 ~ 0129

# 0117 - Objects.requireNonNull

์ž๋ฐ”7์— ์ถ”๊ฐ€๋œ Object ํด๋ž˜์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ๋„(Null) ์ฒดํฌ๋ฅผ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ. ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ž…๋ ฅ๋œ ๊ฐ’์ด null์ด๋ผ๋ฉด NPE(NullPointerException)๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์ž…๋ ฅ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฉ”์†Œ๋“œ์ด๋‹ค. requireNonNull์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ธ๊ฐ€์ง€๋กœ ์˜ค๋ฒ„๋กœ๋”ฉ ๋˜์–ด์žˆ๋‹ค.

๋ฆฌํ„ดํƒ€์ž… ๋ฉ”์†Œ๋“œ
T requireNonNull(T obj)
T requireNonNull(T obj, String message)
T requireNonNull(T obj, Supplier msgSupplier)

์ฒซ๋ฒˆ์งธ ๋ฉ”์†Œ๋“œ๋Š” null์„ ์ „๋‹ฌํ•˜๋ฉด ๋ฉ”์„ธ์ง€๊ฐ€ ๋น„์–ด์žˆ๋Š” NPE ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

Objects.requireNonNull(null);
// java.lang.NullPointerException
1
2

๋‘๋ฒˆ์งธ ๋ฉ”์†Œ๋“œ๋Š” null์„ ์ „๋‹ฌํ•˜๋ฉด, ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ ๋ฌธ์ž์—ด์„ ๋ฉ”์„ธ์ง€๋กœ ๊ฐ–๋Š” NPE ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

Objects.requireNonNull(null, "null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!");
// java.lang.NullPointerException: null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!
1
2

์„ธ๋ฒˆ์งธ ๋ฉ”์†Œ๋“œ๋Š” null์„ ์ „๋‹ฌํ•˜๋ฉด, ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ Supplier ๋ฅผ ๊ตฌํ˜„ํ•œ ์ต๋ช… ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋ฉ”์„ธ์ง€๋กœ ๊ฐ–๋Š” NPE ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

Objects.requireNonNull(null, () -> "null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!");
// java.lang.NullPointerException: null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!
1
2

# [ ์‚ฌ์šฉ ์ด์œ  ]

๋น ๋ฅธ ์‹คํŒจ

null์„ ์ฐธ์กฐํ•˜์—ฌ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ requireNonNull์— null์ด ๋“ค์–ด๊ฐ€๋‚˜ ๋˜‘๊ฐ™์ด NPE๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์€ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‚˜ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๋น ๋ฅธ ์‹คํŒจ (Fail-Fast) ์ด๋‹ค. ๋””๋ฒ„๊น…์„ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ์ฆ‰๊ฐ์ ์œผ๋กœ ๊ฐ์ง€ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ๋ฌธ์ œ์˜ ์›์ธ๊ณผ ๋ฌธ์ œ์˜ ๋ฐœ์ƒ ์ง€์ ์ด ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ฉ€๋ฆฌ ๋–จ์–ด์ ธ ์žˆ๋‹ค๋ฉด ๋””๋ฒ„๊น…ํ•˜๊ธฐ ํž˜๋“ค ๊ฒƒ์ด๋‹ค.

๋ช…์‹œ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ

๋น ๋ฅธ ์‹คํŒจ๋Š” if ๋ฌธ์œผ๋กœ๋„ ์ถฉ๋ถ„ํžˆ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ˆ˜๋™์œผ๋กœ ๋„์ฒดํฌํ•œ ์ฝ”๋“œ๋ณด๋‹ค ๊ฐ€๋…์„ฑ์ด ๋” ์ข‹๊ณ , ๋ช…์‹œ์ ์ด๋‹ค.


# 0119 - Security์—์„œ hasRole, hasAuthority ์ฐจ์ด

ํ”ํžˆ Spring Securit์—์„œ ์ œ๊ณตํ•˜๋Š” ์—ญํ• (Role)๊ณผ ๊ถŒํ•œ(Authority)์„ ํ˜ผ๋™ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์€๋ฐ ๋น„์Šทํ•˜๋ฉด์„œ๋„ ๋‹ค๋ฅด๋‹ค.

  • role ๊ด€๋ จ ์„ค์ •์€ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ 4์ด์ƒ ๋ฒ„์ „๋ถ€ํ„ฐ ์ž๋™์œผ๋กœ ์ ‘๋‘์‚ฌ์— 'ROLE_'์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • authority๋Š” 'ROLE_' ์ถ”๊ฐ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • hasAuthority('ROLE_ADMIN')์™€ hasRole('ADMIN')์€ ๊ฐ™์€ ์˜๋ฏธ์ด๋‹ค.

# 0124 - self-invocation

# [ Spring AOP์˜ ๋™์ž‘ ๊ณผ์ • ]

Spring AOP๋Š” ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์œผ๋กœ IoC ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ์‹œ์ ์— AOP๋ฅผ ์ ์šฉํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜์—ฌ ํ”„๋ก์‹œ ๋นˆ์„ ์ƒ์„ฑํ•ด์ค€๋‹ค.

์ด ๊ณผ์ •์—์„œ JDK Proxy์™€ CGLIB ๋‘˜ ์ค‘์— ์„ ํƒ ํ•ด์„œ ํ”„๋ก์‹œ ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ํƒ€๊นƒ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ JDK Proxy์˜ ๋ฐฉ์‹์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ  ํƒ€๊นƒ์˜ ๊ฐ์ฒด๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์œผ๋ฉด CGLIB ๋ฐฉ์‹์œผ๋กœ ํ”„๋ก์‹œ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

์ด ํ”„๋ก์‹œ์˜ ํ•ต์‹ฌ์ ์ธ ๊ธฐ๋Šฅ์€ ์ง€์ •๋œ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ(Invocation)๋  ๋•Œ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐœ๋กœ์ฑ„์–ด ๋ถ€๊ฐ€๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

# [ Self-Invocation์ด๋ž€? ]

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted.

target object, ์ฆ‰ AOP๊ฐ€ ์ ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋™์ผํ•œ ํด๋ž˜์Šค์˜ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ self-invocation์ด๋ผ ํ•œ๋‹ค. image

# [ self-invocation ํ•ด๊ฒฐ ๋ฐฉ์•ˆ ]

  • AopContext
  • IoC ์ปจํ…Œ์ด๋„ˆ bean ํ™œ์šฉ
  • AspectJ Weaving

-> ํ—ˆ๋‚˜ ํ•ด๋‹น๋ฐฉ๋ฒ•๋“ค ๋ณด๋‹ค๋Š” ํด๋ž˜์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์ง€ํ–ฅ


# 0125 - GSON Adapter ๋“ฑ๋ก

TimeStamp <-> LocalDateTime ์œผ๋กœ ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ํ•ด์•ผ ํ•  ์ผ์ด ์ƒ๊ฒผ๋‹ค.

# [ Gson registerTypeAdapter ๋“ฑ๋ก ]

private final Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {  
    @Override  
    public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)  
            throws JsonParseException {  
        return LocalDateTime.ofInstant(Instant.parse(json.getAsString()), ZoneOffset.UTC);  
    }  
}).create();
1
2
3
4
5
6
7
import com.google.gson.*;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

@Slf4j
public class GsonUtils {
    private static String PATTERN_DATE = "yyyy-MM-dd";
    private static String PATTERN_TIME = "HH:mm:ss";
    private static String PATTERN_DATETIME = String.format("%s %s", PATTERN_DATE, PATTERN_TIME);

    private static Gson gson = new GsonBuilder()
            .disableHtmlEscaping()
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .setDateFormat(PATTERN_DATETIME)
            .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter().nullSafe())
            .registerTypeAdapter(LocalDate.class, new LocalDateAdapter().nullSafe())
            .registerTypeAdapter(LocalTime.class, new LocalTimeAdapter().nullSafe())
            .create();

    public static String toJson(Object o) {
        String result = gson.toJson(o);
        if("null".equals(result))
            return null;
        return result;
    }

    public static <T> T fromJson(String s, Class<T> clazz) {
        try {
            return gson.fromJson(s, clazz);
        } catch(JsonSyntaxException e) {
            log.error(e.getMessage());
        }
        return null;
    }
    static class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> {
        DateTimeFormatter format = DateTimeFormatter.ofPattern(PATTERN_DATETIME);

        @Override
        public void write(JsonWriter out, LocalDateTime value) throws IOException {
            if(value != null)
                out.value(value.format(format));
        }

        @Override
        public LocalDateTime read(JsonReader in) throws IOException {
            return LocalDateTime.parse(in.nextString(), format);
        }
    }

    static class LocalDateAdapter extends TypeAdapter<LocalDate> {
        DateTimeFormatter format = DateTimeFormatter.ofPattern(PATTERN_DATE);

        @Override
        public void write(JsonWriter out, LocalDate value) throws IOException {
            out.value(value.format(format));
        }

        @Override
        public LocalDate read(JsonReader in) throws IOException {
            return LocalDate.parse(in.nextString(), format);
        }
    }

    static class LocalTimeAdapter extends TypeAdapter<LocalTime> {
        DateTimeFormatter format = DateTimeFormatter.ofPattern(PATTERN_TIME);
        @Override
        public void write(JsonWriter out, LocalTime value) throws IOException {
            out.value(value.format(format));
        }

        @Override
        public LocalTime read(JsonReader in) throws IOException {
            return LocalTime.parse(in.nextString(), format);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
Last update: February 1, 2023 23:04
Contributors: jaesungahn91