لماذا لا يتمكن JAXB من العثور على jaxb.index الخاص بي عند التشغيل داخل Apache Felix؟

StackOverflow https://stackoverflow.com/questions/1043109

  •  20-08-2019
  •  | 
  •  

سؤال

إنه هناك، في الحزمة التي يجب فهرستها.ومع ذلك، عندما أتصل

JAXBContext jc = JAXBContext.newInstance("my.package.name");

أحصل على JAXBException يقول ذلك

"my.package.name" لا يحتوي على ObjectFactory.class أو jaxb.index

على الرغم من أنه يحتوي على كليهما.

ما ينجح، لكنه ليس ما أريده تمامًا، هو

JAXBContext jc = JAXBContext.newInstance(my.package.name.SomeClass.class);

يظهر هذا السؤال من أشخاص آخرين في بعض القوائم البريدية والمنتديات ولكن يبدو أنه لا يحصل على إجابات.

أقوم بتشغيل هذا على OpenJDK 6، لذا حصلت على الحزم المصدرية وقمت بإدخال مصحح الأخطاء إلى المكتبة.يبدأ بالبحث عن jaxb.properties، ثم يبحث عن خصائص النظام ويفشل في العثور على أي منهما، ويحاول إنشاء السياق الافتراضي باستخدام com.sun.internal.xml.bind.v2.ContextFactory.هناك، يتم طرح الاستثناء (داخل ContextFactor.createContext(String ClassLoader, Map))، ولكن لا أستطيع أن أرى ما يحدث لأن المصدر ليس هنا.

الوقت المتوقع للوصول:

انطلاقًا من الكود المصدري لـ ContentFactory، وجدت هنا, ، فمن المحتمل أن يكون هذا هو الجزء من التعليمات البرمجية الذي فشل في العمل على النحو المنشود:

/**
 * Look for jaxb.index file in the specified package and load it's contents
 *
 * @param pkg package name to search in
 * @param classLoader ClassLoader to search in
 * @return a List of Class objects to load, null if there weren't any
 * @throws IOException if there is an error reading the index file
 * @throws JAXBException if there are any errors in the index file
 */
