Posts Spring
Post
Cancel

Spring

Java Annotation


๐Ÿ”˜ Annotation

  1. ์–ด๋…ธํ…Œ์ด์…˜์˜ ์—ญํ• ๋„ ์ฃผ์„๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋Š”๋‹ค.
  2. ์ผ๋ฐ˜์ฃผ์„๊ณผ ํฐ ์ฐจ์ด์ ์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ๋‹ค๋ฅด๋‹ค.
  3. ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์€ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋ญ”๊ฐ€๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด ๋œ๋‹ค.
  4. ์–ด๋…ธํ…Œ์ด์…˜๋„ enum๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ 1.5์— ๋“ฑ์žฅํ–ˆ๋‹ค๊ณ  ํ•œ๋‹ค.

๐Ÿ”˜ Annotation ์ข…๋ฅ˜

  1. @Retention
    • ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋‹ค๋ฃจ๋Š” ๋ฐฉ๋ฒ•์„ ๊ธฐ์ˆ ํ•˜๋ฉฐ, ํŠน์ • ์‹œ์ ๊นŒ์ง€ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š”์ง€๋ฅผ ๊ฒฐ์ •
    • RetentionPolicy.SOURCE: ์ปดํŒŒ์ผ ์ „๊นŒ์ง€๋งŒ ์œ ํšจ(์ปดํŒŒ์ผ์‹œ ์‚ฌ๋ผ์ง)
    • RetentionPolicy.CLASS: ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํด๋ž˜์Šค๋ฅผ ์ฐธ์กฐํ•  ๋•Œ๊นŒ์ง€ ์œ ํšจ(๋ฐ”์ดํŠธ์ฝ”๋“œ์—๋Š” ์กด์žฌ)
    • RetentionPolicy.RUNTIME: ์ปดํŒŒ์ผ ์ดํœด์—๋„ JVM์— ์˜ํ•ด ๊ณ„์† ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅ(๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
  2. Target
    • ์–ด๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋  ์œ„์น˜๋ฅผ ์„ ํƒ
    • ElementType.PACKAGE: ํŒจํ‚ค์ง€์— ์„ ์–ธ
    • ElementType.TYPE: ํƒ€์ž… ์„ ์–ธ
    • ElementType.ANNOTAION_TYPE: ์–ด๋…ธํ…Œ์ด์…˜ ํƒ€์ž… ์„ ์–ธ
    • ElementType.CONSTRUCTOR: ์ƒ์„ฑ์ž ์„ ์–ธ
    • ElementType.FIELD: ๋ฉค๋ฒ„ ๋ณ€์ˆ˜ ์„ ์–ธ
    • ElementType.LOCAL_VARIBALE: ์ง€์—ญ๋ณ€์ˆ˜ ์„ ์–ธ
    • ElementType.METHOD: ๋ฉ”์„œ๋“œ ์„ ์–ธ
    • ElementType.PARAMETER: ์ „๋‹ฌ์ธ์ž ์„ ์–ธ
    • ElementType.TYPE_PARAMETER: ์ „๋‹ฌ์ธ์ž ํƒ€์ž… ์„ ์–ธ
    • ElementType.TYPE_USE: ํƒ€์ž… ์„ ์–ธ
  3. Documented
    • ํ•ด๋‹น Annotation์„ JavaDoc์— ํฌํ•จ์‹œํ‚ต๋‹ˆ๋‹ค.
  4. Inherited
    • Annotaion ์ƒ์†์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  5. @Repeatable
    • Java8 ๋ถ€ํ„ฐ ์ง€์›ํ•˜๋ฉฐ ์—ฐ์†์ ์œผ๋กœ ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

๐Ÿ”˜ Annotation ์ •์˜ํ•˜๊ธฐ

โœ”๏ธ ์ •์ˆ˜ ๊ฐ’ ์ฃผ์ž…ํ•˜๊ธฐ

1
2
3
4
5
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InsertIntData {
    int data() default 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AnnotationExam01 {
    @InsertIntData(data = 30)
    private int myAge;

    @InsertIntData
    private int defaultAge;

    public AnnotationExam01() {
        this.myAge = -1;
        this.defaultAge = -1;
    }

    public int getMyAge() {
        return myAge;
    }

    public int getDefaultAge() {
        return defaultAge;
    }
}
  • myAge์— ์–ด๋…ธํ…Œ์ด์…˜์—์„œ๋Š” 30์œผ๋กœ ๊ฐ’์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • defaultAge ์—์„œ๋Š” ๊ฐ’์ด ์—†๋Š”๋ฐ ์ด ๊ฒฝ์šฐ ์–ด๋…ธํ…Œ์ด์…˜์—์„œ ์ •ํ•œ ๊ธฐ๋ณธ ๊ฐ’์ธ 0์œผ๋กœ ๊ฐ’์ด ์ฃผ์ž…์ด ๋ฉ๋‹ˆ๋‹ค.
  • ์ƒ์„ฑ์ž์˜ ๊ฒฝ์šฐ ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ -1์„ ๊ธฐ๋ณธ์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”˜ Annotation Processor

Annotation Processor๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์†Œ์Šค๋ฅผ ์กฐ์ž‘

  • Annotation Processor๊ฐ€ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ๋ชจ๋“  ์†Œ์Šค๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, ์ƒˆ๋กœ ์ž‘์„ฑ๋˜๋Š” ํŒŒ์ผ์—๋งŒ ์†Œ์Šค๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ณ  ๊ธฐ์กด์— ์žˆ๋˜ ํŒŒ์ผ๋“ค์€ ๊ฑด๋“œ๋ฆด ์ˆ˜ ์—†๋‹ค๊ณ  ํ•œ๋‹ค.
  • Lombok์€ ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

๐Ÿ”˜ Annotation Processsor ๋™์ž‘

Annotation Processor๋Š” ์—ฌ๋Ÿฌ๋ฒˆ ๋ฐ˜๋ณตํ•ด์„œ ์ˆ˜ํ–‰๋œ๋‹ค.(๋ผ์šด๋“œ์— ๊ธฐ์ดˆํ•˜์—ฌ) ๊ฐ ๋ผ์šด๋“œ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์–ด๋…ธํ…Œ์ด์…˜์„ ๊ฒ€์ƒ‰ํ•˜๊ณ , ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์— ๋งž๋Š” Processor๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ ๋ถ€ํ„ฐ ์‹œ์ž‘๋œ๋‹ค.

If any files are generated during this process, another round is started with the generated files as its input. This process continues until no new files are generated during the processing stage.

Annotation Processor ๋˜ํ•œ JVM ์œ„์—์„œ ๋Œ์•„๊ฐ€๋ฏ€๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋งŒ๋“  Processor๋ฅผ .jar ํŒŒ์ผ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ์••์ถ•ํ•  ๋•Œ META-INF/services ์•ˆ์— ์žˆ๋Š” Processor๋ฅผ ๊ฐ™์ด ์••์ถ•ํ•ด์ค˜์•ผ ํ•œ๋‹ค.(google์˜ auto-service๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•Œ์•„์„œ ํ•ด์ค€๋‹ค.)


๐Ÿ”˜ Annotation Processsor ์‚ฌ์šฉ

๋ชจ๋“  ํ”„๋กœ์„ธ์„œ๋“ค์€ AbstractProcessor๋ฅผ ์ƒ์†๋ฐ›์•„์•ผ ํ•œ๋‹ค.

โœ”๏ธ ์ถ”์ƒ๋ฉ”์„œ๋“œ process()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract boolean process(
 Set<? extends TypeElement> annotations, RoundEnvironment roundEnv
);

public synchronized void init(ProcessingEnvironment processingEnv)

public SourceVersion getSupportedSourceVersion()

public Set<String> getSupportedAnnotationTypes()

public Set<String> getSupportedOptions()

public Iterable<? extends Completion> getCompletions(...)

protected synchronized boolean isInitialized()

private Set<String> arrayToSet(...)
  • process(): ๊ฐ ํ”„๋กœ์„ธ์„œ์˜ main ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์€ ์—ญํ•  ์ด ๋ฉ”์„œ๋“œ์—์„œ ์›ํ•˜๋Š” ๋™์ž‘์„ ์ฝ”๋“œ๋กœ ์ž‘์„ฑ
  • getSupportedAnnotationTypes(): ์ฒ˜๋ฆฌํ•  Annotation์„ ๋ช…์‹œ ์ด ๋ฉ”์„œ๋“œ๋Š” Annotation์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • getSupportedSourceVersion(): ํŠน์ • ์ž๋ฐ”๋ฒ„์ „์„ ๋ช…์‹œํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Annotation์„ ๋Œ€์ฒด ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • Annotation์—์„œ๋Š” SourceVersion.latestSupported()๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ณ  ํŠน์ • ๋ฒ„์ „์„ ๋ช…์‹œํ•ด์ค˜์•ผ ํ•œ๋‹ค๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.
  • init(ProcessingEnvironment processingEnvironment): ๋ชจ๋“  Annotation Processor๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. ๋Œ€์‹  init ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ processingEnvironment์—์„œ Util์„ ์ œ๊ณตํ•œ๋‹ค.
    1. Types typeUtils = processingEnvironment.getTypeUtils();
    2. Elements elementUtils = processingEnvironment.getElementUtils();
    3. Filer filer = processingEnvironment.getFiler();
    4. Messager messager = processingEnvironment.getMessager();

๐Ÿ”˜ Poet ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

JAVA ์†Œ์Šค ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ JAVA API

โœ”๏ธ Hello World ๋งŒ๋“ค๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MethodSpec main = MethodSpec.methodBuilder("main")
    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
    .returns(void.class)
    .addParameter(String[].class, "args")
    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
    .addMethod(main)
    .build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
    .build();

javaFile.writeTo(System.out);
1
2
3
4
5
public static void main(String[] args) throws IOException {
   System.out.println( "Hello World!" );
   HelloWorldPoet poet = new HelloWorldPoet();
   poet.generatedHelloWorld();
}
  • writeTo(): ์ž…๋ ฅ๋œ PATH์— ํŒŒ์ผ์ด ์ƒ์„ฑ๋จ()

๐Ÿ”˜ Lombock

ํ‘œ์ค€์ ์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•  ์ฝ”๋“ค๋ฅด ๊ฐœ๋ฐœ์ž ๋Œ€์‹  ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • ์ปดํŒŒ์ผ ์‹œ์ ์— Annotation Processor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†Œ์Šค์ฝ”๋“œ์˜ AST(abstract syntax tree)๋ฅผ ์กฐ์ž‘ํ•œ๋‹ค.

โœ”๏ธ BUT

  1. ๊ณต๊ฐœ๋œ API๊ฐ€ ์•„๋‹Œ ์ปดํŒŒ์ผ๋Ÿฌ ๋‚ด๋ถ€ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•œ๋‹ค.
  2. Eclipse์˜ ๊ฒฝ์šฐ java agent๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํŒŒ์ผ๋Ÿฌ ํด๋ž˜์Šค๊นŒ์ง€ ์กฐ์ž‘ํ•˜์—ฌ ์‚ฌ์šฉ. ํ•ด๋‹น ํด๋ž˜์Šค๋“ค ์—ญ์‹œ ๊ณต๊ฐœ๋œ API๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ๋ฒ„์ „ ํ˜ธํ™˜์„ฑ์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

Annotation Processor ์‹ค์Šต

โœ”๏ธ Factory ๋งŒ๋“ค๊ธฐ

  1. magic Annotation ์ƒ์„ฑ
  2. AbstractProcessor๋ฅผ ์ƒ์†ํ•˜์—ฌ customProcessor๋ฅผ ์ƒ์„ฑ
  3. process(Set<> annotations, RoundEnvironment roundEnv) ์ž‘์„ฑ
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
@Override
public boolean process(
    Set<? extends TypeElemnet> annotations, 
    RoundEnvironment roundEnv ) {
        roundEnv.getElementAnnotatedWith(Magic.class);
         
        for(Element element : elements) {
            Name simpleName = element.getSimpleName();
            if(element.getKind() != ElementKind.INTERFACE) {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "ERROR");
            } else {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "name: " + simpleName);
            }
        }

        TypeElement typeElement = (TypeElement)element;
        ClassName className = ClassName.get(typeElement);

        MethodSpec pullOut = MethodSpec.methodBuilder("pullOut")
            .addModifiers(Modifier.PUBLIC);
            .returns(String.class)
            .addStatement("return $s", "Rabbits!")
            .build();

        TypeSpec MagicMoja = TypeSpec.classBuilder("MagicMoja")
            .addModifiers(Modifier.PUBLIC)
            .addSuperinterface(className)
            .addMethod(pullOut)
            .build();

        Filter filter = processsingEnv.getFilter();
        try {
            JavaFile.builder(className.packageName(), magicMoja)
                .build();
                .writeTo(filter);
        } catch(IOException e) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "ERROR");
        }

        return true;
}
  1. META-INF.services์— javax.annotation.processing.Processor์— ๋งŒ๋“  Processor์˜ ํ’€ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ ์ž…๋ ฅ(Processor๋ฅผ ๋“ฑ๋ก)
    • Processor๊ฐ€ ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋นŒ๋“œ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋นŒ๋“œํ•˜๊ณ  ์ž‘์„ฑํ•ด์•ผํ•จ
    • ์•„๋‹ˆ๋ฉด auto-Service๋ฅผ ์‚ฌ์šฉํ•˜์ž
  2. ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์— ๋งŒ๋“  Processor์˜ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•œ๋‹ค.
  3. ์†Œ์Šค์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ค€๋‹ค.
This post is licensed under CC BY 4.0 by the author.

Spring JPA 2

Java Generic