রানটাইমের সময় জাভা টীকা স্ক্যান করা [বন্ধ]


253

কোনও টীকাযুক্ত শ্রেণীর জন্য পুরো ক্লাসপথটি অনুসন্ধান করার সর্বোত্তম উপায় কী?

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

এটি করার জন্য আপনি কোনও গ্রন্থাগার বা জাভা সুবিধা জানেন?

সম্পাদনা: আমি জাভা ইই 5 ওয়েব পরিষেবাদি বা ইজেবি'র জন্য নতুন কার্যকারিতার মতো কিছু সম্পর্কে ভাবছি। আপনি @WebServiceবা আপনার ক্লাসটি টিকিয়ে দিন@EJB এবং লোড করার সময় সিস্টেম এই ক্লাসগুলি সন্ধান করে যাতে সেগুলি দূর থেকে অ্যাক্সেসযোগ্য।

উত্তর:


210

Org.springframework.context.annotation.ClassPathScanningCandidateCompenderProvider ব্যবহার করুন

এপিআই

একটি উপাদান সরবরাহকারী যা বেস প্যাকেজ থেকে ক্লাসপাথটি স্ক্যান করে। এরপরে এটি বাদ পড়ে এবং পরীক্ষার্থীদের সন্ধানের জন্য ফলাফল শ্রেণিতে ফিল্টার অন্তর্ভুক্ত করে।

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());

5
তথ্যের জন্য ধন্যবাদ. আপনি কি জানেন যে ক্লাসপাঠগুলি কীভাবে ক্লাসপাথ স্ক্যান করবেন যার ক্ষেত্রগুলিতে কাস্টম টিকা আছে?
জাভাটার

6
জাভাটার জাভার রিফ্লেকশন এপিআই ব্যবহার করুন। <YOUR_CLASS> .class.getFields () প্রতিটি ক্ষেত্রের জন্য, getAnnotation (<YOUR_ANNOTATION>) প্রার্থনা করুন
আর্থার রোনাল্ড

1
দ্রষ্টব্য: আপনি যদি একটি স্প্রিং অ্যাপ্লিকেশনের মধ্যে এটি করছেন তবে স্প্রিং এখনও @Conditionalটীকাগুলির উপর ভিত্তি করে মূল্যায়ন করবে এবং কাজ করবে । সুতরাং কোনও শ্রেণীর যদি তার @Conditionalমান মিথ্যা ফেরত findCandidateComponentsথাকে তবে এটি স্ক্যানারের ফিল্টারটির সাথে মিলে গেলেও এটি ফিরে আসবে না । এটি আমাকে আজ ছুড়ে ফেলেছে - পরিবর্তে আমি নীচে জোনাথনের সমাধানটি ব্যবহার করে শেষ করেছি।
অ্যাডাম

1
আর্থাররোনাল্ড দুঃখিত, আর্থার আমি বোঝাতে চাইছি যে BeanDefinitionঅবজেক্টটি সরাসরি ক্লাস পাওয়ার কোনও উপায় সরবরাহ করে না। নিকটতম জিনিসটি মনে হয় getBeanClassNameযা পুরোপুরি যোগ্যতাসম্পন্ন শ্রেণীর নাম দেয় তবে এই পদ্ধতির সঠিক আচরণটি পরিষ্কার নয়। এছাড়া, এটিও পরিষ্কার না বর্গ লোডার ক্লাসে পাওয়া যায়নি পারে।
ম্যাক্স

3
@ Class<?> cl = Class.forName(beanDef.getBeanClassName()); ম্যাক্স এটি
জেমস ওয়াটকিন্স

149

এবং অন্য সমাধান হ'ল গুগল প্রতিচ্ছবি

