Мені потрібно читати класи, що містяться в пакеті Java. Ці класи знаходяться в класі. Мені потрібно виконати це завдання безпосередньо з програми Java. Чи знаєте ви простий спосіб зробити це?
List<Class> classes = readClassesFrom("my.package")
Мені потрібно читати класи, що містяться в пакеті Java. Ці класи знаходяться в класі. Мені потрібно виконати це завдання безпосередньо з програми Java. Чи знаєте ви простий спосіб зробити це?
List<Class> classes = readClassesFrom("my.package")
Відповіді:
Якщо у вас є Spring у своєму класі, тоді це зробить наступне.
Знайдіть усі класи в пакунку, котрі анотовані XmlRootElement:
private List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
List<Class> candidates = new ArrayList<Class>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + "**/*.class";
Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (isCandidate(metadataReader)) {
candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
}
}
}
return candidates;
}
private String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}
private boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
try {
Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
if (c.getAnnotation(XmlRootElement.class) != null) {
return true;
}
}
catch(Throwable e){
}
return false;
}
Ви можете скористатися описаним тут проектом "Роздуми"
Він цілком повний і простий у використанні.
Короткий опис із зазначеного вище веб-сайту:
Reflections сканує шлях до вашого класу, індексує метадані, дозволяє запитувати їх під час виконання та може зберігати та збирати цю інформацію для багатьох модулів у вашому проекті.
Приклад:
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);
Я використовую цей, він працює з файлами або архівами jar
public static ArrayList<String>getClassNamesFromPackage(String packageName) throws IOException{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL packageURL;
ArrayList<String> names = new ArrayList<String>();;
packageName = packageName.replace(".", "/");
packageURL = classLoader.getResource(packageName);
if(packageURL.getProtocol().equals("jar")){
String jarFileName;
JarFile jf ;
Enumeration<JarEntry> jarEntries;
String entryName;
// build jar file name, then loop through zipped entries
jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
jarFileName = jarFileName.substring(5,jarFileName.indexOf("!"));
System.out.println(">"+jarFileName);
jf = new JarFile(jarFileName);
jarEntries = jf.entries();
while(jarEntries.hasMoreElements()){
entryName = jarEntries.nextElement().getName();
if(entryName.startsWith(packageName) && entryName.length()>packageName.length()+5){
entryName = entryName.substring(packageName.length(),entryName.lastIndexOf('.'));
names.add(entryName);
}
}
// loop through files in classpath
}else{
URI uri = new URI(packageURL.toString());
File folder = new File(uri.getPath());
// won't work with path which contains blank (%20)
// File folder = new File(packageURL.getFile());
File[] contenuti = folder.listFiles();
String entryName;
for(File actual: contenuti){
entryName = actual.getName();
entryName = entryName.substring(0, entryName.lastIndexOf('.'));
names.add(entryName);
}
}
return names;
}
Spring реалізував чудову функцію пошуку шляху до класу в PathMatchingResourcePatternResolver. Якщо ви використовуєте classpath*префікс:, ви можете знайти всі ресурси, включаючи класи в певній ієрархії, і навіть відфільтрувати їх, якщо хочете. Потім ви можете використовувати дитина AbstractTypeHierarchyTraversingFilter, AnnotationTypeFilterі AssignableTypeFilterфільтрувати ці ресурси або на анотаціях на рівні класу або інтерфейс вони реалізують.
Java 1.6.0_24:
public static File[] getPackageContent(String packageName) throws IOException{
ArrayList<File> list = new ArrayList<File>();
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader()
.getResources(packageName);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
File dir = new File(url.getFile());
for (File f : dir.listFiles()) {
list.add(f);
}
}
return list.toArray(new File[]{});
}
Це рішення було протестовано в середовищі EJB .
Scannotation та Reflections використовують підхід до сканування шляху до класу:
Reflections reflections = new Reflections("my.package");
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);
Інший підхід полягає у використанні Java Pluggable Annotation Processing API для написання процесора анотацій, який збиратиме всі анотовані класи під час компіляції та будуватиме файл індексу для використання під час виконання. Цей механізм реалізований у бібліотеці ClassIndex :
Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");
Наскільки мені відомо, ця функціональність досі підозріло відсутня в API відображення Java. Ви можете отримати об'єкт пакета, просто виконавши наступне:
Package packageObj = Package.getPackage("my.package");
Але, як ви напевно помітили, це не дозволить вам перерахувати класи в цьому пакеті. На сьогоднішній день вам доведеться скористатись більш орієнтованим на файлову систему підходом.
У цій публікації я знайшов кілька зразків реалізацій
Я не впевнений на 100%, що ці методи спрацюють, коли ваші класи поховані у файлах JAR, але, сподіваюся, хтось із них це зробить за вас.
Я згоден з @skaffman ... якщо у вас є інший спосіб зробити це, я б рекомендував зробити це замість цього.
В даний час найнадійнішим механізмом переліку всіх класів у даному пакеті є ClassGraph , оскільки він обробляє найширший з можливих наборів механізмів специфікації шляху до класу, включаючи нову систему модулів JPMS. (Я автор.)
List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
.enableClassInfo().scan()) {
classNames = scanResult.getAllClasses().getNames();
}
eXtcos виглядає багатообіцяючим. Уявіть, ви хочете знайти всі класи, які:
З eXtcos це так просто, як
ClasspathScanner scanner = new ClasspathScanner();
final Set<Class> classStore = new ArraySet<Class>();
Set<Class> classes = scanner.getClasses(new ClassQuery() {
protected void query() {
select().
from(“common”).
andStore(thoseExtending(Component.class).into(classStore)).
returning(allAnnotatedWith(MyComponent.class));
}
});
Білл Берк написав (приємну статтю про сканування класів), а потім написав Scannotation .
Про сплячий режим уже написано:
CDI може вирішити це питання, але не знаю - ще не досліджував його повністю
.
@Inject Instance< MyClass> x;
...
x.iterator()
Також для анотацій:
abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
Я випадково реалізував це, і це працює в більшості випадків. Оскільки він довгий, я помістив його у файл тут .
Ідея полягає в тому, щоб знайти розташування вихідного файлу класу, яке доступне в більшості випадків (відомим винятком є файли класу JVM - наскільки я тестував). Якщо код знаходиться в каталозі, проскануйте всі файли та лише файли спотових класів. Якщо код знаходиться у файлі JAR, відскануйте всі записи.
Цей метод можна використовувати лише тоді, коли:
У вас є клас, який знаходиться в тому самому пакеті, який ви хочете виявити. Цей клас називається SeedClass. Наприклад, якщо ви хочете перерахувати всі класи в 'java.io', це може бути насіннєвий клас java.io.File.
Ваші класи знаходяться в каталозі або у файлі JAR, в якому є інформація про вихідний файл (не файл вихідного коду, а лише вихідний файл). Наскільки я спробував, він працює майже на 100%, крім класу JVM (ці класи поставляються з JVM).
Ваша програма повинна мати дозвіл на доступ до ProtectionDomain цих класів. Якщо ваша програма завантажується локально, проблем не повинно бути.
Я протестував програму лише для регулярного використання, тому вона все ще може мати проблеми.
Я сподіваюся, що це допомагає.
Ось ще один варіант, невелика модифікація іншої відповіді вгорі / внизу:
Reflections reflections = new Reflections("com.example.project.package",
new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);
У часи, коли аплети були загальним місцем, на шляху до класу міг бути URL. Коли навантажувачу класів потрібен клас, він здійснюватиме пошук у всіх місцях на шляху до класу, включаючи ресурси http. Оскільки ви можете мати такі речі, як URL-адреси та каталоги на шляху до класу, немає простого способу отримати остаточний список класів.
Однак ви можете наблизитися досить близько. Деякі з весняних бібліотек роблять це зараз. Ви можете отримати всі банки на шляху до класу та відкрити їх як файли. Потім ви можете взяти цей список файлів і створити структуру даних, що містить ваші класи.
використовувати залежність maven:
groupId: net.sf.extcos
artifactId: extcos
version: 0.4b
тоді скористайтеся цим кодом:
ComponentScanner scanner = new ComponentScanner();
Set classes = scanner.getClasses(new ComponentQuery() {
@Override
protected void query() {
select().from("com.leyton").returning(allExtending(DynamicForm.class));
}
});
Brent - причина того, що асоціація є одним із шляхів, пов’язана з тим, що будь-який клас будь-якого компонента вашого CLASSPATH може заявити про себе в будь-якому пакеті (крім java / javax). Таким чином, просто не існує відображення ВСІХ класів у даному "пакеті", оскільки ніхто не знає і не може знати. Ви можете завтра оновити файл jar та видалити або додати класи. Це все одно, що намагатися скласти список усіх людей на ім’я Джон / Джон / Йохан у всіх країнах світу - ніхто з нас не є всезнаючим, тому ніхто з нас ніколи не матиме правильної відповіді.