2015-11-07 6 views
0

Мне нужно использовать пользовательский ClassLoader для загрузки сторонних драйверов. План состоит в том, что драйверы - это просто общие архивы jar, но с суффиксом .dar (архив драйверов). Эти архивы затем просто добавляются в путь к классам, в то время как jvm игнорирует это расширение файла и обрабатывает файлы dar, такие как ресурсы (что означает игнорирование файлов классов внутри).Пользовательский загрузчик классов, загружающий jar, дает мне строку Illegal UTF8 в постоянном пуле в файле класса

Теперь моя проблема в том, что мой загрузчик классов дает мне строку Illegal UTF8 в постоянном пуле в исключении файла класса. Как я мог обойти это?

public class DriversClassLoader extends ClassLoader { 

    public DriversClassLoader() { 
     super(ClassLoader.getSystemClassLoader()); 
    } 

    @Override 
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 
     if(name.startsWith("java.")) { 
      return super.loadClass(name, resolve); 
     } else { 
      // see if we have already loaded the class. 
      Class<?> c = findLoadedClass(name); 
      if (c != null) return c; 

      try { 
       URL driversUrl = super.getResource("drivers.dar").toURI().toURL(); 
       System.out.println(driversUrl); 
       JarInputStream jis = new JarInputStream(driversUrl.openConnection().getInputStream()); 

       ZipEntry entry; 
       while ((entry = jis.getNextEntry()) != null) { 
        if (entry.getName().matches(name)) { 
         System.out.println("loading: " + entry); 
         byte[] cBytes = new byte[(int) entry.getSize()]; 
         jis.read(cBytes, 0, cBytes.length); 

         // this is where I get the exception 
         c = defineClass(name, cBytes, 0, cBytes.length); 
         if (resolve) resolveClass(c); 
         return c; 
        } 
       } 
      } catch (Exception e) { 
       throw new ClassNotFoundException("loading of class " + name + " failed", e); 
      } 

      // else delegate to parent 
      return super.loadClass(name, resolve); 

      /* 
      URL res = getResource(name); 
      if (res == null) throw new ClassNotFoundException("Class " + name + "not found in:"); 

      try { 
       byte[] cBytes = IOUtils.toByteArray(new InputStreamReader(res.openStream())); 
       c = defineClass(name, cBytes, 0, cBytes.length); 
       if (resolve) resolveClass(c); 
       return c; 
      } catch (Exception e) { 
       throw new ClassNotFoundException("loading of class " + name + " failed", e); 
      } 

      // delegate to parent 
      return super.loadClass(name, resolve);*/ 
     } 
    } 

    @Override 
    public URL getResource(String name) { 
     try { 
      URL driversUrl = super.getResource("drivers.dar").toURI().toURL(); 
      System.out.println(driversUrl); 
      JarInputStream jis = new JarInputStream(driversUrl.openConnection().getInputStream()); 

      ZipEntry entry; 
      while ((entry = jis.getNextEntry()) != null) { 

       if (entry.getName().matches(name)) { 
        System.out.println(entry); 
        return new URL("jar:" + driversUrl + "!/" + entry); 
       } 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     // delegate to parent 
     return super.getResource(name); 
    } 

    @Override 
    public Enumeration<URL> getResources(String name) throws IOException { 
     //super.get 
     return super.getResources(name); 
    } 
} 

Тогда я просто

Class<?> aClass = Class.forName("a.class", false, new DriverClassLoader()); 
System.out.println("aclass = " + aClass); 

EDIT 1: Но файл содержит допустимые классы:

java -cp ../rangeCache/src/main/resources/drivers.dar pkg.test.Test 

Выходы Привет из DAR баночке

Хотя это не делает:

java -cp target/libs/range-cache-302-SNAPSHOT.jar:drivers/ com.data.cache.range.drivers.DriversClassLoader 
jar:file:/home/rangeCache/target/libs/range-cache-302-SNAPSHOT.jar!/drivers.dar 
loading: com/data/cache/range/drivers/DatastaxCassandraDriver.class 
Exception in thread "main" java.lang.ClassFormatError: Illegal UTF8 string in constant pool in class file com/data/cache/range/drivers/DatastaxCassandraDriver/class 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642) 
    at com.mindbusters.data.cache.range.drivers.DriversClassLoader.loadClass(DriversClassLoader.java:40) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Class.java:348) 
    at com.data.cache.range.drivers.DriversClassLoader.main(DriversClassLoader.java:105) 
+0

Коррумпированные файлы классов или не файлы классов вообще. – Kayaman

+0

@ Каяман в архиве содержит допустимые классы: java -cp ../rangeCache/src/main/resources/drivers.dar pkg.test.Test работает как ожидалось – KIC

ответ

2

Ваш код для чтения байтов из ZipEntry не работает.

Вы не должны полагаться на ZipEntry.getSize(), так как -1 может быть возвращен, если не известен (см. Javadocs).

Тогда InputStream.read(byte[], int , int) может читать less байт, чем запрашивалось. Вы должны прочитать байты в цикле до тех пор, пока не будет возвращено -1 или используйте IOUtils.toByteArray, как вы уже делали один раз.

Смежные вопросы