দ্রুত পর্যালোচনা:

  • স্প্রিং সলিউশনটি যদি আপনি স্প্রিং ব্যবহার করছেন তবে যাওয়ার উপায়। অন্যথায় এটি একটি বড় নির্ভরতা।
  • সরাসরি এএসএম ব্যবহার করা কিছুটা জটিল।
  • সরাসরি জাভা অ্যাসিস্ট ব্যবহার করা খুব জটিল।
  • এনোভেনশন হ'ল সুপার লাইটওয়েট এবং সুবিধাজনক। এখনও কোনও মাভেন ইন্টিগ্রেশন নেই।
  • গুগল সংগ্রহগুলি গুগলের প্রতিচ্ছবি টানছে s সমস্ত কিছু সূচক করে এবং তারপরে সুপার দ্রুত।

43
new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)। সি'স্ট টাউট
zapp

4
আমার কি কোনও প্যাকেজের নাম উল্লেখ করা দরকার? ওয়াইল্ডকার্ড? ক্লাসপথে সব ক্লাসের জন্য কী?
সানডে

1
সাবধান এটা এখনও জাভা 9 সমর্থন কোনো অগ্রগতি আছে: github.com/ronmamo/reflections/issues/186
Vadzim

org.refferences গ্রন্থাগারটি জাভা 13 এর অধীনে সঠিকভাবে কাজ করে না (সম্ভবত আগেও হতে পারে)। এটি প্রথমবার বলা হয়ে গেলে এটি ঠিক আছে বলে মনে হচ্ছে। পরবর্তী তাত্ক্ষণিকতা এবং ব্যবহারগুলি ব্যর্থ করে সার্চ ইউআরএলগুলি কনফিগার করা হয়নি তা বলে।
ইভভ

44

আপনি ক্লাসগ্রাফের সাথে যে কোনও প্রদত্ত টিকা দিয়ে ক্লাসগুলি খুঁজে পেতে পারেন , পাশাপাশি আগ্রহের অন্যান্য মানদণ্ডগুলির জন্য অনুসন্ধান করতে পারেন, যেমন প্রদত্ত ইন্টারফেস প্রয়োগ করে এমন ক্লাস। (দাবি অস্বীকার, আমি ক্লাসগ্রাফের লেখক।) ক্লাসগ্রাফ ক্লাসপ্যাথের সমস্ত শ্রেণীর জন্য বা ক্লাসের জন্য মেমরিতে পুরো শ্রেণি গ্রাফের (সমস্ত শ্রেণি, টীকা, পদ্ধতি, পদ্ধতির পরামিতি এবং ক্ষেত্রগুলি) একটি বিমূর্ত উপস্থাপনা তৈরি করতে পারে Class শ্বেত তালিকাভুক্ত প্যাকেজগুলি, এবং আপনি চান তবে ক্লাসের গ্রাফটি জিজ্ঞাসা করতে পারেন। ক্লাসগ্রাফ অন্য কোনও স্ক্যানারের চেয়ে ক্লাসপথ স্পেসিফিকেশন মেকানিজম এবং ক্লাসলোডারকে সমর্থন করে এবং নতুন জেপিএমএস মডিউল সিস্টেমের সাথে নির্বিঘ্নে কাজ করে, সুতরাং আপনি যদি ক্লাসগ্রাফে আপনার কোডটি বেস করেন তবে আপনার কোড সর্বাধিক বহনযোগ্য। এখানে এপিআই দেখুন।


1
এটি চালানোর জন্য কি জাভা 8 লাগবে?
ডেভিড জর্জ

1
জাভা 7 ব্যবহার করার জন্য আপডেট হয়েছে, কোনও সমস্যা নেই। কেবল টীকাগুলি সরান এবং বেনামে অভ্যন্তরীণ ক্লাসগুলি ব্যবহার করতে ফাংশনগুলিকে রূপান্তর করুন। আমি 1 ফাইল শৈলী পছন্দ করি। কোডটি একটি দুর্দান্ত একটি পরিষ্কার, তাই যদিও এটি আমার পছন্দ মতো কয়েকটি জিনিস সমর্থন করে না (ক্লাস + টীকাগুলি একই সাথে) আমি মনে করি এটি যুক্ত করা খুব সহজ easy মহান কাজ! যদি কেউ ভি 7 এর সংশোধন করার জন্য কাজটি পরিচালনা করতে না পারে তবে তাদের সম্ভবত এটি করা উচিত Reflections। এছাড়াও, আপনি যদি পেয়ারা / ইত্যাদি ব্যবহার করে থাকেন এবং পাই হিসাবে সহজেই সংগ্রহগুলি পরিবর্তন করতে চান। ভিতরে খুব দুর্দান্ত মন্তব্য।
অ্যান্ড্রু ব্যাকার

