ক্লাসপথে জাভা প্যাকেজ থেকে সমস্ত ক্লাস কীভাবে পড়ব?


95

আমার একটি জাভা প্যাকেজে থাকা ক্লাসগুলি পড়তে হবে। সেই ক্লাসগুলি ক্লাসপথে রয়েছে। আমার সরাসরি কোনও জাভা প্রোগ্রাম থেকে এই কাজটি করা দরকার। আপনি কি একটি সহজ উপায় জানেন?

List<Class> classes = readClassesFrom("my.package")

7
সহজভাবে বলুন, না, আপনি এটি সহজেই করতে পারবেন না। কিছু চূড়ান্ত কৌশল অবলম্বন করে যা কিছু পরিস্থিতিতে কাজ করে তবে আমি দৃ a়ভাবে একটি আলাদা ডিজাইনের পরামর্শ দিই।
স্কাফম্যান


সমাধানটি ওয়েল্ড প্রকল্পে পাওয়া যেতে পারে ।
ওন্দ্রা Žižka

উত্তরের জন্য এই লিঙ্কটি দেখুন: stackoverflow.com/questions/176527/…
কার্তিক ই

উত্তর:


49

আপনার যদি স্প্রিং ইন ক্লাসপথ থাকে তবে নীচেরগুলি এটি করবে।

একটি প্যাকেজে সমস্ত শ্রেণীর সন্ধান করুন যা এক্সএমএল রুটএলিমেন্টের সাথে টীকাযুক্ত রয়েছে:

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;
}

কোড স্নিপেট জন্য ধন্যবাদ। :) আপনি যদি প্রার্থীদের তালিকায় ক্লাসের সদৃশতা এড়াতে চান তবে সংগ্রহের ধরনটি তালিকা থেকে সেট এ পরিবর্তন করুন। এবং ক্লাসমেটাডেটা'র এনক্লোজিংক্লাস () এবং getEnclosingClassName () ব্যবহার করুন। অন্তর্নিহিত শ্রেণির সম্পর্কে getEnclosingClass পদ্ধতিটি ব্যবহার করুন
ট্রাপার

29

আপনি এখানে বর্ণিত প্রতিচ্ছবি প্রকল্প ব্যবহার করতে পারেন

এটি বেশ সম্পূর্ণ এবং সহজেই ব্যবহারযোগ্য।

উপরের ওয়েবসাইট থেকে সংক্ষিপ্ত বিবরণ:

প্রতিচ্ছবিগুলি আপনার ক্লাসপাথটিকে স্ক্যান করে, মেটাডেটা সূচী করে, আপনাকে রানটাইমে এটি অনুসন্ধানের অনুমতি দেয় এবং আপনার প্রকল্পের মধ্যে অনেকগুলি মডিউলগুলির জন্য তথ্যটি সংরক্ষণ এবং সংগ্রহ করতে পারে।

উদাহরণ:

Reflections reflections = new Reflections(
    new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);

ইকুইনক্সে কাজ হয়? এবং যদি তা হয় তবে এটি প্লাগিনগুলি সক্রিয় না করে এটি করতে পারে?
ট্যাগ করুন

বিষুবক্ষ জন্য কাজ করে। প্রতিচ্ছবিগুলির পুরানো সংস্করণগুলিতে, বান্ডিল জার ভিএফএসটাইপ যুক্ত করুন। দেখতে এখানে
zapp

28

আমি এটি ব্যবহার করি এটি ফাইল বা জার সংরক্ষণাগারগুলির সাথে কাজ করে

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;
}

4
এই কাজ যদি আপনি File.Separator রেফারেন্স এবং মাত্র ব্যবহার খুঁজে নিতে '/'
উইল গ্লাস

4
যখন পাথে ফাঁকা স্থান রয়েছে তখন জার ফাইলগুলির সাথে কাজ করার জন্য আরও একটি পরিবর্তন প্রয়োজন। আপনার অবশ্যই জার ফাইলের পাথটি ডিকোড করতে হবে। পরিবর্তন: jarFileName = packageURL.getFile (); থেকে: jarFileName = URLDecoder.decode (packageURL.getFile ());
উইল গ্লাস

আমি কেবল প্যাকেজের নাম পাত্রে পাই ... ক্লাসের নাম
পাচ্ছি না

