반응형

javax.lang.model.util.AbstractTypeVisitor6는 Java 언어에서 타입(ElementKind.TYPE)에 대한 방문자 패턴(Visitor Pattern)을 구현하는 유틸리티 클래스입니다. 

방문자 패턴은 객체 지향 디자인 패턴 중 하나로, 구조와 기능을 분리하여 확장성을 높이는 데 유용합니다. 이 패턴은 다음과 같은 경우에 사용됩니다.

- 여러 종류의 객체가 있고, 이 객체들의 행동이 다양하게 변화해야 할 때
- 객체의 구조를 변경하지 않고 새로운 동작을 추가하거나 수정해야 할 때

AbstractTypeVisitor6 클래스는 타입에 대한 메서드를 포함하는 추상 클래스입니다. 이 클래스를 상속받는 클래스를 만들고, 필요한 메서드를 오버라이드하여 새로운 동작을 추가하거나 수정할 수 있습니다. 

AbstractTypeVisitor6 클래스의 메서드는 다음과 같습니다.

- visitDeclared(DeclaredType t, P p) : 선언된 타입(클래스, 인터페이스, enum 등)을 방문할 때 호출됩니다.
- visitArray(ArrayType t, P p) : 배열 타입을 방문할 때 호출됩니다.
- visitTypeVariable(TypeVariable t, P p) : 타입 변수를 방문할 때 호출됩니다.
- visitWildcard(WildcardType t, P p) : 와일드카드 타입을 방문할 때 호출됩니다.
- visitIntersection(IntersectionType t, P p) : 타입의 교차(Intersection)을 방문할 때 호출됩니다.
- visitUnion(UnionType t, P p) : 타입의 합집합(Union)을 방문할 때 호출됩니다.

AbstractTypeVisitor6 클래스를 상속받은 클래스에서는 이 메서드들을 오버라이드하여, 각 타입에 대한 동작을 구현할 수 있습니다. 

예를 들어, 다음과 같이 AbstractTypeVisitor6 클래스를 상속받은 클래스를 만들 수 있습니다.

 

class MyTypeVisitor extends AbstractTypeVisitor6<Void, Void> {
    @Override
    public Void visitDeclared(DeclaredType t, Void p) {
        // 선언된 타입을 방문할 때 실행될 코드
        return super.visitDeclared(t, p);
    }
    
    @Override
    public Void visitArray(ArrayType t, Void p) {
        // 배열 타입을 방문할 때 실행될 코드
        return super.visitArray(t, p);
    }
    
    // 나머지 메서드들도 오버라이드할 수 있습니다.
}


AbstractTypeVisitor6 클래스는 Java 6에서 도입되었으며, 타입(ElementKind.TYPE)에 대한 방문자 패턴을 구현하는 데 사용됩니다. 따라서 Java 6 이상에서만 사용할 수 있습니다.AbstractTypeVisitor6 클래스의 두 번째 타입 인자는 방문자 패턴에서 사용하는 데이터의 타입입니다. 보통 이 인자는 각 메서드에서 처리할 데이터를 전달하는 데 사용됩니다. 만약 데이터를 사용하지 않는다면 Void 타입을 사용할 수 있습니다.

AbstractTypeVisitor6 클래스는 다른 유틸리티 클래스와 함께 사용될 때 매우 유용합니다. 예를 들어, javax.lang.model.util.ElementScanner6 클래스를 사용하면 Java 소스 코드의 요소(Element)를 스캔할 수 있습니다. 이때 AbstractTypeVisitor6 클래스를 상속받은 클래스를 만들어서 ElementScanner6 클래스에서 사용할 수 있습니다. 

아래는 AbstractTypeVisitor6 클래스를 사용하는 간단한 예시입니다.

 

import javax.lang.model.type.*;
import javax.lang.model.util.*;

class MyElementScanner extends ElementScanner6<Void, Void> {
    public MyElementScanner() {
        super(new VoidVisitor<Void>(), null);
    }
    
