Ar galite rasti visas pakuotės klases, naudodami atspindį?

Ar galiu rasti visas šio paketo klases ar sąsajas? (Greitai žiūrint, pavyzdžiui, į Package , tai atrodo ne.)

447
06 февр. Joniko nustatytas 06 vasario mėn 2009-02-06 16:43 '09 at 16:43 2009-02-06 16:43
@ 23 atsakymai

Dėl dinamiško klasės krautuvų pobūdžio tai neįmanoma. Klasteriniai krautuvai neprivalo pranešti VM, kokioms klasėms jis gali suteikti, o tik paprašo klasės ir turi grąžinti klasę arba pašalinti išimtį.

Tačiau, jei rašote savo klasės krautuvus arba mokote klasės takus ir jų stiklainius, galite rasti šią informaciją. Tai bus padaryta per failų sistemos operacijas, bet ne atspindys. Gali būti bibliotekų, kurios gali jums padėti.

Jei yra klasių, kurios sukuriamos ar perduodamos nuotoliniu būdu, negalėsite aptikti šių klasių.

Įprasta metodas yra užsiregistruoti kur nors klasėse, kurioms jums reikia prieigos prie failo, arba kreiptis į juos kitoje klasėje. Arba tiesiog naudokite susitarimą, kai kalbama apie pavadinimą.

Priedas: Atspindėjimo biblioteka leis jums ieškoti klasių dabartinėje klasėje. Jis gali būti naudojamas visoms paketų klasėms gauti:

  Reflections reflections = new Reflections("my.project.prefix"); Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class); 
321
06 февр. Atsakymą pateikė Staale 06 Feb. 2009-02-06 16:47 '09 at 16:47 2009-02-06 16:47

Turbūt turėtumėte pažvelgti į atvirojo kodo katalogą „Reflection Library“ . Su juo galite lengvai pasiekti tai, ko norite.

Pirmiausia nustatykite atspindžio indeksą (tai yra šiek tiek nepatogus, nes visų klasių paieška pagal nutylėjimą yra išjungta):

 List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>(); classLoadersList.add(ClasspathHelper.contextClassLoader()); classLoadersList.add(ClasspathHelper.staticClassLoader()); Reflections reflections = new Reflections(new ConfigurationBuilder() .setScanners(new SubTypesScanner(false ), new ResourcesScanner()) .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0]))) .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.your.package")))); 
border=0

Tada galite paprašyti visų šio paketo objektų:

 Set<Class<?>> classes = reflections.getSubTypesOf(Object.class); 
162
05 марта '12 в 20:29 2012-03-05 20:29 atsakymas pateikiamas Aleksander Blomskøld kovo 5 d. 12 val. 20:29 2012-03-05 20:29

„Google Guava 14“ apima naują ClassPath klasę su trimis nuskaitymo metodais aukščiausio lygio klasėms:

  • getTopLevelClasses()
  • getTopLevelClasses(String packageName)
  • getTopLevelClassesRecursive(String packageName)

Išsamesnės informacijos ieškokite ClassPath javadocs .

106
20 нояб. Christoph Leiter atsakymas lapkričio 20 d. 2012-11-20 19:06 '12, 07:06 pm 2012-11-20 19:06

Galite naudoti šį metodą 1, kuris naudoja „ ClassLoader .

  private static Class[] getClasses(String packageName) throws ClassNotFoundException, IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; String path = packageName.replace('.', '/'); Enumeration<URL> resources = classLoader.getResources(path); List<File> dirs = new ArrayList<File>(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); dirs.add(new File(resource.getFile())); } ArrayList<Class> classes = new ArrayList<Class>(); for (File directory : dirs) { classes.addAll(findClasses(directory, packageName)); } return classes.toArray(new Class[classes.size()]); }  private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException { List<Class> classes = new ArrayList<Class>(); if (!directory.exists()) { return classes; } File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) { assert !file.getName().contains("."); classes.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); } } return classes; } 

__________
1 Šis metodas buvo paimtas iš http://snippets.dzone.com/posts/show/4831 , kuris buvo archyvuotas su juo susijusiame internetiniame archyve. Ištrauka taip pat pateikiama https://dzone.com/articles/get-all-classes-within-package .

88
06 февр. atsakymas, kurį pateikė user59634 06 Feb. 2009-02-06 16:49 '09, 4:49 PM 2009-02-06 16:49

Pavasaris