নতুন ফাইল (uri) স্পেস সহ আপনার সমস্যাটি সমাধান করবে।
ট্রেজকাজ

এন্ট্রি নেম.লাইস্ট ইন্ডেক্সঅফ ('।') হবে -1
মার্সটোন

11

বসন্তে একটি দুর্দান্ত ক্লাসপাথ অনুসন্ধান ফাংশন বাস্তবায়ন করেছে PathMatchingResourcePatternResolver। আপনি যদি classpath*: উপসর্গটি ব্যবহার করেন তবে আপনি প্রদত্ত শ্রেণিবদ্ধ শ্রেণিতে সমস্ত সংস্থান সন্ধান করতে পারেন এবং আপনি চাইলে এগুলি ফিল্টারও করতে পারেন। তারপর আপনি সন্তান ব্যবহার করতে পারেন AbstractTypeHierarchyTraversingFilter, AnnotationTypeFilterএবং AssignableTypeFilterবর্গ স্তর টীকা উপর পারেন যারা সম্পদ ফিল্টার করতে বা ইন্টারফেসগুলি তারা বাস্তবায়ন।


6

জাভা 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[]{});
}

এই সমাধানটি ইজেবি পরিবেশের মধ্যে পরীক্ষা করা হয়েছিল ।


6

স্ক্যানোটেশন এবং প্রতিচ্ছবি শ্রেণীর পাথ স্ক্যানিং পদ্ধতির ব্যবহার করে:

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

আরেকটি উপায় হ'ল এনভাটেশন প্রসেসর লিখতে জাভা প্লাগেবল অ্যানোটেশন প্রসেসিং এপিআই ব্যবহার করা যা সংকলন সময়ে সমস্ত টীকাগুলি শ্রেণি সংগ্রহ করবে এবং রানটাইম ব্যবহারের জন্য সূচি ফাইলটি তৈরি করবে। এই প্রক্রিয়াটি ClassIndex লাইব্রেরিতে প্রয়োগ করা হয়েছে :

Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");

4

প্রদত্ত প্যাকেজে সমস্ত শ্রেণি তালিকাভুক্ত করার জন্য সবচেয়ে শক্তিশালী প্রক্রিয়াটি বর্তমানে ক্লাসগ্রাফ , কারণ এটি নতুন জেপিএমএস মডিউল সিস্টেম সহ শ্রেণিপথ স্পেসিফিকেশন ব্যবস্থার বিস্তৃত সম্ভাব্য অ্যারে পরিচালনা করে । (আমি লেখক।)

List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
        .enableClassInfo().scan()) {
    classNames = scanResult.getAllClasses().getNames();
}

আমি এই কয়েক বছর পরে এসেছি। এটা খুব ভালো একটা যন্ত্র! এটি প্রতিবিম্বের তুলনায় অনেক দ্রুত কাজ করে এবং আমি পছন্দ করি যে এটি স্ট্যাটিক আরম্ভকারীদের ডাকবে না। আমাদের যে সমস্যাটি ছিল তা সমাধান করার জন্য আমার যা প্রয়োজন ছিল তা ঠিক।
akagixxer

3

সেই কার্যকারিতাটি এখনও পর্যন্ত আমার জানা হিসাবে জাভা প্রতিবিম্ব API থেকে সন্দেহজনকভাবে অনুপস্থিত। আপনি কেবল এটি করে একটি প্যাকেজ বস্তু পেতে পারেন:

Package packageObj = Package.getPackage("my.package");

তবে আপনি সম্ভবত লক্ষ্য করেছেন, এটি আপনাকে সেই প্যাকেজে ক্লাসগুলি তালিকাবদ্ধ করতে দেবে না। এই মুহূর্তে, আপনাকে আরও একটি ফাইল সিস্টেম-ভিত্তিক পদ্ধতির বাছাই করতে হবে।

আমি এই পোস্টে কিছু নমুনা বাস্তবায়ন পেয়েছি

আমি 100% নিশ্চিত নই যে যখন আপনার ক্লাসগুলি জেআর ফাইলগুলিতে সমাহিত করা হবে তখন এই পদ্ধতিগুলি কার্যকর হবে তবে আমি আশা করি যে এর মধ্যে একটি আপনার জন্য এটি করবে।

