2010년 4월 9일 금요일

클래스 생성 시 인터페이스 메서드 implements 하기 - JDT

이클립스에서 클래스를 생성할 때 클랫스 생성 다이얼로그에서 인터페이스를 지정하면
생성된 클래스 소스 안에 인터페이스에 정의된 메서드들이 override되어 있다.
메서드 내의 로직은 없지만 컴파일 에러가 발생하지 않을 정도의 소스 코드가 생성된다.

이러한 작업은 클래스가 생성 된 이후에도 가능하다.
특정 인터페이스를 implements 한 후에 프로젝트 탐색뷰에서 해당 클래스를 선택한 후 팝업메뉴를 띄우거나 현재 작업 중인 에디터에서 팝업메뉴를 띄운 후 Source -> Override/Implement Methods 를 선택하면 override 하거나 implement 할 메서드 목록을 선택할 수 있는 창이 열린다.
메서드를 선택한 후 OK버튼을 클릭하면 메서드가 override/implements 된다.

요구사항 : 특정 인터페이스를 상속하는 클래스를 생성한다. 생성된 클래스는 인터페이스 메서드를 implements 한다.

JDT UI에서 처리되는 이러한 작업을 프로그래밍적으로 구현해야 한다면 어떻게 해야할까?
먼저 JDT에서는 어떻게 구현되었는지 살펴보았다.

org.eclipse.jdt.ui.actions.OverrideMethodsAction 에서 org.eclipse.jdt.internal.ui.dialogs.OverrideMethodDialog 으로부터 선택된 결과(org.eclipse.jdt.core.dom.IMethodBinding 목록)를 가지고 org.eclipse.jdt.internal.corext.codemanipulation.AddUnimplementedMethodsOperation 을 호출하는 구조로 되어 있다.

나의 요구사항에서는 OverrideMethodDialog가 필요없다. implements해야 할 메서드들이 이미 결정되어 있기 때문이다. 그래서 implements할 메서드 목록을 IMethodBinding으로 뽑아 내기만 하면 작업이 거의 완성될 것으로 판단했다. 어차피 나머지 작업은 AddUnimplementedMethodsOperation에서 처리될 것이기 때문이다.
스텁 코드에 대한 처리를 할 일이 있다면 org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2 클래스에 대해서 알아두는 것이 유익하다.
아래의 소스 코드는 StubUtility2에서 IMethodBinding을 뽑아내는 로직이 들어있다.
살펴보기 바란다.


IType javaType = ProjectHelper.findType(javaProject, serviceClass);
CompilationUnit unit = ProjectHelper.parse(javaType);
final ITypeBinding binding = ASTNodes.getTypeBinding(unit, javaType);
if(binding != null) {
final IPackageBinding pack = binding.getPackage();
// 클래스에서 override하거나 implements 해야 할 모든 메서드 목록에 대한 정보를 리턴한다.
final IMethodBinding[] methods =
StubUtility2.getOverridableMethods(unit.getAST(), binding, false);
List list = new ArrayList();
for(IMethodBinding methodBinding: methods) {
// 상위 인터페이스에 정의된 메서드 목록만 추려낸다.
if(proxyInterface.equals(methodBinding.getDeclaringClass().getQualifiedName())) {
list.add(methodBinding);
}
}

IMethodBinding[] methodToOverride = list.toArray(new IMethodBinding[list.size()]);
try {
final ITypeBinding typeBinding= ASTNodes.getTypeBinding(unit, javaType);

// 시작위치는 지정하지 않는다. 가장 마지막에 추가될 것으로 판단된다.
int insertPos = -1;
// 오퍼레이션을 실행한다.
AddUnimplementedMethodsOperation operation = (AddUnimplementedMethodsOperation) createRunnable(unit, typeBinding, methodToOverride, insertPos, true);
operation.run(monitor);
} finally {
}
}


................

public static IWorkspaceRunnable createRunnable(CompilationUnit astRoot, ITypeBinding type, IMethodBinding[] methodToOverride, int insertPos, boolean createComments) {
AddUnimplementedMethodsOperation operation= new AddUnimplementedMethodsOperation(astRoot, type, methodToOverride, insertPos, true, true, true);
operation.setCreateComments(createComments);
return operation;
}


AddUnimplementedMethodsOperation의 생성자의 파라미터는 마지막 3개의 boolean 파라미터는 각각
imports: if the import edits should be applied
apply: if the resulting edit should be applied
save: if the changed compilation unit should be saved

참고로, 에디터가 열린 상태로 소스 코드를 생성하는 것이 아니기 때문에 save는 반드시 true로 지정되어한다.

댓글 없음:

댓글 쓰기