2
অ্যালেক্সান্দ্রসকে ধন্যবাদ, আপনার ক্লাসগ্রাফটি পরীক্ষা করা উচিত, এটি ফাস্টক্লাসপাথস্ক্যানারের চেয়ে উল্লেখযোগ্যভাবে উন্নত হয়েছে।
লুক হাচিসন

2
@ অ্যান্ড্রুব্যাকার ক্লাসগ্রাফ (ফাস্টক্লাসপাথস্ক্যানারের নতুন সংস্করণ) ফিল্টার বা সেট অপারেশনের মাধ্যমে বুলিয়ান অপারেশনের জন্য সম্পূর্ণ সমর্থন রয়েছে। কোডের উদাহরণগুলি এখানে দেখুন: github.com/classراف
লুক

1
@ লুক হ্যাচিসন ইতিমধ্যে ক্লাসগ্রাফ ব্যবহার করছেন। জাভা 10 এ মাইগ্রেশন করতে আমাকে সহায়তা করেছে সত্যই দরকারী লাইব্রেরি।
আলেকজান্দ্রোস

24

আপনি যদি সত্যই হালকা ওজন চান (কোনও নির্ভরতা, সহজ এপিআই, 15 কেবি জার ফাইল নেই) এবং খুব দ্রুত সমাধান চান annotation-detectorতবে https://github.com/rmuller/infomas-asl এ পাওয়া এক নজরে দেখুন

দাবি অস্বীকার: আমি লেখক।


20

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

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

উপরের প্রক্রিয়াটি ইতিমধ্যে ClassIndex লাইব্রেরিতে প্রয়োগ করা হয়েছে ।

এটি ব্যবহার করতে আপনার পছন্দসই টীকাকে @ ইন্ডেক্সঅনোটেটেড মেটা-টিকা দিয়ে ann এটি সংকলনের সময়ে একটি সূচি ফাইল তৈরি করবে: মেটা-আইএনএফ / টিকা / কম / টেস্ট / আপনার কাস্টমঅ্যানোটেশন সমস্ত টীকাযুক্ত শ্রেণীর তালিকা। আপনি সঞ্চালনের মাধ্যমে রানটাইমে সূচকটি বাড়িয়ে দিতে পারেন:

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

5

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

ক্লাসলোডার দিয়ে কেউ যদি এর উপর কিছু চেষ্টা করতে চায় তার পরেও, আমি প্যাকেজে ক্লাস থেকে টীকাগুলি মুদ্রণের জন্য নিজে থেকে কিছু লিখেছি:

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

এবং কনফিগ ফাইলে আপনি প্যাকেজের নাম রেখেছেন এবং এটি একটি শ্রেণিতে আনমশাল করে দিন।


3

বসন্তের সাথে আপনি এনিটেশন ইউটিলেস ক্লাসটি ব্যবহার করে কেবল নিম্নলিখিতটি লিখতে পারেন। অর্থাৎ,

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

আরও বিশদ এবং সমস্ত পৃথক পদ্ধতির জন্য অফিসিয়াল ডক্স পরীক্ষা করুন: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html