Šis pavyzdys skirtas 4 pavasariui, tačiau ankstesnėse versijose taip pat galite rasti klasės skaitytuvą.

 // create scanner and disable default filters (that is the 'false' argument) final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); // add include filters which matches all the classes (or use your own) provider.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile(".*"))); // get matching classes defined in the package final Set<BeanDefinition> classes = provider.findCandidateComponents("my.package.name"); // this is how you can load the class type from BeanDefinition instance for (BeanDefinition bean: classes) { Class<?> clazz = Class.forName(bean.getBeanClassName()); // ... do your magic with the class ... } 

„Google guava“

Pastaba: API 14 versija vis dar pažymima kaip @Beta, todėl būkite atsargūs, kai gaminio kodas yra.

 final ClassLoader loader = Thread.currentThread().getContextClassLoader(); for (final ClassPath.ClassInfo info : ClassPath.from(loader).getTopLevelClasses()) { if (info.getName().startsWith("my.package.")) { final Class<?> clazz = info.load(); // do something with your clazz } } 
78
29 янв. atsakymas pateikiamas voho sausio 29 d 2014-01-29 15:15 '14, 15:15 2014-01-29 15:15

Sveiki Visada turėjau problemų su anksčiau pateiktais sprendimais (ir kitose svetainėse).
Aš, kaip kūrėjas, programuoju API priedą. API leidžia naudoti bet kokias išorines bibliotekas ar trečiųjų šalių įrankius. Įrenginys taip pat susideda iš kodo mišinio stiklainiuose ar zip rinkmenose ir klasės failuose, esančiuose tiesiogiai kai kuriuose kataloguose. Taigi, mano kodas turėtų veikti visiems nustatymams. Po daugelio tyrimų, aš atėjau metodą, kuris veiks ne mažiau kaip 95% visų galimų nustatymų.

Šis kodas iš esmės yra pernelyg didelis būdas, kuris visada veiks.

Kodas:

Šis kodas nuskaito šį paketą visoms jame esančioms klasėms. Jis veiks tik visoms klasėms dabartinėje klasėje.

 getClassesForPackage("package.your.classes.are.in"); 

Paaiškinimas:

Pirma, metodas gauna dabartinį ClassLoader . Tada jis išskleidžia visus išteklius, kuriuose yra nurodytas paketas, ir šių URL iteracijų. Tada jis sukuria URLConnection ir nustato, kokio tipo URl yra. Tai gali būti katalogas ( FileURLConnection ) arba katalogas, esantis jar arba zip faile ( JarURLConnection ). Priklausomai nuo ryšio tipo, mes vadiname du skirtingus metodus.

Pirma, pažiūrėkime, kas atsitiks, jei tai yra „ FileURLConnection .
Pirma, ji patikrina, ar perduotas failas yra ir ar jis yra katalogas. Tokiu atveju ji patikrina, ar tai yra klasės failas. Jei taip, Class objektas bus sukurtas ir patalpintas į „ ArrayList . Jei tai ne klasės rinkmena, bet katalogas, mes tiesiog pakartojome ir darome tą patį. Visi kiti atvejai / failai bus ignoruojami.

Jei URLConnection yra JarURLConnection , bus vadinamas kitas privatus pagalbininkas. Šis metodas kartojasi per visus įrašus, įrašytus į „zip / jar“ archyvą. Jei vienas įrašas yra klasės failas ir jis yra paketo viduje, Class objektas bus sukurtas ir išsaugomas „ ArrayList .

Išnagrinėjus visus išteklius, jis (pagrindinis metodas) grąžina „ ArrayList kuriame yra visos šio paketo ClassLoader žino dabartinis „ ClassLoader .

Jei procesas bet kuriuo metu nepavyksta, ClassNotFoundException priklausys nuo konkrečios priežasties detalių.

29
17 марта '14 в 21:47 2014-03-17 21:47 atsakymas pateikiamas „ BrainStone“ kovo 17 d. 14 d. 21:47

Nenaudojant jokių papildomų bibliotekų:

 package test; import java.io.DataInputStream; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) throws Exception{ List<Class> classes = getClasses(Test.class.getClassLoader(),"test"); for(Class c:classes){ System.out.println("Class: "+c); } } public static List<Class> getClasses(ClassLoader cl,String pack) throws Exception{ String dottedPackage = pack.replaceAll("[/]", "."); List<Class> classes = new ArrayList<Class>(); URL upackage = cl.getResource(pack); DataInputStream dis = new DataInputStream((InputStream) upackage.getContent()); String line = null; while ((line = dis.readLine()) != null) { if(line.endsWith(".class")) { classes.add(Class.forName(dottedPackage+"."+line.substring(0,line.lastIndexOf('.')))); } } return classes; } } 