    @Override
    public Void visitType(TypeElement e, Void p) {
        // TypeElement를 방문할 때 실행될 코드
        e.asType().accept(new MyTypeVisitor(), null);
        return super.visitType(e, p);
    }
}

class MyTypeVisitor extends AbstractTypeVisitor6<Void, Void> {
    @Override
    public Void visitDeclared(DeclaredType t, Void p) {
        // 선언된 타입을 방문할 때 실행될 코드
        return super.visitDeclared(t, p);
    }
    
    @Override
    public Void visitArray(ArrayType t, Void p) {
        // 배열 타입을 방문할 때 실행될 코드
        return super.visitArray(t, p);
    }
}

public class Example {
    public static void main(String[] args) {
        MyElementScanner scanner = new MyElementScanner();
        scanner.scan(someElement);
    }
}

위 예제에서는 MyElementScanner 클래스를 만들어서 ElementScanner6 클래스에서 사용합니다. MyElementScanner 클래스에서는 TypeElement를 방문할 때 MyTypeVisitor 클래스에서 구현한 visitDeclared()와 visitArray() 메서드를 실행합니다. 이렇게 하면 TypeElement의 타입 정보에 대한 처리를 AbstractTypeVisitor6 클래스를 사용해서 처리할 수 있습니다.아래는 예제 코드입니다. 이 예제 코드는 특정 패키지 내의 클래스 파일의 이름을 출력하는 간단한 프로그램입니다. 이 프로그램은 javax.lang.model.util.ElementScanner6 클래스와 javax.lang.model.util.AbstractTypeVisitor6 클래스를 사용합니다.

 

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.ElementScanner6;
import javax.lang.model.util.AbstractTypeVisitor6;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Example {
    public static void main(String[] args) throws IOException {
        // 특정 패키지 내의 클래스 파일들을 가져옴
        String packageName = "com.example.package";
        List<JavaFileObject> files = new ArrayList<>();
        StandardJavaFileManager fileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null);
        for (JavaFileObject file : fileManager.list(JavaFileObject.Kind.CLASS, packageName, ElementFilter.packageFilter())) {
            files.add(file);
        }
        fileManager.close();

        // 각 클래스 파일의 이름 출력
        for (JavaFileObject file : files) {
            String className = file.getName().substring(packageName.length() + 1, file.getName().length() - ".class".length()).replace('/', '.');
            System.out.println(className);
            TypeElement typeElement = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null).getElements().getTypeElement(className);
            if (typeElement != null) {
                // TypeElement 내의 각 타입 변수 출력
                typeElement.asType().accept(new TypeVariableVisitor(), null);
            }
        }
    }

    private static class TypeVariableVisitor extends AbstractTypeVisitor6<Void, Void> {
        @Override
        public Void visitTypeVariable(TypeVariable t, Void p) {
            System.out.println("\tType variable: " + t);
            return null;
        }

        @Override
        public Void visitDeclared(DeclaredType t, Void p) {
            // DeclaredType 내의 각 TypeMirror에 대해 visit() 메서드 호출
            for (TypeMirror arg : t.getTypeArguments()) {
                arg.accept(this, null);
            }
            return null;
        }
    }
}


위 예제에서는 특정 패키지 내의 클래스 파일들의 이름을 출력하는 프로그램을 작성합니다. ElementFilter.packageFilter() 메서드를 사용해서 패키지 내의 모든 요소(Element)를 가져온 후, 각 클래스 파일의 이름을 출력합니다.

이후 TypeElement를 사용해서 각 클래스 파일의 TypeElement를 가져온 후, TypeElement의 타입 정보를 출력합니다. TypeElement.asType() 메서드를 사용해서 TypeElement의 TypeMirror를 가져온 후, AbstractTypeVisitor6 클래스를 상속받은 TypeVariableVisitor 클래스를 만들어서 TypeMirror의 타입 정보를 출력합니다.

반응형

+ Recent posts