private static List<Class> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException, JAXBException {
    final String resource = pkg.replace('.', '/') + "/jaxb.index";
    final InputStream resourceAsStream = classLoader.getResourceAsStream(resource);

    if (resourceAsStream == null) {
        return null;
    }

من وجهة نظري سابق خبرة, أعتقد أن هذا يتعلق بآليات تحميل الفئة لحاوية OSGi التي يعمل فيها هذا.لسوء الحظ، ما زلت بعيدًا قليلاً عن عمقي هنا.

هل كانت مفيدة؟

المحلول

حسنًا، استغرق هذا بعض البحث، لكن الإجابة ليست مفاجئة وليست معقدة حتى:

لا يمكن لـ JAXB العثور على jaxb.index، لأنه بشكل افتراضي، newInstance(String) يستخدم محمل فئة مؤشر الترابط الحالي (كما تم إرجاعه بواسطة Thread.getContextClassLoader()).لا يعمل هذا داخل Felix، لأن حزم OSGi وخيوط إطار العمل تحتوي على أدوات تحميل فئة منفصلة.

الحل هو الحصول على مُحمل فئة مناسب من مكان ما واستخدامه newInstance(String, ClassLoader).لقد حصلت على مُحمل فئة مناسب من إحدى الفئات الموجودة في الحزمة التي تحتوي على jaxb.index, ، ربما يكون هذا اختيارًا معقولًا لأسباب تتعلق بالمرونة ObjectFactory:

ClassLoader cl = my.package.name.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("my.package.name", cl);

ربما يمكنك أيضًا الوصول إلى مُحمل الفصل الذي يحتوي على Bundle يتم استخدام المثال، لكن لم أتمكن من معرفة كيفية القيام بذلك، ويبدو الحل أعلاه آمنًا بالنسبة لي.

نصائح أخرى

لقد واجهت مشكلة مماثلة مع المشروع الذي أعمل عليه.بعد القراءة http://jaxb.Java.net/faq/index.html#classloader أدركت أن JAXBContext غير قادر على العثور على الحزمة التي تحتوي على jaxb.index.

سأحاول أن أجعل هذا الأمر واضحًا قدر الإمكان.

لدينا

Bundle A
   -- com.a
      A.java
        aMethod()
        {
            B.bMethod("com.c.C");
        }
MANIFEST.MF
Import-Package: com.b, com.c         

Bundle B
   -- com.b
      B.java
        bmethod(String className)
        {
            Class clazz = Class.forName(className);
        }

Export-Package: com.b

Bundle C
   -- com.c
      C.java
        c()
        {
            System.out.println("hello i am C");
        }

Export-Package: com.c

لتتصل جاكسب. الفئة B هي JAXBContext وbMethod هي newInstance()

إذا كنت على دراية بقيود حزمة OSGi، فيجب أن يكون الأمر واضحًا جدًا الآن الحزمة ب لا يتم استيراد الحزمة com.c أي فئة ج يكون غير مرئية ل الصف ب وبالتالي لا يمكن إنشاء مثيل C.

الحل سيكون بتمرير أ ClassLoader إلى طريقة ب.يجب أن يأتي ClassLoader هذا من ملف الحزمة التي تستورد com.c.في هذه الحالة يمكننا المرور A.class.getClassLoader() منذ تقوم الحزمة A باستيراد com.c

نأمل أن يكون هذا مفيدا.

بالنسبة لنفس المشكلة، قمت بحلها عن طريق وضع الحزمة يدويًا في عملية الاستيراد.

إذا كنت تستخدم maven في مشروعك، فما عليك سوى استخدام هذه المكتبة:

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-osgi</artifactId>
    <version>2.2.7</version>
</dependency>

تم إنشاؤه لخادم Glasfish ولكنه يعمل أيضًا مع Tomcat (محدد).مع هذه المكتبة يمكنك بسهولة استخدام JAXB مع حزم OSGI.

تحرير 2:

لقد واجهت ذات مرة مشكلة تحميل فئة غريبة مماثلة في طلبي.إذا قمت بتشغيله كتطبيق عادي، كان كل شيء على ما يرام ولكن عندما قمت باستدعائه كخدمة Windows، بدأ بالفشل مع ClassNotFoundExceptions.أظهر التحليل أن سلاسل الرسائل تحتوي على أدوات تحميل الفصل الخاصة بها على أنها فارغة بطريقة أو بأخرى.لقد قمت بحل المشكلة عن طريق تعيين SystemClassLoader على المواضيع:

// ...
thread.setContextClassLoader(ClassLoader.getSystemClassLoader());
thread.start();
// ...

لا أعرف ما إذا كانت الحاوية الخاصة بك تسمح بهذا النوع من التغيير أم لا.

لقد واجهت للتو هذه المشكلة.بالنسبة لي، كان الحل هو استخدام JRE الخاص بشركة IBM بدلاً من Oracle.يبدو أن تطبيق JAXB أكثر ملاءمة لـ OSGI في هذا التطبيق.

لقد نجحت في حل هذه المشكلة عن طريق إضافة حزمة الفئات التي تم إنشاؤها والتي تحتوي على ObjectFactory إلى <Private-Package> جزء من تعريف الحزمة الخاصة بي، بالإضافة إلى org.jvnet.jaxb2_commons.*

قد يكون هناك سيناريو آخر يمكن أن يسبب هذه المشكلة.

عند تثبيت وبدء تشغيل حزمة تقوم بتصدير الحزمة التي تحتوي على jaxb.index أو objectFactory.java

ثم يرجى التأكد من إيقاف الحزم التي تستورد الفئات أو الإشارة إلى اسم الحزمة الصحيح.

تحقق أيضًا من بيانات التصدير والاستيراد في ملف pom.xml

واجهت مشكلة مماثلة في حاوية Servicemix(karaf) osgi

بالنسبة لي كانت المشكلة هي أن اختبار الوحدة الذي لم يكن مرتبطًا بالوحدة التي قمت بتطويرها لم يكن له تبعية في pom.xml لوحدتي.لا يزال UT يتعرف على الوحدة الخاصة بي بسبب جلب قائمة الحزم من ملف التكوين المشترك.

عند تشغيل UT، لم يقم بتجميع الوحدة الجديدة لذلك لم ينشئ ObjectFactory.java لذلك تلقيت الخطأ على الرغم من أنني عندما قمت بتجميع الوحدة تمكنت من رؤية ObjectFactory.java

تمت إضافة التبعية التالية:

<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>

الحل الخاص بي كان:

سياق JAXBContext = JAXBContext.newInstance(فئة جديدة[]{"my.package.name"});

أو

سياق JAXBContext = JAXBContext.newInstance(فئة جديدة[]{class.getName()});

أو

الحل الكامل:

public static <T> T deserializeFile(Class<T> _class, String _xml) {

        try {

            JAXBContext context = JAXBContext.newInstance(new Class[]{_class});
            Unmarshaller um = context.createUnmarshaller();

            File file = new File(_xml);
            Object obj = um.unmarshal(file);

            return _class.cast(obj);

        } catch (JAXBException exc) {
            return null;
        }
    }

يعمل 100%

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top