Java에서 주어진 클래스의 모든 서브 클래스 (또는 주어진 인터페이스의 모든 구현 자)를 찾으려고 어떻게합니까? 현재로서는이 작업을 수행 할 수있는 방법이 있지만 매우 비효율적입니다 (최소하게 말하면). 방법은 다음과 같습니다
- 클래스 경로에 존재하는 모든 클래스 이름 목록을 가져옵니다.
- 각 클래스를로드하고 테스트하여 해당 클래스 또는 인터페이스의 서브 클래스 또는 구현 자인지 확인하십시오.
이클립스에는 Type Hierarchy라는 멋진 기능이 있는데이를 효율적으로 보여줍니다. 프로그래밍 방식으로 어떻게 진행합니까?
답변
설명 한 것 이외의 다른 방법은 없습니다. 생각해보십시오-클래스 패스에서 각 클래스를 스캔하지 않고 클래스가 어떤 클래스를 클래스 X로 확장하는지 알 수 있습니까?
Eclipse는 “유형 계층에 표시”단추를 누른 시점에 이미 모든 유형 데이터가로드되어 있기 때문에 “효율적인”시간으로 보이는 수퍼 클래스와 서브 클래스에 대해서만 알려줄 수 있습니다. 지속적으로 클래스를 컴파일하고 클래스 패스의 모든 것에 대해 알고 있습니다.)
답변
순수 Java를 사용하면 클래스 스캔이 쉽지 않습니다.
스프링 프레임 워크는 필요한 것을 수행 할 수있는 ClassPathScanningCandidateComponentProvider 클래스를 제공 합니다. 다음 예제는 org.example.package 패키지에서 MyClass의 모든 서브 클래스를 찾습니다.
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
이 방법은 후보를 찾기 위해 바이트 코드 분석기를 사용하는 추가 이점이 있습니다. 즉 , 스캔하는 모든 클래스를로드 하지는 않습니다 .
답변
내장 Java Reflections API 만 사용하는 것은 불가능합니다.
이 정보에 액세스 할 수 있도록 클래스 경로의 필요한 스캔 및 인덱싱을 수행하는 프로젝트가 있습니다 …
반사
Scannotations의 정신에 따른 Java 런타임 메타 데이터 분석
Reflections는 클래스 경로를 스캔하고 메타 데이터를 색인화하며 런타임시이를 쿼리하고 프로젝트 내의 많은 모듈에 대한 정보를 저장하고 수집 할 수 있습니다.
Reflections를 사용하여 메타 데이터를 쿼리하여 다음을 수행 할 수 있습니다.
- 특정 유형의 모든 하위 유형을 가져옵니다
- 주석으로 주석이 달린 모든 유형을 얻습니다.
- 주석 매개 변수 일치를 포함하여 주석으로 주석이 달린 모든 유형을 가져옵니다.
- 모든 메소드에 주석이 달린
(면책 조항 : 나는 그것을 사용하지 않았지만 프로젝트 설명은 귀하의 요구에 정확히 맞는 것 같습니다.)
답변
클래스에 대해 생성 된 Javadoc 에는 알려진 서브 클래스 (및 인터페이스, 알려진 구현 클래스)의 목록이 포함 된다는 것을 잊지 마십시오 .
답변
ClassGraph 사용해보십시오 . (면책 조항, 저자입니다). ClassGraph는 주어진 클래스의 서브 클래스, 런타임 또는 빌드 타임에 대한 스캔을 지원합니다. ClassGraph는 메모리, 클래스 경로의 모든 클래스 또는 허용 된 패키지의 클래스에 대한 전체 클래스 그래프 (모든 클래스, 주석, 메소드, 메소드 매개 변수 및 필드)의 추상 표현을 빌드 할 수 있지만 해당 클래스 그래프를 조회 할 수 있습니다. 당신이 원합니다. ClassGraph는 다른 스캐너보다 더 많은 클래스 경로 지정 메커니즘과 클래스 로더를 지원 하며 새로운 JPMS 모듈 시스템과 완벽하게 작동하므로 ClassGraph를 기반으로 코드를 작성하면 코드를 최대한 이식 할 수 있습니다. 여기 API를 참조하십시오.
답변
나는 몇 년 전에 이것을했습니다. 이를 수행하는 가장 신뢰할 수있는 방법 (예 : 공식 Java API 및 외부 종속성 없음)은 사용자 정의 doclet을 작성하여 런타임시 읽을 수있는 목록을 작성하는 것입니다.
다음과 같이 명령 행에서 실행할 수 있습니다.
javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
또는 다음과 같이 개미에서 실행하십시오.
<javadoc sourcepath="${src}" packagenames="*" >
<doclet name="com.example.ObjectListDoclet" path="${build}"/>
</javadoc>
기본 코드는 다음과 같습니다.
public final class ObjectListDoclet {
public static final String TOP_CLASS_NAME = "com.example.MyClass";
/** Doclet entry point. */
public static boolean start(RootDoc root) throws Exception {
try {
ClassDoc topClassDoc = root.classNamed(TOP_CLASS_NAME);
for (ClassDoc classDoc : root.classes()) {
if (classDoc.subclassOf(topClassDoc)) {
System.out.println(classDoc);
}
}
return true;
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
}
간단히하기 위해 명령 줄 인수 구문 분석을 제거하고 파일이 아닌 System.out에 작성하고 있습니다.
답변
나는이 파티에 몇 년 늦었다는 것을 알고 있지만, 같은 문제를 해결하려고이 질문을 겪었습니다. Eclipse 플러그인을 작성하고 (따라서 캐싱 등을 활용하는 경우) 프로그래밍 방식으로 Eclipse의 내부 검색을 사용하여 인터페이스를 구현하는 클래스를 찾을 수 있습니다. 내 (매우 거친) 첫 컷은 다음과 같습니다.
protected void listImplementingClasses( String iface ) throws CoreException
{
final IJavaProject project = <get your project here>;
try
{
final IType ifaceType = project.findType( iface );
final SearchPattern ifacePattern = SearchPattern.createPattern( ifaceType, IJavaSearchConstants.IMPLEMENTORS );
final IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
final SearchEngine searchEngine = new SearchEngine();
final LinkedList<SearchMatch> results = new LinkedList<SearchMatch>();
searchEngine.search( ifacePattern,
new SearchParticipant[]{ SearchEngine.getDefaultSearchParticipant() }, scope, new SearchRequestor() {
@Override
public void acceptSearchMatch( SearchMatch match ) throws CoreException
{
results.add( match );
}
}, new IProgressMonitor() {
@Override
public void beginTask( String name, int totalWork )
{
}
@Override
public void done()
{
System.out.println( results );
}
@Override
public void internalWorked( double work )
{
}
@Override
public boolean isCanceled()
{
return false;
}
@Override
public void setCanceled( boolean value )
{
}
@Override
public void setTaskName( String name )
{
}
@Override
public void subTask( String name )
{
}
@Override
public void worked( int work )
{
}
});
} catch( JavaModelException e )
{
e.printStackTrace();
}
}
지금까지 본 첫 번째 문제는 모든 하위 클래스가 아닌 인터페이스를 직접 구현하는 클래스 만 잡는다는 것입니다.