আমার একটি জাভা প্যাকেজে থাকা ক্লাসগুলি পড়তে হবে। সেই ক্লাসগুলি ক্লাসপথে রয়েছে। আমার সরাসরি কোনও জাভা প্রোগ্রাম থেকে এই কাজটি করা দরকার। আপনি কি একটি সহজ উপায় জানেন?
List<Class> classes = readClassesFrom("my.package")
আমার একটি জাভা প্যাকেজে থাকা ক্লাসগুলি পড়তে হবে। সেই ক্লাসগুলি ক্লাসপথে রয়েছে। আমার সরাসরি কোনও জাভা প্রোগ্রাম থেকে এই কাজটি করা দরকার। আপনি কি একটি সহজ উপায় জানেন?
List<Class> classes = readClassesFrom("my.package")
উত্তর:
আপনার যদি স্প্রিং ইন ক্লাসপথ থাকে তবে নীচেরগুলি এটি করবে।
একটি প্যাকেজে সমস্ত শ্রেণীর সন্ধান করুন যা এক্সএমএল রুটএলিমেন্টের সাথে টীকাযুক্ত রয়েছে:
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");
প্রদত্ত প্যাকেজে সমস্ত শ্রেণি তালিকাভুক্ত করার জন্য সবচেয়ে শক্তিশালী প্রক্রিয়াটি বর্তমানে ক্লাসগ্রাফ , কারণ এটি নতুন জেপিএমএস মডিউল সিস্টেম সহ শ্রেণিপথ স্পেসিফিকেশন ব্যবস্থার বিস্তৃত সম্ভাব্য অ্যারে পরিচালনা করে । (আমি লেখক।)
List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
.enableClassInfo().scan()) {
classNames = scanResult.getAllClasses().getNames();
}
সেই কার্যকারিতাটি এখনও পর্যন্ত আমার জানা হিসাবে জাভা প্রতিবিম্ব API থেকে সন্দেহজনকভাবে অনুপস্থিত। আপনি কেবল এটি করে একটি প্যাকেজ বস্তু পেতে পারেন:
Package packageObj = Package.getPackage("my.package");
তবে আপনি সম্ভবত লক্ষ্য করেছেন, এটি আপনাকে সেই প্যাকেজে ক্লাসগুলি তালিকাবদ্ধ করতে দেবে না। এই মুহূর্তে, আপনাকে আরও একটি ফাইল সিস্টেম-ভিত্তিক পদ্ধতির বাছাই করতে হবে।
আমি এই পোস্টে কিছু নমুনা বাস্তবায়ন পেয়েছি
আমি 100% নিশ্চিত নই যে যখন আপনার ক্লাসগুলি জেআর ফাইলগুলিতে সমাহিত করা হবে তখন এই পদ্ধতিগুলি কার্যকর হবে তবে আমি আশা করি যে এর মধ্যে একটি আপনার জন্য এটি করবে।
আমি @ স্কাফম্যানের সাথে একমত ... আপনার যদি এই সম্পর্কে আরও কিছু উপায় থাকে তবে আমি পরিবর্তে এটি করার পরামর্শ দিই।
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));
}
});
বিল বার্ক একটি লিখেছেন ( ক্লাস স্ক্যানিং সম্পর্কে দুর্দান্ত নিবন্ধ ] এবং তারপরে তিনি স্ক্যানোটেশন লিখেছিলেন ।
হাইবারনেট এটি ইতিমধ্যে লিখেছেন:
সিডিআই এটি সমাধান করতে পারে তবে জানে না - এখনও পুরোপুরি তদন্ত করে নি
।
@Inject Instance< MyClass> x;
...
x.iterator()
টীকাগুলির জন্যও:
abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
আমি এটি প্রয়োগ করেছি এবং বেশিরভাগ ক্ষেত্রে এটি কাজ করে। যেহেতু এটি দীর্ঘ, আমি এটি এখানে একটি ফাইলে রাখি ।
ক্লাস সোর্স ফাইলের অবস্থানটি সন্ধান করা হ'ল বেশিরভাগ ক্ষেত্রে পাওয়া যায় (একটি পরিচিত ব্যতিক্রম জেভিএম ক্লাস ফাইলগুলি - যতদূর আমি পরীক্ষা করেছি)। কোডটি যদি কোনও ডিরেক্টরিতে থাকে তবে সমস্ত ফাইল এবং কেবল স্পট শ্রেণির ফাইলগুলির মাধ্যমে স্ক্যান করুন। কোডটি কোনও জেআর ফাইলে থাকলে সমস্ত এন্ট্রি স্ক্যান করুন।
এই পদ্ধতিটি কেবল তখনই ব্যবহার করা যেতে পারে:
আপনি আবিষ্কার করতে চান একই প্যাকেজের মধ্যে আপনার একটি ক্লাস রয়েছে, এই শ্রেণিকে বলা হয় বীডক্লাস। উদাহরণস্বরূপ, আপনি যদি 'java.io' তে সমস্ত শ্রেণীর তালিকা করতে চান তবে বীজ বর্গ হতে পারে java.io.File
।
আপনার ক্লাসগুলি একটি ডিরেক্টরিতে বা একটি জেআর ফাইলে রয়েছে এতে উত্স ফাইলের তথ্য রয়েছে (উত্স কোড ফাইল নয়, তবে কেবল উত্স ফাইল)। আমি যতদূর চেষ্টা করেছি, এটি জেভিএম ক্লাস বাদে প্রায় 100% কাজ করে (যারা ক্লাসগুলি জেভিএম নিয়ে আসে)।
আপনার প্রোগ্রামটি অবশ্যই এই শ্রেণীর সুরক্ষাডমিন অ্যাক্সেস করার অনুমতি থাকতে হবে। আপনার প্রোগ্রামটি যদি স্থানীয়ভাবে লোড হয় তবে কোনও সমস্যা হবে না।
আমি প্রোগ্রামটি কেবলমাত্র আমার নিয়মিত ব্যবহারের জন্য পরীক্ষা করেছি তাই এখনও সমস্যা হতে পারে।
আশা করি এটা কাজে লাগবে.
এখানে আরও একটি বিকল্প, উপরে / নীচে অন্য উত্তরে সামান্য পরিবর্তন:
Reflections reflections = new Reflections("com.example.project.package",
new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);
অ্যাপলেটগুলি যখন সাধারণ জায়গায় ছিল তখন ফিরে ক্লাসপথে একটির URL থাকতে পারে। ক্লাস লোডার যখন কোনও ক্লাসের প্রয়োজন হয়, তখন এটি http সংস্থানগুলি সহ শ্রেণিপথের সমস্ত অবস্থান অনুসন্ধান করে। ক্লাসপথে ইউআরএল এবং ডিরেক্টরিগুলির মতো জিনিস থাকতে পারে বলে ক্লাসগুলির একটি নির্দিষ্ট তালিকা পাওয়ার সহজ উপায় নেই।
তবে, আপনি খুব কাছাকাছি পেতে পারেন। কিছু স্প্রিং লাইব্রেরি এখন এটি করছে। আপনি ক্লাসপথে সমস্ত বয়াম পেতে এবং সেগুলি ফাইলে খুলতে পারেন। তারপরে আপনি ফাইলগুলির এই তালিকাটি নিতে পারেন এবং আপনার ক্লাসগুলি সহ একটি ডেটা স্ট্রাকচার তৈরি করতে পারেন।
নির্ভরতা মেভেন ব্যবহার করুন:
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));
}
});
ব্রেন্ট - এই সমিতিটির একটি উপায় হওয়ার কারণে আপনার ক্লাসস্প্যাথের যে কোনও উপাদানের যে কোনও শ্রেণি কোনও প্যাকেজে নিজেকে ঘোষণা করতে পারে (জাভা / জাভ্যাক্স বাদে)। সুতরাং কেবলমাত্র প্রদত্ত "প্যাকেজ" -এ সমস্ত শ্রেণীর ম্যাপিং নেই কারণ কেউ জানে বা জানতে পারে না। আপনি আগামীকাল একটি জার ফাইল আপডেট করতে এবং ক্লাসগুলি সরাতে বা যুক্ত করতে পারেন। এটি বিশ্বের সমস্ত দেশে জন / জোন / জোহান নামের সমস্ত ব্যক্তির একটি তালিকা পাওয়ার চেষ্টা করার মতো - আমাদের মধ্যে কেউই সর্বজ্ঞ নয় তাই আমাদের কারওরও সঠিক উত্তর হবে না।