12
18 февр. Atsakymą pateikė Williams López , vasario 18 d. 2014-02-18 01:48 '14 ne 1:48 2014-02-18 01:48

Įprastų klasių krautuvų atveju visų klasių skenavimas klasėje nėra leidžiamas. Tačiau paprastai naudojamas vienintelis klasės krautuvas yra „UrlClassLoader“, iš kurio mes galime gauti katalogų ir jar failų sąrašą (žr. „ GetURL“ ) ir atidaryti juos po vieną, kad būtų pateiktos galimos klasės. Šis metodas, vadinamas klasių kelio nuskaitymu, įgyvendinamas skenuojant ir atspindint .

 Reflections reflections = new Reflections("my.package"); Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class); 

Kitas būdas yra naudoti „ Java Pluggable Annotation Processing API“, kad parašytumėte anotacijos procesorių, kuris surinks visus anotuotus kursus kompiliavimo metu ir sukurtų indekso failą, skirtą naudoti vykdymo metu. Šis mechanizmas įdiegtas ClassIndex bibliotekoje:

 // package-info.java @IndexSubclasses package my.package; // your code Iterable<Class> classes = ClassIndex.getPackageClasses("my.package"); 

Atkreipkite dėmesį, kad nereikia jokios papildomos konfigūracijos, nes nuskaitymas yra visiškai automatizuotas dėka „Java“ kompiliatoriaus, kuris automatiškai aptinka visus klasės tako rasti procesorius.

10
22 дек. Atsakymas duotas Sławekui gruodžio 22 d. 2012-12-22 15:02 '12 15:02 2012-12-22 15:02

Norėčiau išspręsti šią problemą rašydamas „ FastClasspathScanner“ . Jis tvarko daug įvairių klasių nuskaitymo užduočių tipų, turi paprastą API, dirba su daugeliu skirtingų klasių ClassLoaders ir classpath, yra kruopščiai lyginamas ir optimizuotas greitam ir mažam atminties naudojimui. Jis netgi gali sukurti „GraphViz“ klasės grafikos vizualizaciją, parodant, kaip klasės yra tarpusavyje susijusios.

Jei norite sužinoti pradinį klausimą apie visų paketų klasių ar sąsajų paiešką, galite:

 List<String> classNames = new FastClasspathScanner("com.mypackage").scan() .getNamesOfAllClasses(); 

Yra daug galimų parinkčių: išsamios informacijos rasite dokumentacijoje (žr. Aukščiau).

7
31 июля '16 в 4:48 2016-07-31 04:48 atsakymą pateikė Luke Hutchison, liepos 31 d. 16, 4:48 2016-07-31 04:48

