मुझे जावा पैकेज में निहित कक्षाएं पढ़ने की जरूरत है। वे क्लास क्लासपैथ में हैं। मुझे यह कार्य सीधे जावा प्रोग्राम से करने की आवश्यकता है। क्या आप एक सरल तरीका जानते हैं?
List<Class> classes = readClassesFrom("my.package")
मुझे जावा पैकेज में निहित कक्षाएं पढ़ने की जरूरत है। वे क्लास क्लासपैथ में हैं। मुझे यह कार्य सीधे जावा प्रोग्राम से करने की आवश्यकता है। क्या आप एक सरल तरीका जानते हैं?
List<Class> classes = readClassesFrom("my.package")
जवाबों:
यदि आपके पास क्लासपैथ में स्प्रिंग है तो निम्न कार्य करेंगे।
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 = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);
मैं इस एक का उपयोग करता हूं, यह फाइलों या जार अभिलेखागार के साथ काम करता है
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;
}
स्प्रिंग ने एक उत्कृष्ट क्लासपैथ खोज फंक्शन लागू किया है PathMatchingResourcePatternResolver
। यदि आप classpath*
: उपसर्ग का उपयोग करते हैं , तो आप किसी दिए गए पदानुक्रम में कक्षाओं सहित सभी संसाधनों को पा सकते हैं, और यदि आप चाहें तो उन्हें फ़िल्टर भी कर सकते हैं। तो फिर तुम के बच्चों का उपयोग कर सकते AbstractTypeHierarchyTraversingFilter
, AnnotationTypeFilter
और AssignableTypeFilter
वर्ग के स्तर का एनोटेशन पर या तो उन संसाधनों फिल्टर करने के लिए या इंटरफेस पर उन्हें लागू करने।
जावा 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[]{});
}
ईजेबी पर्यावरण के भीतर इस समाधान का परीक्षण किया गया था ।
स्कैनोटेशन और प्रतिबिंब वर्ग पथ स्कैनिंग दृष्टिकोण का उपयोग करते हैं:
Reflections reflections = new Reflections("my.package");
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);
एक अन्य दृष्टिकोण एनोटेशन प्रोसेसर को लिखने के लिए जावा प्लगएबल एनोटेशन प्रोसेसिंग एपीआई का उपयोग करना है जो संकलन समय पर सभी एनोटेट कक्षाओं को इकट्ठा करेगा और रनटाइम उपयोग के लिए इंडेक्स फाइल का निर्माण करेगा। यह तंत्र ClassIndex लाइब्रेरी में लागू किया गया है:
Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");
जहाँ तक मुझे पता है कि कार्यक्षमता जावा प्रतिबिंब एपीआई से संदिग्ध रूप से गायब है। आप ऐसा करके एक पैकेज ऑब्जेक्ट प्राप्त कर सकते हैं:
Package packageObj = Package.getPackage("my.package");
लेकिन जैसा कि आपने शायद देखा, कि आप उस पैकेज में कक्षाओं को सूचीबद्ध नहीं करेंगे। जैसा कि अभी है, आपको एक और फाइलसिस्टम-ओरिएंटेड अप्रोच लेना होगा।
मैंने इस पोस्ट में कुछ नमूना कार्यान्वयन पाया
मुझे यकीन नहीं है कि ये विधियां तब काम करेंगी जब आपकी कक्षाएं JAR फाइलों में दफन हो जाएंगी, लेकिन मुझे उम्मीद है कि इनमें से एक आपके लिए है।
मैं @skaffman से सहमत हूं ... यदि आपके पास इस बारे में जाने का दूसरा तरीका है, तो मैं इसके बजाय ऐसा करने की सलाह दूंगा।
किसी दिए गए पैकेज में सभी वर्गों को सूचीबद्ध करने के लिए सबसे मजबूत तंत्र वर्तमान में क्लासग्राफ है , क्योंकि यह नए जेपीएमएस मॉड्यूल सिस्टम सहित क्लासपैथ विनिर्देशन तंत्र के व्यापक संभव सरणी को संभालता है। (मैं लेखक हूँ)
List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
.enableClassInfo().scan()) {
classNames = scanResult.getAllClasses().getNames();
}
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));
}
});
बिल बर्क ने एक अच्छा लेख लिखा है ( वर्ग स्कैनिंग के बारे में] और फिर उन्होंने स्कैननोटेशन लिखा ।
हाइबरनेट ने यह पहले ही लिखा है:
CDI इसे हल कर सकता है, लेकिन नहीं जानता - अभी तक पूरी तरह से जांच नहीं की गई है
।
@Inject Instance< MyClass> x;
...
x.iterator()
एनोटेशन के लिए भी:
abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
मैं इसे लागू करने के लिए हुआ हूं, और यह ज्यादातर मामलों में काम करता है। चूंकि यह लंबा है, इसलिए मैंने इसे एक फाइल में यहां रखा है ।
विचार वर्ग स्रोत फ़ाइल का स्थान खोजने के लिए है जो ज्यादातर मामलों में उपलब्ध है (एक ज्ञात अपवाद जेवीएम श्रेणी की फाइलें हैं - जहां तक मैंने परीक्षण किया है)। यदि कोड एक निर्देशिका में है, तो सभी फ़ाइलों और केवल स्पॉट क्लास फ़ाइलों के माध्यम से स्कैन करें। यदि कोड एक JAR फ़ाइल में है, तो सभी प्रविष्टियों को स्कैन करें।
इस विधि का उपयोग केवल तभी किया जा सकता है जब:
आपके पास एक वर्ग है जो उसी पैकेज में है जिसे आप खोजना चाहते हैं, इस वर्ग को सीडक्लास कहा जाता है। उदाहरण के लिए, यदि आप 'java.io' में सभी वर्गों को सूचीबद्ध करना चाहते हैं, तो बीज वर्ग हो सकता है java.io.File
।
आपकी कक्षाएं एक निर्देशिका या JAR फ़ाइल में होती हैं, जिसमें स्रोत फ़ाइल जानकारी होती है (स्रोत कोड फ़ाइल नहीं, बल्कि सिर्फ स्रोत फ़ाइल)। जहाँ तक मैंने कोशिश की है, यह जेवीएम वर्ग (उन कक्षाओं जेवीएम के साथ आता है) को छोड़कर लगभग 100% काम करता है।
आपके प्रोग्राम के पास उन वर्गों के प्रोटेक्शनडोमेन को एक्सेस करने की अनुमति होनी चाहिए। यदि आपका प्रोग्राम स्थानीय रूप से लोड किया गया है, तो कोई समस्या नहीं होनी चाहिए।
मैंने केवल अपने नियमित उपयोग के लिए कार्यक्रम का परीक्षण किया है, इसलिए इसमें अभी भी समस्या हो सकती है।
आशा है कि ये आपकी मदद करेगा।
यहाँ एक और विकल्प है, ऊपर / नीचे एक और उत्तर के लिए मामूली संशोधन:
Reflections reflections = new Reflections("com.example.project.package",
new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);
जब एप्लेट्स सामान्य स्थान पर थे, तो क्लासपाथ पर एक URL हो सकता है। जब क्लास-लोडर को क्लास की आवश्यकता होती है, तो वह HTTP संसाधनों सहित, क्लासपाथ पर सभी स्थानों को खोजेगा। क्योंकि आपके पास classpath पर URL और निर्देशिका जैसी चीजें हो सकती हैं, वर्गों की एक निश्चित सूची प्राप्त करने का कोई आसान तरीका नहीं है।
हालाँकि, आप बहुत करीब आ सकते हैं। कुछ स्प्रिंग लाइब्रेरी अब ऐसा कर रहे हैं। आप क्लास जार पर सभी जार प्राप्त कर सकते हैं, और उन्हें फ़ाइलों की तरह खोल सकते हैं। तब आप फ़ाइलों की इस सूची को ले सकते हैं, और अपनी कक्षाओं में डेटा संरचना बना सकते हैं।
निर्भरता मावेन का उपयोग करें:
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));
}
});
ब्रेंट - इसका कारण एसोसिएशन का एक तरीका यह है कि इस तथ्य के साथ कि आपके क्लास के किसी भी घटक पर कोई भी वर्ग खुद को किसी भी पैकेज (जावा / जेवैक्स को छोड़कर) में घोषित कर सकता है। इस प्रकार किसी दिए गए "पैकेज" में सभी कक्षाओं का कोई मानचित्रण नहीं है क्योंकि कोई भी नहीं जानता है और न ही जान सकता है। आप कल एक जार फ़ाइल को अपडेट कर सकते हैं और कक्षाएं हटा सकते हैं या जोड़ सकते हैं। यह दुनिया के सभी देशों में जॉन / जॉन / जोहान नाम के सभी लोगों की सूची प्राप्त करने की कोशिश करने जैसा है - हममें से कोई भी सर्वज्ञ नहीं है इसलिए हममें से किसी का भी सही उत्तर कभी नहीं होगा।