2017-02-14 4 views
0

Ich versuche, eine Instanz einer Klasse aus JAR-Datei in einem Byte-Array geladen zu erstellen.

Ich erhalte zwei argumente:
1. byte [], die mit der erforderlichen Klasse JAR-Datei repräsentiert
2. qualifizierten Klassennamen

Wenn ich es lokal zu testen bin es funktioniert wie erwartet, aber wenn ich hochladen genau die gleiche JAR-Datei mit dem gleichen qualifizierten Klassennamen remote (mithilfe der mit Spring MVC für Back und AngularJS für das Front-End im Tomcat-Server implementierten Webanwendung). Es kann die erforderliche Klasse nicht gefunden werden:
java.lang.ClassNotFoundException

Als ich debugging, drehte es sich t, dieser Klassenlader wird korrekt aufgerufen, aber keine Klasse wird von jar geladen.

Ich wäre dankbar, wenn jemand sagen kann, was der Grund für diesen Unterschied sein kann oder wie kann ich diese Funktionalität auf andere Weise implementieren.


Eine Methode, die Klasse lädt und gibt eine Instanz davon:
Problem mit der Ladeklasse aus JAR-Datei als Byte-Array dargestellt

public static <T> T getInstanceOfLoadedClass(byte[] jarFileBytes, String qualifiedClassName) throws ClassFromJarInstantiationException { 
    LOGGER.info("Getting instance of class from loaded jar file. Class name: " + qualifiedClassName); 
    try { 
     return (T) Class.forName(qualifiedClassName, true, new ByteClassLoader(jarFileBytes)).newInstance(); 
    } catch (InstantiationException | IllegalAccessException | IOException | ClassNotFoundException | NoSuchFieldException e) { 
     LOGGER.error("Exception was thrown while reading jar file for " + qualifiedClassName + "class.", e); 
     throw new ClassFromJarInstantiationException(e); 
    } 
} 

Individuelle ByteClassLoader:

public class ByteClassLoader extends ClassLoader { 
    private static final Logger LOGGER = Logger.getLogger(ByteClassLoader.class); 
    private final byte[] jarBytes; 
    private final Set<String> names; 

    public ByteClassLoader(byte[] jarBytes) throws IOException { 
     this.jarBytes = jarBytes; 
     this.names = loadNames(jarBytes); 
    } 

    private Set<String> loadNames(byte[] jarBytes) throws IOException { 
     Set<String> set = new HashSet<>(); 
     try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) { 
      ZipEntry entry; 
      while ((entry = jis.getNextEntry()) != null) { 
       set.add(entry.getName()); 
      } 
     } 
     return Collections.unmodifiableSet(set); 
    } 

    @Override 
    public InputStream getResourceAsStream(String resourceName) { 
     if (!names.contains(resourceName)) { 
      return null; 
     } 
     boolean found = false; 
     ZipInputStream zipInputStream = null; 
     try { 
      zipInputStream = new ZipInputStream(new ByteArrayInputStream(jarBytes)); 
      ZipEntry entry; 
      while ((entry = zipInputStream.getNextEntry()) != null) { 
       if (entry.getName().equals(resourceName)) { 
        found = true; 
        return zipInputStream; 
       } 
      } 
     } catch (IOException e) { 
      LOGGER.error("ByteClassLoader threw exception while reading jar byte stream for resource: "+resourceName, e); 
      e.printStackTrace(); 
     } finally { 
      if (zipInputStream != null && !found) { 
       try { 
        zipInputStream.close(); 
       } catch (IOException e) { 
        LOGGER.error("ByteClassLoader threw exception while closing jar byte stream for resource: "+resourceName, e); 
        e.printStackTrace(); 
       } 
      } 
     } 
     return null; 
    } } 

Antwort

0

Das Problem war, dass die Klasse in einem Bereich war zu ladende erforderlich von Classloader, während es getestet wurde.
Hoffe es hilft jemandem bei der Lösung dieses Problems, weil es wirklich leicht zu übersehen ist.

Verwandte Themen