Taip aš tai darau. Aš nuskaitysiu visus poaplankius (subpaketus) ir nenoriu atsisiųsti anoniminių klasių:

   private static List<Class> getClassesForPackage(String pckgname) throws ClassNotFoundException { // This will hold a list of directories matching the pckgname. There may be more than one if a package is split over multiple jars/paths ArrayList<File> directories = new ArrayList<File>(); String packageToPath = pckgname.replace('.', '/'); try { ClassLoader cld = Thread.currentThread().getContextClassLoader(); if (cld == null) { throw new ClassNotFoundException("Can't get class loader."); } // Ask for all resources for the packageToPath Enumeration<URL> resources = cld.getResources(packageToPath); while (resources.hasMoreElements()) { directories.add(new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8"))); } } catch (NullPointerException x) { throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Null pointer exception)"); } catch (UnsupportedEncodingException encex) { throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Unsupported encoding)"); } catch (IOException ioex) { throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + pckgname); } ArrayList<Class> classes = new ArrayList<Class>(); // For every directoryFile identified capture all the .class files while (!directories.isEmpty()){ File directoryFile = directories.remove(0); if (directoryFile.exists()) { // Get the list of the files contained in the package File[] files = directoryFile.listFiles(); for (File file : files) { // we are only interested in .class files if ((file.getName().endsWith(".class"))  (!file.getName().contains("$"))) { // removes the .class extension int index = directoryFile.getPath().indexOf(packageToPath); String packagePrefix = directoryFile.getPath().substring(index).replace('/', '.');; try { String className = packagePrefix + '.' + file.getName().substring(0, file.getName().length() - 6); classes.add(Class.forName(className)); } catch (NoClassDefFoundError e) { // do nothing. this class hasn't been found by the loader, and we don't care. } } else if (file.isDirectory()){ // If we got to a subdirectory directories.add(new File(file.getPath())); } } } else { throw new ClassNotFoundException(pckgname + " (" + directoryFile.getPath() + ") does not appear to be a valid package"); } } return classes; } 
5
17 авг. atsakymas pateikiamas Nadav B 17 d. 2016-08-17 23:54 '16 at 11:54 pm 2016-08-17 23:54

Sudėjau paprastą „github“ projektą, kuris išsprendžia šią problemą:

https://github.com/ddopson/java-class-enumerator

Ji turėtų veikti BOTH klasės failams ir jar failams.

Jei patikrinote projektą atlikdami komandų komandą, ji išspausdina:

  Cleaning... rm -rf build/ Building... javac -d build/classes src/pro/ddopson/ClassEnumerator.java src/test/ClassIShouldFindOne.java src/test/ClassIShouldFindTwo.java src/test/subpkg/ClassIShouldFindThree.java src/test/TestClassEnumeration.java Making JAR Files... jar cf build/ClassEnumerator_test.jar -C build/classes/ . jar cf build/ClassEnumerator.jar -C build/classes/ pro Running Filesystem Classpath Test... java -classpath build/classes test.TestClassEnumeration ClassDiscovery: Package: 'test' becomes Resource: 'file:/Users/Dopson/work/other/java-class-enumeration/build/classes/test' ClassDiscovery: Reading Directory '/Users/Dopson/work/other/java-class-enumeration/build/classes/test' ClassDiscovery: FileName 'ClassIShouldFindOne.class' => class 'test.ClassIShouldFindOne' ClassDiscovery: FileName 'ClassIShouldFindTwo.class' => class 'test.ClassIShouldFindTwo' ClassDiscovery: FileName 'subpkg' => class 'null' ClassDiscovery: Reading Directory '/Users/Dopson/work/other/java-class-enumeration/build/classes/test/subpkg' ClassDiscovery: FileName 'ClassIShouldFindThree.class' => class 'test.subpkg.ClassIShouldFindThree' ClassDiscovery: FileName 'TestClassEnumeration.class' => class 'test.TestClassEnumeration' Running JAR Classpath Test... java -classpath build/ClassEnumerator_test.jar test.TestClassEnumeration ClassDiscovery: Package: 'test' becomes Resource: 'jar:file:/Users/Dopson/work/other/java-class-enumeration/build/ClassEnumerator_test.jar!/test' ClassDiscovery: Reading JAR file: '/Users/Dopson/work/other/java-class-enumeration/build/ClassEnumerator_test.jar' ClassDiscovery: JarEntry 'META-INF/' => class 'null' ClassDiscovery: JarEntry 'META-INF/MANIFEST.MF' => class 'null' ClassDiscovery: JarEntry 'pro/' => class 'null' ClassDiscovery: JarEntry 'pro/ddopson/' => class 'null' ClassDiscovery: JarEntry 'pro/ddopson/ClassEnumerator.class' => class 'null' ClassDiscovery: JarEntry 'test/' => class 'null' ClassDiscovery: JarEntry 'test/ClassIShouldFindOne.class' => class 'test.ClassIShouldFindOne' ClassDiscovery: JarEntry 'test/ClassIShouldFindTwo.class' => class 'test.ClassIShouldFindTwo' ClassDiscovery: JarEntry 'test/subpkg/' => class 'null' ClassDiscovery: JarEntry 'test/subpkg/ClassIShouldFindThree.class' => class 'test.subpkg.ClassIShouldFindThree' ClassDiscovery: JarEntry 'test/TestClassEnumeration.class' => class 'test.TestClassEnumeration' Tests Passed. 

Taip pat žr. Mano kitą atsakymą.

4
25 окт. Dave Dopson atsakymas spalio 25 d 2012-10-25 00:49 '12 12:49 AM 2012-10-25 00:49

Taip, naudojant kelias API, kurias galite padaryti, kaip aš norėčiau tai padaryti, bėgo į šią problemą, kurią naudoju su miego branduoliu ir turėjau surasti klases, kurios komentuoja konkrečią anotaciją.

Atlikite šias pasirinktines anotacijas, naudodamiesi ženklu, kurias klases norite gauti.

 import java.> 

Tada pažymėkite savo klasę

 @EntityToBeScanned public MyClass{ } 

Sukurkite šią naudingumo klasę, kurioje yra toks metodas

 public class ClassScanner { public static Set<Class<?>> allFoundClassesAnnotatedWithEntityToBeScanned(){ Reflections reflections = new Reflections(".*"); Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(EntityToBeScanned.class); return annotated; } } 

Skambinkite metodu „ AllFoundClassesAnnotatedWithEntityToBeScanned“ (), kad gautumėte nustatytą klasių rinkinį .

Jums reikės žemiau pateiktų libs.

 <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>21.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.javassist/javassist --> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.22.0-CR1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.reflections/reflections --> <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency> 
4
08 февр. Atsakymą pateikė Sujal Mandal 08 Feb. 2017-02-08 13:57 '17, 13:57 2017-02-08 13:57

Bandau naudoti „Reflections“ biblioteką, bet turėjau tam tikrų problemų naudodamasis jais, ir buvo per daug skardinių, kuriuos turėjau įjungti tik norėdami gauti paketas.

Aš paskelbsiu šį dvigubą klausimą rastą sprendimą: kaip gauti visus paketo pavadinimus?

Atsakymą parašė sp00m ; Aš pridėjau keletą pataisų, kad galėčiau dirbti:

 import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; public final class ClassFinder { private final static char DOT = '.'; private final static char SLASH = '/'; private final static String CLASS_SUFFIX = ".class"; private final static String BAD_PACKAGE_ERROR = "Unable to get resources from path '%s'. Are you sure the given '%s' package exists?"; public final static List<Class<?>> find(final String scannedPackage) { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); final String scannedPath = scannedPackage.replace(DOT, SLASH); final Enumeration<URL> resources; try { resources = classLoader.getResources(scannedPath); } catch (IOException e) { throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage), e); } final List<Class<?>> classes = new LinkedList<Class<?>>(); while (resources.hasMoreElements()) { final File file = new File(resources.nextElement().getFile()); classes.addAll(find(file, scannedPackage)); } return classes; } private final static List<Class<?>> find(final File file, final String scannedPackage) { final List<Class<?>> classes = new LinkedList<Class<?>>(); if (file.isDirectory()) { for (File nestedFile : file.listFiles()) { classes.addAll(find(nestedFile, scannedPackage)); } //File names with the $1, $2 holds the anonymous inner classes, we are not interested on them. } else if (file.getName().endsWith(CLASS_SUFFIX)  !file.getName().contains("$")) { final int beginIndex = 0; final int endIndex = file.getName().length() - CLASS_SUFFIX.length(); final String className = file.getName().substring(beginIndex, endIndex); try { final String resource = scannedPackage + DOT + className; classes.add(Class.forName(resource)); } catch (ClassNotFoundException ignore) { } } return classes; } } 

Norėdami jį naudoti, tiesiog iškvieskite šiame pavyzdyje paminėtą paieškos metodą kaip sp00n: prireikus pridėjau klasių demonstraciją.

 List<Class<?>> classes = ClassFinder.find("com.package"); ExcelReporting excelReporting; for (Class<?> aClass : classes) { Constructor constructor = aClass.getConstructor(); //Create an object of the class type constructor.newInstance(); //... } 
3
03 дек. atsakymas duotas Martín C 03 dec. 2013-12-03 20:52 '13, 08:52 pm 2013-12-03 20:52

Turite pažvelgti į kiekvieną klasės krautuvo įrašą klasėje:

  String pkg = "org/apache/commons/> 

Jei įrašas yra katalogas, tiesiog ieškokite reikiamo pakatalogio:

 if (jar.isDirectory()) { File subdir = new File(jar, pkg); if (!subdir.exists()) continue; File[] files = subdir.listFiles(); for (File file : files) { if (!file.isFile()) continue; if (file.getName().endsWith(".class")) System.out.println("Found class: " + file.getName().substring(0, file.getName().length() - 6)); } } 

Jei įrašas yra jar faile, patikrinkite jo ZIP įrašus:

 else { // try to open as ZIP try { ZipFile zip = new ZipFile(jar); for (Enumeration<? extends ZipEntry> entries = zip .entries(); entries.hasMoreElements();) { ZipEntry entry = entries.nextElement(); String name = entry.getName(); if (!name.startsWith(pkg)) continue; name = name.substring(pkg.length() + 1); if (name.indexOf('/') < 0  name.endsWith(".class")) System.out.println("Found class: " + name.substring(0, name.length() - 6)); } } catch (ZipException e) { System.out.println("Not a ZIP: " + e.getMessage()); } catch (IOException e) { System.err.println(e.getMessage()); } }