আমি @ স্কাফম্যানের সাথে একমত ... আপনার যদি এই সম্পর্কে আরও কিছু উপায় থাকে তবে আমি পরিবর্তে এটি করার পরামর্শ দিই।


4
এটি সন্দেহজনক নয়, এটি ঠিক সেভাবে কাজ করে না। ক্লাসগুলি প্যাকেজের সাথে "সম্পর্কিত" নয়, তাদের কাছে উল্লেখ রয়েছে re সমিতি অন্য দিক নির্দেশ করে না।
স্কাফম্যান

4
@ স্কাফম্যান খুব আকর্ষণীয় বিষয়। কখনও সেভাবে সে সম্পর্কে ভাবেননি। সুতরাং যতক্ষণ আমরা এই চিন্তার পথটিকে ঘুরে বেড়াচ্ছি, কেন সমিতিটি দ্বি-দিকনির্দেশক নয় (এটি এখন আমার নিজের কৌতূহলের জন্য আরও বেশি)?
ব্রেন্ট লিখেছেন কোড

2

eXtcos আশাব্যঞ্জক দেখাচ্ছে। আপনি যে সমস্ত শ্রেণীর সন্ধান করতে চান তা কল্পনা করুন:

  1. "উপাদান" শ্রেণি থেকে প্রসারিত করুন এবং সেগুলি সংরক্ষণ করুন
  2. "মাই কম্পোম্পোনেন্ট" দিয়ে টিকা দেওয়া হয় এবং
  3. "সাধারণ" প্যাকেজে রয়েছে।

এক্সটাকোসের সাথে এটি যতটা সহজ

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));
    }
});

2
  1. বিল বার্ক একটি লিখেছেন ( ক্লাস স্ক্যানিং সম্পর্কে দুর্দান্ত নিবন্ধ ] এবং তারপরে তিনি স্ক্যানোটেশন লিখেছিলেন ।

  2. হাইবারনেট এটি ইতিমধ্যে লিখেছেন:

    • org.hibernate.ejb.packaging.Scanner
    • org.hibernate.ejb.packaging.NativeScanner
  3. সিডিআই এটি সমাধান করতে পারে তবে জানে না - এখনও পুরোপুরি তদন্ত করে নি

@Inject Instance< MyClass> x;
...
x.iterator() 

টীকাগুলির জন্যও:

abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}

নিবন্ধটির লিঙ্কটি মারা গেছে।
ব্যবহারকারী 2418306

1

আমি এটি প্রয়োগ করেছি এবং বেশিরভাগ ক্ষেত্রে এটি কাজ করে। যেহেতু এটি দীর্ঘ, আমি এটি এখানে একটি ফাইলে রাখি ।

ক্লাস সোর্স ফাইলের অবস্থানটি সন্ধান করা হ'ল বেশিরভাগ ক্ষেত্রে পাওয়া যায় (একটি পরিচিত ব্যতিক্রম জেভিএম ক্লাস ফাইলগুলি - যতদূর আমি পরীক্ষা করেছি)। কোডটি যদি কোনও ডিরেক্টরিতে থাকে তবে সমস্ত ফাইল এবং কেবল স্পট শ্রেণির ফাইলগুলির মাধ্যমে স্ক্যান করুন। কোডটি কোনও জেআর ফাইলে থাকলে সমস্ত এন্ট্রি স্ক্যান করুন।

এই পদ্ধতিটি কেবল তখনই ব্যবহার করা যেতে পারে:

  1. আপনি আবিষ্কার করতে চান একই প্যাকেজের মধ্যে আপনার একটি ক্লাস রয়েছে, এই শ্রেণিকে বলা হয় বীডক্লাস। উদাহরণস্বরূপ, আপনি যদি 'java.io' তে সমস্ত শ্রেণীর তালিকা করতে চান তবে বীজ বর্গ হতে পারে java.io.File

  2. আপনার ক্লাসগুলি একটি ডিরেক্টরিতে বা একটি জেআর ফাইলে রয়েছে এতে উত্স ফাইলের তথ্য রয়েছে (উত্স কোড ফাইল নয়, তবে কেবল উত্স ফাইল)। আমি যতদূর চেষ্টা করেছি, এটি জেভিএম ক্লাস বাদে প্রায় 100% কাজ করে (যারা ক্লাসগুলি জেভিএম নিয়ে আসে)।

  3. আপনার প্রোগ্রামটি অবশ্যই এই শ্রেণীর সুরক্ষাডমিন অ্যাক্সেস করার অনুমতি থাকতে হবে। আপনার প্রোগ্রামটি যদি স্থানীয়ভাবে লোড হয় তবে কোনও সমস্যা হবে না।

