개발자입니다
[Java] 예제 소스 정리 - Reflect 본문
네이버클라우드 AIaaS 개발자 양성과정 1기/DBMS, SQL, JDBC, Servlet
[Java] 예제 소스 정리 - Reflect
끈기JK 2023. 2. 27. 20:58com.eomcs.reflect
예제 소스 정리
reflect
com.eomcs.reflect.ex01
Reflection API : 클래스 로딩
package com.eomcs.reflect.ex01;
class A {
static int i;
static void m() {
i = 100;
System.out.println(i);
}
static {
System.out.println("A 클래스 로딩!");
}
public A() {
System.out.println("A() 생성자 호출!");
}
}
public class Exam0110 {
public static void main(String[] args) throws Exception {
// 클래스 로딩
// => 클래스가 로딩되어 있지 않을 때 다음을 수행하면 클래스가 로딩된다.
// 1) 클래스의 스태틱 멤버(변수,메서드)를 사용할 때
// 2) new 명령을 사용하여 인스턴스를 생성하려 할 때
// 3) Class.forName()을 이용하여 임의로 클래스를 로딩할 때
//
// 클래스 로딩 과정에서 하는 일
// => 스태틱 변수를 준비한다.
// => 스태틱 블록을 실행한다.
// A.i = 100; // 클래스 로딩 확인!
// A.m(); // 클래스 로딩 확인!
// new A(); // 클래스 로딩 확인!
// new A(); // 클래스는 중복으로 로딩되지 않는다.
// Class.forName("com.eomcs.reflect.ex01.A");
// 파라미터로 패키지명을 포함한 전체 클래스 이름을 지정해야 한다.
// 패키지명을 포함한 전체 클래스 이름
// = fully qualified class name
// = FQName
// = QName
// A obj = null; // 레퍼런스 선언은 클래스 로딩과 상관 없다.
// A[] arr; // 배열 레퍼런스 선언도 클래스 로딩과 상관 없다.
// arr = new A[100]; // 레퍼런스 배열도 마찬가지로 클래스 로딩과 상관없다.
System.out.println("실행 했음!");
}
}
Reflection API : 중첩 클래스 로딩
package com.eomcs.reflect.ex01;
class B {
static {
System.out.println("B 클래스 로딩됨!");
}
static class C {
static int s_var = 100;
int i_var = 200;
static void s_m() {}
void i_m() {}
static {
System.out.println("B의 중첩클래스 C 로딩됨!");
}
}
}
public class Exam0120 {
public static void main(String[] args) throws Exception {
// Class.forName("com.eomcs.reflect.ex01.B");
// => 바깥 클래스가 로딩되었다고 중첩 클래스가 자동으로 로딩되는 것은 아니다.
// Class.forName("com.eomcs.reflect.ex01.B$C");
// => 중첩 클래스는 "바깥클래스명$중첩클래스명" 형식의 이름을 갖는다.
// => 스태틱 중첩 클래스를 로딩할 때는 바깥 클래스를 로딩하지는 않는다.
// 스태틱 중첩 클래스 입장에서는 바깥 클래스가 패키지의 역할을 할 뿐이다.
// => 바깥 클래스 파일이 존재하지 않더라도 실행 오류가 발생하지 않는다.
//
// 주의!
// => 자바 코드로 중첩 클래스를 표현할 때는
// 클래스 이름에 $ 를 붙이지 않고 . 을 붙인다.
// com.eomcs.reflect.ex01.B.C obj;
// obj = new com.eomcs.reflect.ex01.B.C();
System.out.println("실행 완료!");
}
}
Reflection API : 클래스 정보를 얻는 방식 - forName()과 "class"라는 스태틱 변수
package com.eomcs.reflect.ex01;
import java.io.File;
public class Exam0210 {
static class A {
static int s_var = 100;
int i_var = 200;
static void s_m() {}
void i_m() {}
static {
System.out.println("A 클래스 로딩!");
}
}
public static void main(String[] args) throws Exception {
// 다음은 클래스를 로딩한 후 스태틱 필드를 생성하고 스태틱 블록을 실행한다.
// Class clazz = Class.forName("com.eomcs.reflect.ex01.Exam03$A");
System.out.println("-----------------------------");
// 자바의 모든 클래스는 "class"라는 특별한 스태틱 변수를 갖고 있다.
// "class" 변수에는 해당 클래스의 정보를 담은 Class 객체의 주소가 저장되어 있다.
Class clazz1 = A.class;
// 하지만 이 방식은 static {} 블록을 실행하지 않는다.
// 물론 스태틱 멤버를 사용하는 최초의 순간에는 static 블록이 실행될 것이기 때문에
// "클래스 로딩 후 스태틱 블록 실행" 명제는 지켜진다.
// 클래스 정보를 얻기 위해 A.class 처럼 class 라는 스태틱 변수를 사용하는 것이
// forName()을 호출하는 것 보다 안 좋은 이유는?
// - forName()의 파라미터는 문자열이다.
// - 즉 외부에서 문자열을 입력 받아 해당 클래스를 임의로 로딩할 수 있지만,
// "class"라는 스태틱 변수를 사용하는 것은
// 자바 소스 안에 명확히 해당 클래스를 지정(하드코딩)해야 한다.
// - 이런 방식은 다른 클래스를 로딩하려면 다시 코드를 변경해야 하는 문제가 있다.
Class clazz2 = String.class;
Class clazz3 = System.class;
Class clazz4 = File.class;
Class clazz5 = int.class;
System.out.println("실행 완료!");
}
}
Reflection API : forName() 활용
package com.eomcs.reflect.ex01;
import java.util.Scanner;
class X {
static {
System.out.println("X 클래스 로딩");
}
}
class Y {
static {
System.out.println("Y 클래스 로딩");
}
}
class Z {
static {
System.out.println("Z 클래스 로딩");
}
}
public class Exam0220 {
public static void main(String[] args) throws Exception {
Scanner keyScan = new Scanner(System.in);
System.out.println("로딩할 클래스명을 입력하시오? ");
String className = keyScan.nextLine();
keyScan.close();
// forName()은
// 이렇게 프로그램 아규먼트나 키보드 입력을 통해
// 클래스 이름을 입력 받아서 로딩할 수 있다.
Class.forName(className);
// 그러나 다음과 같이 "class" 변수를 사용하게 되면
// 코드로 이름을 고정하기 때문에 임의의 클래스를 로딩할 수 없다.
// 다른 클래스를 가져오려면 소스 코드를 변경해야 한다.
Class clazz = X.class;
}
}
Reflection API : 클래스 로딩과 인스턴스 생성
package com.eomcs.reflect.ex01;
public class Exam0310 {
static class A {
void m() {
System.out.println("Hello!");
}
}
public static void main(String[] args) throws Exception {
// 1) 일반적인 인스턴스 생성
// A obj1 = new A();
// 2) 클래스 정보를 가지고 인스턴스 생성
// => 클래스 정보를 로딩한다.
Class clazz = Class.forName("com.eomcs.reflect.ex01.Exam0310$A");
// 타입(클래스) 정보만 있다면 인스턴스 생성할 수 있다.
A obj = (A) clazz.newInstance();
obj.m();
// deprecated 메서드이다.
// 자바는 생성자를 이용하여 인스턴스를 생성할 것을 권고하고 있다.
}
}
com.eomcs.reflect.ex02
클래스 정보 추출 - 클래스 이름 알아내기
package com.eomcs.reflect.ex02;
public class Exam0110 {
static class A {}
static Object obj = new Object() {
@Override
public String toString() {
return "익명 클래스";
}
};
public static void main(String[] args) throws Exception {
//1) 패키지 멤버 클래스
Class<?> clazz = Class.forName("java.lang.String");
// '클래스의 타입 정보를 담은 객체'를 통해 클래스 정보를 추출할 수 있다.
System.out.println(clazz.getSimpleName()); // String
System.out.println(clazz.getName()); // java.lang.String
System.out.println(clazz.getCanonicalName()); // java.lang.String
System.out.println(clazz.getTypeName()); // java.lang.String
System.out.println("------------------------------------------");
//2) 중첩 클래스
Class<?> clazz2 = Class.forName("com.eomcs.reflect.ex02.Exam01$A");
// 클래스의 타입 객체를 통해 클래스 정보를 추출할 수 있다.
System.out.println(clazz2.getSimpleName()); // A
System.out.println(clazz2.getName()); // com.eomcs.reflect.ex02.Exam01$A
System.out.println(clazz2.getCanonicalName()); // com.eomcs.reflect.ex02.Exam01.A
System.out.println(clazz2.getTypeName()); // com.eomcs.reflect.ex02.Exam01$A
System.out.println("------------------------------------------");
//3) 익명 클래스
Class<?> clazz3 = obj.getClass(); // 익명 클래스의 인스턴스로부터 클래스 정보 추출
// 클래스의 타입 객체를 통해 클래스 정보를 추출할 수 있다.
System.out.println(clazz3.getSimpleName()); //
System.out.println(clazz3.getName()); // com.eomcs.reflect.ex02.Exam01$1
System.out.println(clazz3.getCanonicalName()); // null
System.out.println(clazz3.getTypeName()); // com.eomcs.reflect.ex02.Exam01$1
}
}
클래스 정보 추출 - 배열의 이름
package com.eomcs.reflect.ex02;
import java.sql.Date;
import java.util.ArrayList;
public class Exam0120 {
public static void main(String[] args) throws Exception {
System.out.println(byte.class.getName()); // byte 타입
System.out.println(byte[].class.getName()); // byte 배열 타입
System.out.println("---------------------------");
System.out.println(short.class.getName());
System.out.println(short[].class.getName());
System.out.println("---------------------------");
System.out.println(int.class.getName());
System.out.println(int[].class.getName());
System.out.println("---------------------------");
System.out.println(long.class.getName());
System.out.println(long[].class.getName());
System.out.println("---------------------------");
System.out.println(float.class.getName());
System.out.println(float[].class.getName());
System.out.println("---------------------------");
System.out.println(double.class.getName());
System.out.println(double[].class.getName());
System.out.println("---------------------------");
System.out.println(boolean.class.getName());
System.out.println(boolean[].class.getName());
System.out.println("---------------------------");
System.out.println(char.class.getName());
System.out.println(char[].class.getName());
System.out.println("---------------------------");
System.out.println(String.class.getName());
System.out.println(String[].class.getName());
System.out.println("---------------------------");
System.out.println(Date.class.getName());
System.out.println(Date[].class.getName());
System.out.println("---------------------------");
System.out.println(ArrayList.class.getName());
System.out.println(ArrayList[].class.getName());
System.out.println("---------------------------");
}
}
결과
byte
[B
---------------------------
short
[S
---------------------------
int
[I
---------------------------
long
[J
---------------------------
float
[F
---------------------------
double
[D
---------------------------
boolean
[Z
---------------------------
char
[C
---------------------------
java.lang.String
[Ljava.lang.String;
---------------------------
java.sql.Date
[Ljava.sql.Date;
---------------------------
java.util.ArrayList
[Ljava.util.ArrayList;
---------------------------
클래스 정보 추출 - 배열 항목의 타입
package com.eomcs.reflect.ex02;
import java.sql.Date;
public class Exam0130 {
public static void main(String[] args) throws Exception {
// getComponentType()
// - 배열의 항목에 대한 타입 정보를 리턴한다.
// - 배열이 아니라면, 항목이 없기 때문에 리턴 값은 null이다.
//
System.out.println(byte.class.getComponentType());
System.out.println("---------------------------");
System.out.println(byte.class.getName());
System.out.println(byte[].class.getName());
System.out.println(byte[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(short.class.getName());
System.out.println(short[].class.getName());
System.out.println(short[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(int.class.getName());
System.out.println(int[].class.getName());
System.out.println(int[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(long.class.getName());
System.out.println(long[].class.getName());
System.out.println(long[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(float.class.getName());
System.out.println(float[].class.getName());
System.out.println(float[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(double.class.getName());
System.out.println(double[].class.getName());
System.out.println(double[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(boolean.class.getName());
System.out.println(boolean[].class.getName());
System.out.println(boolean[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(char.class.getName());
System.out.println(char[].class.getName());
System.out.println(char[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(String.class.getName());
System.out.println(String[].class.getName());
System.out.println(String[].class.getComponentType().getName());
System.out.println("---------------------------");
System.out.println(Date.class.getName());
System.out.println(Date[].class.getName());
System.out.println(Date[].class.getComponentType().getName());
System.out.println("---------------------------");
}
}
결과
null
---------------------------
byte
[B
byte
---------------------------
short
[S
short
---------------------------
int
[I
int
---------------------------
long
[J
long
---------------------------
float
[F
float
---------------------------
double
[D
double
---------------------------
boolean
[Z
boolean
---------------------------
char
[C
char
---------------------------
java.lang.String
[Ljava.lang.String;
java.lang.String
---------------------------
java.sql.Date
[Ljava.sql.Date;
java.sql.Date
---------------------------
클래스 정보 추출 - 컬렉션의 값 타입
package com.eomcs.reflect.ex02;
import java.util.ArrayList;
public class Exam0140 {
public static void main(String[] args) throws Exception {
ArrayList<Object> values = new ArrayList<>();
values.add(100);
values.add(100L);
values.add(3.14f);
values.add(314.55);
values.add(true);
values.add('A');
values.add("Hello");
values.add(new int[] {100, 200, 300});
values.add(new String[] {"aaa", "bbb", "ccc"});
for (Object value : values) {
printTypeInfo(value.getClass());
}
}
private static void printTypeInfo(Class<?> type) {
if (type.getName().startsWith("[")) {
System.out.printf("=> %s[]\n", type.getComponentType().getName());
} else {
System.out.printf("=> %s\n", type.getName());
}
}
}
결과
=> java.lang.Integer
=> java.lang.Long
=> java.lang.Float
=> java.lang.Double
=> java.lang.Boolean
=> java.lang.Character
=> java.lang.String
=> int[]
=> java.lang.String[]
클래스 정보 추출 - 클래스의 수퍼 클래스 정보 알아내기
package com.eomcs.reflect.ex02;
public class Exam0210 {
static class A {
}
static class B extends A {
}
static class C extends B {
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.eomcs.reflect.ex02.Exam0210$C");
// 수퍼 클래스의 타입을 알아내기
Class<?> superClazz = clazz.getSuperclass();
System.out.println(superClazz.getName());
System.out.println(superClazz.getSuperclass().getName());
}
}
결과
com.eomcs.reflect.ex02.Exam0210$B
com.eomcs.reflect.ex02.Exam0210$A
클래스 정보 추출 - 클래스의 중첩 클래스 정보 알아내기
package com.eomcs.reflect.ex02;
public class Exam0310 {
static class A {
static class B {
} // static nested class
class C {
} // non-static nested class == inner class
public void m() {
class D {
} // local class
}
public void m2() {
Object obj = new Object() {}; // anonymous class
}
public static class E {
}
public class F {
}
public interface X {
}
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.eomcs.reflect.ex02.Exam0310$A");
// public 으로 공개된 중첩 클래스 및 인터페이스 정보를 가져온다.
Class<?>[] nestedList = clazz.getClasses();
for (Class<?> nested : nestedList) {
System.out.println(nested.getName());
}
}
}
결과
com.eomcs.reflect.ex02.Exam0310$A$E
com.eomcs.reflect.ex02.Exam0310$A$F
com.eomcs.reflect.ex02.Exam0310$A$X
클래스 정보 추출 - 클래스의 중첩 클래스 정보 알아내기 II
package com.eomcs.reflect.ex02;
public class Exam0320 {
static class A {
static class B {
} // static nested class
class C {
} // non-static nested class == inner class
public void m() {
class D {
} // local class
}
public void m2() {
Object obj = new Object() {}; // anonymous class
}
public static class E {
}
public class F {
}
private class G {
}
protected class H {
}
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.eomcs.reflect.ex02.Exam0320$A");
// 접근 범위에 상관 없이 모든 중첩 클래스 및 인터페이스 정보를 가져온다.
// => 메서드 안에 정의된 로컬 클래스는 대상이 아니다.
Class<?>[] nestedList = clazz.getDeclaredClasses();
for (Class<?> nested : nestedList) {
System.out.println(nested.getName());
}
}
}
결과
com.eomcs.reflect.ex02.Exam0320$A$B
com.eomcs.reflect.ex02.Exam0320$A$C
com.eomcs.reflect.ex02.Exam0320$A$E
com.eomcs.reflect.ex02.Exam0320$A$F
com.eomcs.reflect.ex02.Exam0320$A$G
com.eomcs.reflect.ex02.Exam0320$A$H
클래스 정보 추출 - 구현 인터페이스 정보 알아내기
package com.eomcs.reflect.ex02;
public class Exam0410 {
static interface A {
}
static interface B {
}
static interface C {
}
static class D implements A, B, C {
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.eomcs.reflect.ex02.Exam0410$D");
// 해당 클래스가 구현한 인터페이스 정보를 가져온다.
Class<?>[] list = clazz.getInterfaces();
for (Class<?> c : list) {
System.out.println(c.getName());
}
}
}
결과
com.eomcs.reflect.ex02.Exam0410$A
com.eomcs.reflect.ex02.Exam0410$B
com.eomcs.reflect.ex02.Exam0410$C
클래스 정보 추출 - 패키지 정보 알아내기
package com.eomcs.reflect.ex02;
public class Exam0510 {
static interface A {
}
static interface B {
}
static interface C {
}
static class D implements A, B, C {
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.eomcs.reflect.ex02.Exam0510$D");
// 해당 클래스의 패키지 정보를 가져온다.
Package p = clazz.getPackage();
System.out.println(p.getName());
}
}
결과
com.eomcs.reflect.ex02
com.eomcs.reflect.ex03
메서드 정보 추출 - getMethod()
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0110 {
public static void m1() {}
public void m2() {}
protected void m3() {}
void m4() {}
private void m5() {}
public static void main(String[] args) {
Class<?> clazz = Exam0110.class;
// 클래스에서 메서드 정보를 추출하기
// => 해당 클래스에 선언된 public 메서드 + 상속 받은 public 메서드
Method[] list = clazz.getMethods();
for (Method m : list) {
System.out.println(m.getName());
}
}
}
결과
main
m2
m1
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
메서드 정보 추출 - getDeclaredMethods()
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0120 {
public static void m1() {}
public void m2() {}
protected void m3() {}
void m4() {}
private void m5() {}
public static void main(String[] args) {
Class<?> clazz = Exam0120.class;
// => 현재 클래스에 정의된 모든 메서드
Method[] list = clazz.getDeclaredMethods();
for (Method m : list) {
System.out.println(m.getName());
}
}
}
결과
main
m2
m1
m3
m5
m4
메서드 정보 추출 - 특정 메서드만 추출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0210 {
public static void m1() {}
public void m2() {}
protected void m3() {}
void m4() {}
private void m5() {}
public static void main(String[] args) throws Exception {
Class<?> clazz = Exam0210.class;
// 해당 클래스에 선언된 메서드와 상속 받은 메서드까지 포함하여
// 파라미터가 없는 "m3" 이름을 가진 public 메서드 추출
// Method m0 = clazz.getMethod("m3"); // public이 아니기 때문에 못 찾는다.
Method m = clazz.getMethod("m1"); // OK!
System.out.println(m.getName());
System.out.println(clazz.getMethod("toString").getName());
System.out.println("----------------------");
// => public 이 아닌 메서드를 찾고 싶다면,
m = clazz.getDeclaredMethod("m3"); // OK
System.out.println(m.getName());
// => 단 현재 클래스에 정의된 메서드를 찾는다.
// => 상속 받은 메서드는 제외한다.
System.out.println(clazz.getDeclaredMethod("toString")); // 예외 발생!
// 상속 받은 메서드는 못찾는다.
}
}
결과
m1
toString
----------------------
m3
Exception in thread "main" java.lang.NoSuchMethodException: com.eomcs.reflect.ex03.Exam0210.toString()
at java.base/java.lang.Class.getDeclaredMethod(Class.java:2675)
at com.eomcs.reflect.ex03.Exam0210.main(Exam0210.java:36)
메서드 정보 추출 - 특정 메서드만 추출 II
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0220 {
public void m1() {}
public void m2(String s) {}
public void m3(String s, int i) {}
public static void main(String[] args) throws Exception {
Class<?> clazz = Exam0220.class;
// 파라미터가 없는 메서드를 찾을 때는 파라미터의 타입 정보를 넘기지 않는다.
System.out.println(clazz.getMethod("m1").getName());
// 파라미터가 있는 메서드를 찾을 때 그 파라미터의 타입 정보를 넘겨야 한다.
// 타입정보 = 클래스 정보 = Class 객체
Class<?> parameterType = String.class;
Method m = clazz.getMethod("m2", parameterType);
System.out.println(m.getName());
// 위와 같다.
Method m2 = clazz.getMethod("m2", String.class);
System.out.println(m2.getName());
m = clazz.getMethod("m2", Class.forName("java.lang.String"));
System.out.println(m.getName());
// primitive 타입도 클래스 정보가 있다.
// int => int.class
// byte,short,int,long,float,double,boolean,char 는 비록 클래스는 아니지만,
// 일반 클래스처럼 타입 정보를 꺼낼 수 있도록 "class"라는 스태틱 변수를 제공한다.
Class<?> intType = int.class;
Class<?> stringType = String.class;
m = clazz.getMethod("m3", stringType, intType);
System.out.println(m.getName());
m = clazz.getMethod("m3", String.class, int.class);
System.out.println(m.getName());
// 메서드의 파라미터 순서를 지켜야 한다.
// m = clazz.getMethod("m3", int.class, String.class);
// System.out.println(m.getName());
System.out.println(clazz.getMethod("m3", String.class, int.class).getName());
}
}
메서드 정보 추출 - 스태틱 메서드 호출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0310 {
// 스태틱 메서드
public static void plus(int a, int b) {
System.out.printf("합계: %d\n", a + b);
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Exam0310.class;
// 스태틱 메서드 호출 방법
// Method.invoke(인스턴스, 아규먼트, ...);
//
// 1) 스태틱 메서드를 찾아 호출하기
Method m = clazz.getMethod("plus", int.class, int.class);
// => 스태틱 메서드이기 때문에 인스턴스는 지정할 필요가 없다.
m.invoke(null, 10, 20);
// => 클래스 메서드를 호출하는 일반적인 방식
Exam0310.plus(10, 20);
}
}
메서드 정보 추출 - 인스턴스 메서드 호출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0320 {
// 인스턴스 메서드
public void minus(int a, int b) {
System.out.printf("빼기: %d\n", a - b);
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Exam0320.class;
// 메서드 호출 방법
// Method.invoke(인스턴스, 아규먼트, ...);
//
// 1) 인스턴스 메서드를 찾아 호출하기
Method m = clazz.getMethod("minus", int.class, int.class);
// => 인스턴스 메서드를 호출할 때는 반드시 인스턴스 주소를 넘겨야 한다.
Exam0320 obj = new Exam0320();
m.invoke(obj, 10, 20); // 리플렉션 API를 사용하여 인스턴스 메서드 호출
// => 인스턴스 메서드를 호출하는 일반적인 방식
obj.minus(10, 20);
// => 인스턴스 주소를 넘겨주지 않으면 NullPointerException 발생!
// m.invoke(null, 10, 20);
}
}
메서드 정보 추출 - 여러 개의 파라미터를 가지는 메서드 호출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0410 {
public static void print(String name, int a, int b, int c) {
System.out.printf("==> %s: %d\n", name, (a + b + c));
}
public static void main(String[] args) throws Exception {
Method m = Exam0410.class.getMethod("print", String.class, int.class, int.class, int.class);
System.out.println(m);
// 파라미터 값을 낱개로 전달하기
m.invoke(null, "홍길동", 100, 90, 80);
// 파라미터 값을 배열에 담아서 전달할 수 있다.
m.invoke(null, new Object[] {"홍길동", 100, 100, 100});
}
}
메서드 정보 추출 - 배열 파라미터를 가지는 메서드 호출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0420 {
// 배열 파라미터
public static void print(String[] names) {
System.out.print("==> ");
for (String name : names) {
System.out.print(name + ",");
}
System.out.println();
}
public static void main(String[] args) throws Exception {
Method m = Exam0420.class.getMethod("print", String[].class);
System.out.println(m);
// 배열 파라미터인 경우 배열에 담아서 전달
m.invoke(null, (Object) new String[] {"홍길동", "임꺽정", "유관순"});
// 다음과 같이 낱개로 전달할 수 없다.
// m.invoke(null, "홍길동", "임꺽정", "유관순"); // 예외 발생!
}
}
필드 정보 추출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Exam0510 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
Class<?> clazz = Car.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.printf("%s:%s\n", f.getName(), f.getType().getName());
}
Constructor<Car> defaultConst = (Constructor<Car>) clazz.getConstructor();
Car car = defaultConst.newInstance();
// 1) private 필드는 일반적인 방식으로 접근할 수 없다.
// car.maker = "비트자동차"; // 컴파일 오류!
// 2) 다음과 같이 Reflection API를 사용하면 private 필드에 접근할 수 있다.
Field makerField = clazz.getDeclaredField("maker");
// private modifier로 선언된 필드라 하더라도
// 다음 메서드를 통해 접근 가능하도록 만들 수 있다.
makerField.setAccessible(true);
// private 필드에 값 넣기
// 가능해?
makerField.set(car, "비트자동차");
System.out.println(car);
}
}
package com.eomcs.reflect.ex03;
public class Car {
private String maker;
private String model;
private int cc;
@Override
public String toString() {
return "Car [maker=" + maker + ", model=" + model + ", cc=" + cc + "]";
}
public String getMaker() {
return maker;
}
public void setMaker(String maker) {
this.maker = maker;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getCc() {
return cc;
}
public void setCc(int cc) {
this.cc = cc;
}
}
메서드 정보 추출 - 가변 파라미터를 가지는 메서드 호출
package com.eomcs.reflect.ex03;
import java.lang.reflect.Method;
public class Exam0430 {
//가변 파라미터(varargs; variable arguments)
public static void print(String... names) {
System.out.print("==> ");
for (String name : names) {
System.out.print(name + ",");
}
System.out.println();
}
public static void main(String[] args) throws Exception {
Method m = Exam0430.class.getMethod("print", String[].class);
System.out.println(m);
// 가변 파라미터인 경우에도 배열에 담아 전달
m.invoke(null, (Object) new String[] {"홍길동", "임꺽정", "유관순"});
// 다음과 같이 낱개로 전달할 수 없다.
// m.invoke(null, "홍길동", "임꺽정", "유관순"); // 예외 발생!
}
}
com.eomcs.reflect.ex04
생성자 : 생성자 정보 가져오기
package com.eomcs.reflect.ex04;
import java.lang.reflect.Constructor;
public class Exam01 {
public Exam01() {}
public Exam01(int i) {}
public Exam01(String s, int i) {}
public static void main(String[] args) {
Class<?> clazz = Exam01.class;
// 생성자 목록 가져오기
Constructor<?>[] list = clazz.getConstructors();
for (Constructor<?> c : list) {
System.out.printf("%s(%d)\n", c.getName(), c.getParameterCount());
}
}
}
생성자 : 파라미터를 가지는 생성자 알아내기
package com.eomcs.reflect.ex04;
import java.lang.reflect.Constructor;
public class Exam02 {
public Exam02() {}
public Exam02(int i) {}
public Exam02(String s, int i) {}
public static void main(String[] args) throws Exception {
Class<?> clazz = Exam02.class;
// 파라미터가 없는 기본 생성자 가져오기
Constructor<?> c1 = clazz.getConstructor();
System.out.printf("%s(%d)\n", c1.getName(), c1.getParameterCount());
// int 값을 받는 생성자 가져오기
Constructor<?> c2 = clazz.getConstructor(int.class);
System.out.printf("%s(%d)\n", c2.getName(), c2.getParameterCount());
// String과 int 값을 순서대로 받는 생성자 가져오기
Constructor<?> c3 = clazz.getConstructor(String.class, int.class);
System.out.printf("%s(%d)\n", c3.getName(), c3.getParameterCount());
// 해당 타입의 값을 받는 생성자가 없을 때?
// => 예외 발생!
Constructor<?> c4 = clazz.getConstructor(String.class);
System.out.printf("%s(%d)\n", c4.getName(), c4.getParameterCount());
}
}
생성자 : 생성자 호출하기
package com.eomcs.reflect.ex04;
import java.lang.reflect.Constructor;
public class Exam03 {
int value;
public Exam03(int i) {
this.value = i;
}
public void print() {
System.out.printf("value=%d\n", this.value);
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Exam03.class;
// newInstance()는 객체를 생성한 후 기본 생성자를 호출한다.
// Exam03은 기본 생성자가 없기 때문에 실행 오류가 발생한다!
// Exam03 obj0 = (Exam03) clazz.newInstance(); // 실행 오류!
// 해결=> 생성자를 준비한다.
Constructor<?> c = clazz.getConstructor(int.class);
// 생성자 객체를 통해 인스턴스를 생성해야 한다.
Exam03 obj = (Exam03) c.newInstance(200);
obj.print();
}
}
com.eomcs.reflect.ex05
파라미터 - 파라미터 정보 알아내기
package com.eomcs.reflect.ex05;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class Exam0110 {
public void m1(String name, int age) {}
public void m2() {}
public void m3(File file, String name) {}
public static void main(String[] ok) {
Class<?> clazz = Exam0110.class;
// 해당 클래스에 정의된 메서드를 모두 가져온다.
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
System.out.printf("%s:\n", m.getName());
// 메서드의 파라미터 정보를 가져온다.
Parameter[] parameters = m.getParameters();
for (Parameter p : parameters) {
System.out.printf(" %s : %s\n", p.getName(), p.getType().getName());
// 파라미터의 이름은 argx 행태로 되어 있다.
// .class 파일에는 분명히 파라미터 이름이 보관되어 있지만,
// Reflection API에서는 보관된 값을 꺼낼 수 없다.
// 꺼내려면 직접 .class 파일을 읽어서 파라미터 정보를 알아내야 한다.
//
// 컴파일할 때 파라미터 이름을 Reflection API에서 꺼낼 수 있도록
// 설정해준다면, 그렇다면 원래의 파라미터 이름을 알아낼 수 있다.
// 즉 -parameters 옵션을 추가하여 컴파일하면 Reflection API로 파라미터 이름을
// 꺼낼 수 있다.
// > javac -d bin/main -encoding UTF-8 -parameters src/com/eomcs/reflect/ex05/Exam01.java
// 그런데 일반적으로 이 옵션을 붙여 컴파일 하지 않는다.
// 그럼에도불구하고 Spring Framework나 eclipse IDE에서는
// 메서드의 파라미터 이름을 정확하게 추출한다.
// 그것은 Spring 프레임워크나 eclipse IDE가
// 직접 .class 파일을 읽고 분석해서 해당 정보를 추출하기 때문이다.
//
}
}
}
}
리턴 타입
package com.eomcs.reflect.ex05;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
public class Exam0210 {
public String m1(String name, int age) {
return null;
}
public char[] m2() {
return null;
}
public ArrayList<String> m3(File file, String name) {
return null;
}
public void m4() {}
public Map<String,File> m5() {
return null;
}
public static void main(String[] ok) {
Class<?> clazz = Exam0210.class;
// 클래스에 정의된 메서드를 모두 가져온다.
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
System.out.printf("%s:\n", m.getName());
// 메서드의 리턴 타입 가져오기
Class<?> returnType = m.getReturnType();
System.out.printf(" 리턴: %s\n", returnType.getName());
}
}
}
리턴 타입 - 제네릭 타입
package com.eomcs.reflect.ex05;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Map;
public class Exam0220 {
public String m1(String name, int age) {
return null;
}
public char[] m2() {
return null;
}
public ArrayList<String> m3(File file, String name) {
return null;
}
public void m4() {}
public Map<String,File> m5() {
return null;
}
public static void main(String[] ok) {
Class<?> clazz = Exam0220.class;
// 클래스에 정의된 메서드를 모두 가져온다.
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
System.out.printf("%s:\n", m.getName());
// 메서드의 제네릭 리턴 타입 가져오기
Type returnType = m.getGenericReturnType();
System.out.printf(" 리턴: %s\n", returnType.getTypeName());
if (returnType instanceof ParameterizedType) {
Type[] actualTypes = ((ParameterizedType) returnType).getActualTypeArguments();
System.out.print(" => ");
for (Type actualType : actualTypes) {
System.out.print(actualType.getTypeName() + ", ");
}
System.out.println();
}
}
}
}
메서드의 modifier
package com.eomcs.reflect.ex05;
//어떤 클래스나 인터페이스의 스태틱 멤버를 import 할 수 있다.
import static java.lang.reflect.Modifier.FINAL;
import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.PROTECTED;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Exam0310 {
public static void main(String[] ok) {
Class<?> clazz = String.class;
// 클래스에 정의된 메서드를 모두 가져온다.
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
System.out.printf("%s() => ", m.getName());
int modifiers = m.getModifiers();
if (Modifier.isPublic(modifiers))//(modifiers & Modifier.PUBLIC) == Modifier.PUBLIC)
System.out.print(" public");
else if ((modifiers & PROTECTED) != 0)
System.out.print(" protected");
else if ((modifiers & PRIVATE) != 0)
System.out.print(" private");
//if ((modifiers & STATIC) != 0)
if (Modifier.isStatic(modifiers))
System.out.print(" static");
if ((modifiers & FINAL) != 0)
System.out.print(" final");
System.out.println();
}
}
}
메서드가 실제 정의된 클래스 알아내기
package com.eomcs.reflect.ex05;
import java.io.BufferedReader;
import java.lang.reflect.Method;
public class Exam0410 {
public static void main(String[] ok) {
Class<?> clazz = BufferedReader.class;
// 수퍼 클래스의 메서드를 포함하여 모든 public 메서드를 알아낸다.
Method[] methods = clazz.getMethods();
for (Method m : methods) {
// 메서드가 실제 정의된 클래스의 이름 출력하기
System.out.printf("%s.%s()\n",
m.getDeclaringClass().getSimpleName(),
m.getName());
}
}
}
com.eomcs.reflect.ex06
Proxy 객체를 만드는 방법
package com.eomcs.reflect.ex06.a;
import java.lang.reflect.Proxy;
// Proxy 객체를 만드는 방법
public class Exam0110 {
public static void main(String[] args) {
MyInterface obj = (MyInterface) Proxy.newProxyInstance(
Exam0110.class.getClassLoader(), // 클래스를 메모리에 로딩하는 일을 할 객체
new Class[] {MyInterface.class}, // 자동 생성할 클래스가 구현해야 하는 인터페이스 목록
new MyInvocationHandler());
// 자동 생성된 인터페이스 구현체의 메서드 호출하기
obj.m1();
obj.m2();
}
}
package com.eomcs.reflect.ex06.a;
public interface MyInterface {
void m1();
void m2();
}
package com.eomcs.reflect.ex06.a;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("호출됨!");
return null;
}
}
호출되는 메서드를 알아내는 방법
package com.eomcs.reflect.ex06.b;
import java.lang.reflect.Proxy;
// 호출되는 메서드를 알아내는 방법
public class Exam0110 {
public static void main(String[] args) {
MyInterface obj = (MyInterface) Proxy.newProxyInstance(//
Exam0110.class.getClassLoader(), // 클래스를 메모리에 로딩하는 일을 할 객체
new Class[] {MyInterface.class}, // 자동 생성할 클래스가 구현해야 하는 인터페이스 목록
new MyInvocationHandler());
obj.m1();
obj.m2();
}
}
package com.eomcs.reflect.ex06.b;
public interface MyInterface {
void m1();
void m2();
}
package com.eomcs.reflect.ex06.b;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("%s()가 호출됨!\n", method.getName());
System.out.println(args);
return null;
}
}
값을 리턴하는 방법
package com.eomcs.reflect.ex06.c;
import java.lang.reflect.Proxy;
// 값을 리턴하는 방법
public class Exam0110 {
public static void main(String[] args) {
MyInterface obj = (MyInterface) Proxy.newProxyInstance(//
Exam0110.class.getClassLoader(), // 클래스를 메모리에 로딩하는 일을 할 객체
new Class[] {MyInterface.class}, // 자동 생성할 클래스가 구현해야 하는 인터페이스 목록
new MyInvocationHandler());
System.out.println(obj.m1());
System.out.println(obj.m2());
obj.m3();
}
}
package com.eomcs.reflect.ex06.c;
public interface MyInterface {
int m1();
String m2();
void m3();
}
package com.eomcs.reflect.ex06.c;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "m1":
return 100; // 다음과 같이 auto-boxing => Integer.valueOf(100)
case "m2":
return "Hello!";
}
return null;
}
}
값을 리턴하는 방법
package com.eomcs.reflect.ex06.d;
import java.lang.reflect.Proxy;
// 값을 리턴하는 방법
public class Exam0110 {
public static void main(String[] args) {
MyInterface obj = (MyInterface) Proxy.newProxyInstance(//
Exam0110.class.getClassLoader(), // 클래스를 메모리에 로딩하는 일을 할 객체
new Class[] {MyInterface.class}, // 자동 생성할 클래스가 구현해야 하는 인터페이스 목록
new MyInvocationHandler());
System.out.println(obj.m1(100, 200));
System.out.println(obj.m2("홍길동", 20));
}
}
package com.eomcs.reflect.ex06.d;
public interface MyInterface {
int m1(int p1, int p2);
String m2(String name, int age);
}
package com.eomcs.reflect.ex06.d;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "m1":
int p1 = (int) args[0];
int p2 = (int) args[1];
return p1 + p2;
case "m2":
String name = (String) args[0];
int age = (int) args[1];
return name + "님은 나이는 " + age + "살 입니다.";
}
return null;
}
}
인터페이스 구현체를 자동으로 생성하기
package com.eomcs.reflect.ex06.e;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Exam0110 {
public static void main(String[] args) {
// java.lang.reflect.Proxy
// => 인터페이스 구현체를 만드는 역할을 한다.
//
// newProxyInstance(
// 만든 인터페이스 구현체를 메모리에 로딩하는 일을 도와줄 클래스로더,
// 구현할 인터페이스 정보 목록,
// 실제 작업을 수행하는 객체)
// => 파라미터로 넘겨 받은 인터페이스를 모두 구현한 클래스를 만들고 인스턴스를 생성해 리턴한다.
//
// 클래스 로더
// => 클래스 정보를 로딩하는 역할을 수행한다.
// => 클래스 로더를 얻는 방법
// - 클래스정보.getClassLoader()
// => 클래스 정보
// - 인스턴스.getClass()
// - 클래스명.class
// - Class.forName("패키지명을 포함한 클래스명")
//
// 클래스 정보를 얻는 방법 예:
/*
String s = "hello";
Class<?> c1 = String.class; // 클래스의 static 변수인 class의 값을 사용할 수 있다.
Class<?> c2 = s.getClass(); // 인스턴스로 알아낼 수 있다.
Class<?> c3 = Class.forName("java.lang.String"); // 클래스 정보를 리턴하는 도구를 이용.
*/
//
// 실제 작업을 수행하는 객체
// => java.lang.reflect.InvocationHandler 인터페이스에 따라 동작하는 객체
// => 즉 InvocationHandler 구현체
//
// 1) 로컬 클래스
class MyHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke()...호출됨!");
// newProxyInstance()가 생성한 객체에 대해 메서드를 호출할 때마다 이 메서드가 호출된다.
int a = (int) args[0]; // auto-unboxing => ((Integer)args[0]).intValue();
int b = (int) args[1]; // auto-unboxing => ((Integer)args[1]).intValue();
switch (method.getName()) {
case "plus":
return a + b;
case "minus":
return a - b;
}
return 0;
}
}
// Calculator 인터페이스를 구현한 클래스를 만들고 그 인스턴스를 생성하여 리턴한다.
Calculator c1 = (Calculator) Proxy.newProxyInstance(
Calculator.class.getClassLoader(),
new Class[] {Calculator.class},
new MyHandler());
System.out.println("++++");
System.out.println(c1.plus(10, 20));
System.out.println("----");
System.out.println(c1.minus(10, 20));
}
}
package com.eomcs.reflect.ex06.e;
public interface Calculator {
int plus(int a, int b);
int minus(int a, int b);
}
여러 개의 인터페이스를 구현한 객체를 자동 생성하기
package com.eomcs.reflect.ex06.e;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Exam0120 {
public static void main(String[] args) {
// Calculator, Calculator2, Calculator3 인터페이스를 구현한
// 클래스를 만들고 그 인스턴스를 생성하여 리턴한다.
Object proxy = Proxy.newProxyInstance(
Exam0120.class.getClassLoader(),
new Class[] {
Calculator.class,
Calculator2.class,
Calculator3.class},
// 2) 익명 클래스를 문법을 이용하여 InvocationHandler 구현하기
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// newProxyInstance()가 생성한 객체에 대해 메서드를 호출할 때마다 이 메서드가 호출된다.
int a = (int) args[0]; // auto-unboxing => ((Integer)args[0]).intValue();
int b = (int) args[1]; // auto-unboxing => ((Integer)args[1]).intValue();
switch (method.getName()) {
case "plus":
return a + b;
case "minus":
return a - b;
case "multiple":
return a * b;
case "divide":
return a / b;
case "mod":
return a % b;
}
return 0;
}
});
// 자동 생성된 인터페이스 구현체를 사용하기
// 1) Object 레퍼런스로 바로 사용하기
// => 비록 proxy 레퍼런스가 가리키는 객체가 Calculator, Calculator2, Calculator3 인터페이스를
// 구현한 클래스일지라도
// 일단 proxy 레퍼런스의 타입이 Object 이기 때문에
// 바로 인터페이스의 메서드를 호출할 수 없다.
// => 해결책?
// 레퍼런스를 바로 사용하지 말고 해당 인터페이스로 형변환 한 다음에 사용하라!
//
// int result = 0;
// result = proxy.plus(10, 20); // 컴파일 오류!
// result = proxy.minus(10, 20); // 컴파일 오류!
// result = proxy.multiple(10, 20); // 컴파일 오류!
// result = proxy.divide(10, 20); // 컴파일 오류!
// result = proxy.mod(10, 20); // 컴파일 오류!
Calculator c1 = (Calculator) proxy;
System.out.println(c1.plus(10, 20));
System.out.println(c1.minus(10, 20));
Calculator2 c2 = (Calculator2) proxy;
System.out.println(c2.multiple(10, 20));
System.out.println(c2.divide(10, 20));
Calculator3 c3 = (Calculator3) proxy;
System.out.println(c3.mod(10, 20));
}
}
package com.eomcs.reflect.ex06.e;
public interface Calculator2 {
int multiple(int a, int b);
int divide(int a, int b);
}
package com.eomcs.reflect.ex06.e;
public interface Calculator3 {
int mod(int a, int b);
}
여러 개의 인터페이스를 구현한 객체를 자동 생성하기 - 람다(lambda) 적용=
package com.eomcs.reflect.ex06.e;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Exam0130 {
public static void main(String[] args) {
// Calculator, Calculator2, Calculator3 인터페이스를 구현한
// 클래스를 만들고 그 인스턴스를 생성하여 리턴한다.
Object proxy = Proxy.newProxyInstance(
Exam0130.class.getClassLoader(),
new Class[] {
Calculator.class,
Calculator2.class,
Calculator3.class},
// 3) 람다(lambda) 문법을 사용하여 InvocationHandler 구현하기
(Object proxyObj, Method method, Object[] params) -> {
// newProxyInstance()가 생성한 객체에 대해 메서드를 호출할 때마다 이 메서드가 호출된다.
int a = (int) params[0]; // auto-unboxing => ((Integer)args[0]).intValue();
int b = (int) params[1]; // auto-unboxing => ((Integer)args[1]).intValue();
switch (method.getName()) {
case "plus":
return a + b;
case "minus":
return a - b;
case "multiple":
return a * b;
case "divide":
return a / b;
case "mod":
return a % b;
}
return 0;
});
Calculator c1 = (Calculator) proxy;
Calculator2 c2 = (Calculator2) proxy;
Calculator3 c3 = (Calculator3) proxy;
System.out.println(c1.plus(10, 20));
System.out.println(c1.minus(10, 20));
System.out.println(c2.multiple(10, 20));
System.out.println(c2.divide(10, 20));
System.out.println(c3.mod(10, 20));
}
}
Proxy 를 이용한 DAO 구현체 자동 생성하기
package com.eomcs.reflect.ex06.f;
import java.util.HashMap;
import java.util.List;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.eomcs.ioc.ex01.ApplicationContext;
import com.eomcs.spring.ioc.SpringUtils;
public class Exam01 {
public static void main(String[] args) {
ApplicationContext iocContainer = new ClassPathXmlApplicationContext(//
"com/eomcs/reflect/ex06/f/application-context.xml");
SpringUtils.printBeanList(iocContainer);
BoardDao boardDao = iocContainer.getBean(BoardDao.class);
//1) 게시물 입력
Board board = new Board();
board.setTitle("제목입니다.");
board.setContent("내용입니다.");
boardDao.insert(board);
//2) 게시물 목록 조회
// => selectList()의 파라미터 값을 한 개만 넘겨야 하기 때문에
// 여러 개의 값을 넣고 싶으면 Map에 담아 넘긴다.
HashMap<String,Object> params = new HashMap<>();
params.put("startIndex", 0);
params.put("pageSize", 5);
List<Board> list = boardDao.selectList(params);
for (Board b : list) {
System.out.printf("%d, %s, %s\n",
b.getNo(),
b.getTitle(),
b.getRegisteredDate());
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.eomcs.reflect.ex06.f"/>
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations"
value="classpath*:com/eomcs/reflect/ex06/f/*Mapper.xml" />
<property name="typeAliases"
value="com.eomcs.reflect.ex06.f.Board"/>
</bean>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<context:property-placeholder
location="com/eomcs/reflect/ex06/f/jdbc.properties"/>
<bean id="boardDao" class="com.eomcs.reflect.ex06.f.BoardDaoGenerator"/>
</beans>
# key=value
jdbc.driver=org.mariadb.jdbc.Driver
jdbc.url=jdbc:mariadb://localhost:3306/studydb
jdbc.username=study
jdbc.password=1111
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.eomcs.reflect.ex06.f.BoardDao">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="title" property="title"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<select id="selectList" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date
from x_board
order by board_id desc
limit #{startIndex}, #{pageSize}
</select>
<insert id="insert" parameterType="Board">
insert into x_board(title,contents)
values(#{title},#{content})
</insert>
<delete id="delete" parameterType="int">
delete from x_board
where board_id=#{no}
</delete>
</mapper>
package com.eomcs.reflect.ex06.f;
import java.io.Serializable;
import java.sql.Date;
public class Board implements Serializable {
private static final long serialVersionUID = 1L;
int no;
String title;
String content;
Date registeredDate;
int viewCount;
@Override
public String toString() {
return "Board [no=" + no + ", title=" + title + ", content=" + content + ", registeredDate="
+ registeredDate + ", viewCount=" + viewCount + "]";
}
public int getViewCount() {
return viewCount;
}
public void setViewCount(int viewCount) {
this.viewCount = viewCount;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
// 프로퍼티명 : title
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
// 프로퍼티명 : content
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
// 프로퍼티명 : registeredDate
public Date getRegisteredDate() {
return registeredDate;
}
public void setRegisteredDate(Date registeredDate) {
this.registeredDate = registeredDate;
}
}
package com.eomcs.reflect.ex06.f;
import java.util.List;
import java.util.Map;
public interface BoardDao {
List<Board> selectList(Map<String, Object> map);
int insert(Board board);
int delete(int no);
}
package com.eomcs.reflect.ex06.f;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
public class BoardDaoGenerator implements FactoryBean<BoardDao>{
@Autowired SqlSessionFactory sqlSessionFactory;
@Override
public BoardDao getObject() throws Exception {
return (BoardDao) Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[] {BoardDao.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> interfaceType = proxy.getClass().getInterfaces()[0];
String namespace = interfaceType.getName();
String sqlId = method.getName();
String statementName = namespace + "." + sqlId;
Class<?> returnType = method.getReturnType();
SqlSession sqlSession = sqlSessionFactory.openSession();
if (returnType == void.class || returnType == int.class) {
if (args.length == 0) {
return sqlSession.insert(statementName);
} else {
return sqlSession.insert(statementName, args[0]);
}
} else if (returnType == List.class) {
if (args.length == 0) {
return sqlSession.selectList(statementName);
} else {
return sqlSession.selectList(statementName, args[0]);
}
} else {
if (args.length == 0) {
return sqlSession.selectOne(statementName);
} else {
return sqlSession.selectOne(statementName, args[0]);
}
}
}
});
}
@Override
public Class<?> getObjectType() {
return BoardDao.class;
}
}
'네이버클라우드 AIaaS 개발자 양성과정 1기 > DBMS, SQL, JDBC, Servlet' 카테고리의 다른 글
[Java] 예제 소스 정리 - IoC (0) | 2023.02.28 |
---|---|
[Java] 예제 소스 정리 - Annotation (0) | 2023.02.28 |
[비트캠프] 79일차(17주차1일) - Servlet(리플렉션 API, 애노테이션), myapp-54~58 (0) | 2023.02.27 |
[비트캠프] 78일차(16주차5일) - myapp-51~53(서비스 객체 도입, Front controller, Page Controller) (0) | 2023.02.24 |
[비트캠프] 77일차(16주차4일) - Servlet(파일 업로드, 멀티파트), myapp-50(파일 업로드) (0) | 2023.02.23 |