4
ভাল ধারণা, তবে আপনি যদি nullদ্বিতীয় প্যারামিটার হিসাবে মান রাখেন (যা শ্রেণিটি সংজ্ঞায়িত করে, যার মধ্যে উত্তরাধিকারক্রমক্রম হ'ল স্প্রিং একটি এনটোটেশন ব্যবহার করে এমন একটি ক্লাসের জন্য স্ক্যান করবে), nullবাস্তবায়ন অনুসারে আপনি সর্বদা ফিরে পাবেন ।
jonashackt


2

ক্লাসলোডার এপিআই-তে একটি "গণনা" পদ্ধতি নেই, কারণ শ্রেণি লোডিং একটি "অন-ডিমান্ড" ক্রিয়াকলাপ - আপনার ক্লাসপথে সাধারণত হাজার হাজার ক্লাস থাকে, কেবলমাত্র একটি অংশের প্রয়োজন হবে (আরটি.জার আজকাল 48MB একা!)।

সুতরাং, এমনকি যদি আপনি সমস্ত শ্রেণি গণনা করতে পারেন তবে এটি খুব সময় এবং স্মৃতিশক্তি গ্রহণকারী হবে।

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



1

গুগল প্রতিচ্ছবি বসন্তের তুলনায় অনেক দ্রুত বলে মনে হচ্ছে। এই বৈশিষ্ট্যটির অনুরোধটি খুঁজে পেয়েছে যা এই পার্থক্যটিকে সমাধান করে: http://www.opensaga.org/jira/browse/OS-738

এটি প্রতিবিম্বগুলি ব্যবহার করার কারণ হিসাবে আমার অ্যাপ্লিকেশনটির শুরু হওয়ার সময়টি বিকাশের সময় সত্যই গুরুত্বপূর্ণ is প্রতিবিম্বগুলি আমার ব্যবহারের ক্ষেত্রে ব্যবহার করা খুব সহজ বলে মনে হয় (একটি ইন্টারফেসের সমস্ত প্রয়োগকারী খুঁজুন)।


1
আপনি যদি জিরার ইস্যুকে লক্ষ্য করেন তবে সেখানে মন্তব্য রয়েছে যে স্থিতিশীলতার কারণে তারা প্রতিচ্ছবি থেকে দূরে সরে গেছে।
উইম দেবলাউয়

1

আপনি যদি প্রতিচ্ছবিগুলির বিকল্পের সন্ধান করেন তবে আমি পান্ডার ইউটিলিটিস - অ্যানোটেশনস স্ক্যানার সুপারিশ করতে চাই । প্রতিচ্ছবি গ্রন্থাগার উত্স কোডের উপর ভিত্তি করে এটি একটি পেয়ারাবিহীন (পেয়ারাতে M 3MB, পান্ডা ইউটিলিটিসের 200 ডলার) স্ক্যানার রয়েছে।

এটি ভবিষ্যত-ভিত্তিক অনুসন্ধানগুলির জন্যও উত্সর্গীকৃত। আপনি যদি একাধিকবার অন্তর্ভুক্ত উত্সগুলি স্ক্যান করতে চান বা এমন কোনও এপিআই সরবরাহ করতে চান যা বর্তমান শ্রেণিপথ স্ক্যান করে এমন কাউকে মঞ্জুরি দেয় , যাতে AnnotationsScannerProcessসমস্ত ক্যাচ করা হয় ClassFiles, তাই এটি সত্যিই দ্রুত।

ব্যবহারের সহজ উদাহরণ AnnotationsScanner:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);

1

বসন্ত একটি AnnotatedTypeScannerশ্রেণি বলে কিছু আছে ।
এই শ্রেণিটি অভ্যন্তরীণভাবে ব্যবহার করে

ClassPathScanningCandidateComponentProvider

এই শ্রেণীর ক্লাসপথ সংস্থানগুলির প্রকৃত স্ক্যানিংয়ের কোড রয়েছে । এটি রানটাইমের সময়ে ক্লাস মেটাডেটা ব্যবহার করে এটি করে।

যে কেউ এই ক্লাসটি প্রসারিত করতে বা স্ক্যান করার জন্য একই শ্রেণি ব্যবহার করতে পারে। নীচে কনস্ট্রাক্টরের সংজ্ঞা দেওয়া হল।

/**
     * Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
     * 
     * @param considerInterfaces whether to consider interfaces as well.
     * @param annotationTypes the annotations to scan for.
     */
    public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {

        this.annotationTypess = Arrays.asList(annotationTypes);
        this.considerInterfaces = considerInterfaces;
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.