আমি প্রোগ্রামটি কেবলমাত্র আমার নিয়মিত ব্যবহারের জন্য পরীক্ষা করেছি তাই এখনও সমস্যা হতে পারে।

আশা করি এটা কাজে লাগবে.


4
এটি একটি খুব আকর্ষণীয় জিনিস বলে মনে হচ্ছে! আমি এটি ব্যবহার করার চেষ্টা করব। যদি আমি আমার জন্য সহায়ক মনে করি তবে আমি কি আপনার কোডটি ওপেন সোর্স প্রকল্পে ব্যবহার করতে পারি?

4
আমি এটি ওপেন-সোর্স করার প্রস্তুতি নিচ্ছি। সুতরাং এগিয়ে যান: ডি
নবামন

@ নওয়ামন: আপনি কি শেষ পর্যন্ত এটি প্রকাশ করেছেন? যদি তাই হয়: আমরা শেষ সংস্করণটি কোথায় খুঁজে পাব? ধন্যবাদ!
জোয়ানিস

1

এখানে আরও একটি বিকল্প, উপরে / নীচে অন্য উত্তরে সামান্য পরিবর্তন:

Reflections reflections = new Reflections("com.example.project.package", 
    new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses = 
    reflections.getSubTypesOf(Object.class);

0

অ্যাপলেটগুলি যখন সাধারণ জায়গায় ছিল তখন ফিরে ক্লাসপথে একটির URL থাকতে পারে। ক্লাস লোডার যখন কোনও ক্লাসের প্রয়োজন হয়, তখন এটি http সংস্থানগুলি সহ শ্রেণিপথের সমস্ত অবস্থান অনুসন্ধান করে। ক্লাসপথে ইউআরএল এবং ডিরেক্টরিগুলির মতো জিনিস থাকতে পারে বলে ক্লাসগুলির একটি নির্দিষ্ট তালিকা পাওয়ার সহজ উপায় নেই।

তবে, আপনি খুব কাছাকাছি পেতে পারেন। কিছু স্প্রিং লাইব্রেরি এখন এটি করছে। আপনি ক্লাসপথে সমস্ত বয়াম পেতে এবং সেগুলি ফাইলে খুলতে পারেন। তারপরে আপনি ফাইলগুলির এই তালিকাটি নিতে পারেন এবং আপনার ক্লাসগুলি সহ একটি ডেটা স্ট্রাকচার তৈরি করতে পারেন।


0

নির্ভরতা মেভেন ব্যবহার করুন:

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));
            }
        });

-2

ব্রেন্ট - এই সমিতিটির একটি উপায় হওয়ার কারণে আপনার ক্লাসস্প্যাথের যে কোনও উপাদানের যে কোনও শ্রেণি কোনও প্যাকেজে নিজেকে ঘোষণা করতে পারে (জাভা / জাভ্যাক্স বাদে)। সুতরাং কেবলমাত্র প্রদত্ত "প্যাকেজ" -এ সমস্ত শ্রেণীর ম্যাপিং নেই কারণ কেউ জানে বা জানতে পারে না। আপনি আগামীকাল একটি জার ফাইল আপডেট করতে এবং ক্লাসগুলি সরাতে বা যুক্ত করতে পারেন। এটি বিশ্বের সমস্ত দেশে জন / জোন / জোহান নামের সমস্ত ব্যক্তির একটি তালিকা পাওয়ার চেষ্টা করার মতো - আমাদের মধ্যে কেউই সর্বজ্ঞ নয় তাই আমাদের কারওরও সঠিক উত্তর হবে না।


দুর্দান্ত দার্শনিক উত্তর, কিন্তু সিডিআই শিম স্ক্যানিং কিভাবে কাজ করে? বা হাইবারনেট কীভাবে @ ওয়েবসাইটগুলি স্ক্যান করে?
ওন্দ্রা Žižka
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.