Avatar billede jespersahner Nybegynder
27. august 2005 - 18:07 Der er 33 kommentarer og
1 løsning

Udskrive indholdet af classpath

Hvordan udskriver jeg indholdet af classpath i en kørende Java-session?
Avatar billede jespersahner Nybegynder
27. august 2005 - 18:11 #1
Jeg har brug for at kende classpath umiddelbart før jeg loader en klasse vha. en classloader.
Avatar billede erikjacobsen Ekspert
27. august 2005 - 18:21 #2
String classPath=x.getProperty("java.class.path");
  String a[]=classPath.split(":");

  for (int i=0;i<a.length;i++) {
            out.println(a[i]);
                out.println("<br>");
  }
Avatar billede erikjacobsen Ekspert
27. august 2005 - 18:21 #3
Og det var fra en JSP-side. Du skal måske bruge System.out
Avatar billede simonvalter Praktikant
27. august 2005 - 18:26 #4
Split på System.getProperty( "path.separator" );
Avatar billede erikjacobsen Ekspert
27. august 2005 - 18:29 #5
Man bruger vel Unix, ik'? 

Skulle man være afhængig af Windows, så enten:

    String a[]=classPath.split(";");

eller som Simon foreslår ;)
Avatar billede arne_v Ekspert
27. august 2005 - 18:33 #6
jeg vil foreslå:

        ClassLoader cl = this.getClass().getClassLoader();
        while(cl != null) {
            if(cl instanceof URLClassLoader) {
                URL[] urls = ((URLClassLoader)cl).getURLs();
                for(int i = 0; i < urls.length; i++) {
                    System.out.println(urls[i]);
                }
            }
            cl = cl.getParent();
        }
Avatar billede arne_v Ekspert
27. august 2005 - 18:40 #7
hvis din applikation er en helt normal applikation så vil forskellen på min og
java.class.path propertyen kun være at min har Java RT med (hvilket jo næppe
er interessant)

men hvis din klasse er loadet af en speciel classloader så kan forskellen være
endda meget stor, fordi min tager de classloadere som faktisk bruges mens
propertyen kun angiver status ved start af java kommandoen
Avatar billede jespersahner Nybegynder
27. august 2005 - 18:57 #8
->arne_v: Min klasse er load'et af en URLCLassLoader.

Vender tilbage i morgen..
Avatar billede jespersahner Nybegynder
28. august 2005 - 10:06 #9
Tak for de hurtige inputs! Jeg har brugt Arnes metode of får det ønskede. Egentlig en stump kode, der er rar at have i sin eget utility-pakke :-) Smid gerne et svar.
Avatar billede arne_v Ekspert
28. august 2005 - 10:49 #10
den kommer faktisk også fra noget JSP kode (fordi i Java web apps er det standard
med mange classloadere):

<%@ page import="java.net.*" %>
<ul>
<%
    ClassLoader cl = this.getClass().getClassLoader();
    while(cl != null) {
        %>
        <li><%=cl.getClass().getName()%></li>
        <%
        if(cl instanceof URLClassLoader) {
            %>
            <ul>
            <%
            URL[] urls = ((URLClassLoader)cl).getURLs();
            for(int i = 0; i < urls.length; i++) {
                %>
                <li><%=urls[i]%></li>
                <%
            }
            %>
            </ul>
            <%
        }
        cl = cl.getParent();
    }
%>
</ul>
Avatar billede arne_v Ekspert
28. august 2005 - 10:49 #11
og svar
Avatar billede jespersahner Nybegynder
30. august 2005 - 07:44 #12
->arne_v: Kan man føje til classpath i en kørende session?
Avatar billede arne_v Ekspert
30. august 2005 - 09:17 #13
du kan tilføje nye classloadere

men jeg tror ikke at du kan ændre URL's for eksisterende classloadere

det kunne vist give både inkonsistens og underminere java security modellen
Avatar billede jespersahner Nybegynder
30. august 2005 - 11:32 #14
->arne_v: Jeg bevæger mig måske ud på lidt tynd is her, men jeg prøver alligevel..

Lad os sige, at jeg ønsker at loade en ny klasse, som er placeret i "mitdirectory".Hertil bruger jeg en classloader:
ClassLoader cl=new URLClassLoader(new URL[]{(new File("mitdirectory")).toURL()});
Class c=cl.loadClass("klasse");

Antag videre at der i den klasse, der skal load'es er referencer til klasser, som IKKE er indeholdt i classpath'en for den kørende Java-session (og antag at disse klasser findes i classpath_extra). I så fald vil klassen ikke load'e men kaste en ClassNotFoundException.

Hvordan får jeg i den situation alligevel load'et klassen, hvis ikke classpath'en for den kørende Java-session indeholder classpath_extra? Med andre ord: Hvordan får jeg føjet classpath_extra til på run-time?
Avatar billede arne_v Ekspert
30. august 2005 - 11:45 #15
hvis du angiver classpath_extra  som en yderligere URL til cl, så kan du vel
loade "klasse" med cl
Avatar billede jespersahner Nybegynder
30. august 2005 - 13:17 #16
->arne_v: Jamen, naturligvis! Somme tider er det ikke til at se skoven for bar træer :-)
Avatar billede jespersahner Nybegynder
30. august 2005 - 23:20 #17
->arne_v: Det driller dog stadig en smule.

Flg. virker fint:
Object o1=Class.forName("klasse").newInstance();
Object o2=(Interface1)o1;

Den load'ede klasse "klasse" implementerer interface't Interface1. Så langt så godt.

Jeg prøver nu at erstatte Class.forName() med en specifik classloader:
o1=(new URLClassLoader(new URL[]{(new File("c:/...")).toURL().loadClass("klasse").newInstance();
Object o2=(Interface1)o1;

Nu får jeg en ClassCastException i linie 2, mens linie 1 ikke fejler.

Hvad pokker kan det skyldes?
Avatar billede jespersahner Nybegynder
30. august 2005 - 23:25 #18
->arne_v: Jeg har sågar forsøgt lidt debug mellem linie 1 og 2:
Class[] cl=o.getClass().getInterfaces();
for (int i=0;i<cl.length;i++) {
  System.out.println("Interface: "+cl[i].getName());
}
- og output er:
Interface1

Hrmpf!
Avatar billede arne_v Ekspert
30. august 2005 - 23:29 #19
implementerer "klasse" dinclassloader|Interface1 mens du caster til
standardclassloader|Interface1 ?
Avatar billede jespersahner Nybegynder
30. august 2005 - 23:30 #20
->arne_v: Der skulle vist stå:
o1=(new URLClassLoader(new URL[]{(new File("c:/...")).toURL()})).loadClass("klasse").newInstance();
Avatar billede jespersahner Nybegynder
30. august 2005 - 23:33 #21
->arne_v: Det er nok noget i den retning, der er problemet. Hvordan kommer jeg tættere på det?
Avatar billede arne_v Ekspert
30. august 2005 - 23:35 #22
kan du ikke fjerne Interface1 fra det sted hvor din egen classloader loader fra ?
Avatar billede jespersahner Nybegynder
30. august 2005 - 23:38 #23
->arne_v: Jo, måske nok. Vil det løse problemet, fordi dinclassloader|Interface1 så at sige detekteres før standardclassloader|Interface1?
Avatar billede arne_v Ekspert
30. august 2005 - 23:42 #24
det tror jeg

og det er nærmest omvendt
Avatar billede jespersahner Nybegynder
30. august 2005 - 23:49 #25
->arne_v: Ja, problemet er ganske rigtigt, at samme interface loades af to forskellige classloader'e. Jeg har nu noget at arbejde videre med. Tak for din hjælp i denne sene time!
Avatar billede simonvalter Praktikant
30. august 2005 - 23:58 #26
Avatar billede jespersahner Nybegynder
31. august 2005 - 00:51 #27
->simonvalter: Interessant!
Avatar billede arne_v Ekspert
31. august 2005 - 20:26 #28
meget interessant

jeg er overrasket over at det kan lade sig gøre

men en af pointerne må jo være at den appender til sidst

og man kan jo godt sige at

jar1 jar2 jar3

og

jar1 jar2
jar3

er rimeligt ekvivalente
Avatar billede jespersahner Nybegynder
05. september 2005 - 21:21 #29
->arne_v: Et tillægsspm. til din kommentar 30/08-2005 23:29:46:

Hvorfor load'es Interface1 med dinclassloader, når samme Interface1 allerede er load'et med standardclassloader?
Avatar billede arne_v Ekspert
06. september 2005 - 20:44 #30
det har du egentligt ret i

tilføjer du noget dynamisk til der hvor de enkelte classloadere søger ?
Avatar billede jespersahner Nybegynder
07. september 2005 - 16:33 #31
->arne_v: Problemet her er vist, at jeg arbejder i et "lokalt" miljø (inde i NetBeans), hvor alle klasser er load'et af en custom NetBeans classloader. Når jeg så kommer med min egen URLClassLoader går det galt, idet min URLClassLoader (og dens parents) ikke omfatter NetBeans-classloader'en. Med andre ord vil jeg reload'e interface't, idet min classloader ikke kan se, at dette allerede er load'et. Hvis jeg skal have det til at virke, skal jeg nok føje NetBeans-classloader'en til min egen URLClassLoader.

Givet at jeg står for at skulle definere min URLClassLoader med efterfølgende kald til Class.forName(), skal jeg vel blot føje this.getClass().getClassLoader() til min URLClassLoader. Det kan man vel godt, tænker jeg.
Avatar billede arne_v Ekspert
07. september 2005 - 20:05 #32
starter netbeans ikke en ny JVM når den kører dit program ?
Avatar billede jespersahner Nybegynder
08. september 2005 - 00:20 #33
->arne_v: Jo, det gør den, men jeg opererer i NetBeans IDE-JVM'en.

NetBeans er udover at være en IDE også en udviklingsplatform, som er modulært opbygget. Man kan selv skrive moduler, som tilføjer funktionalitet til platformen (måske ved du alt dette i forvejen), og det er i sådant et modul jeg arbejder, idet jeg har en eksisterende applikation, som jeg ønsker at bygge ind i NetBeans.

Tingene kompliceres af, at jeg bruger en del dynamisk kompilering/class-loading (ud fra et input fra brugeren, som modtages og "parses" gennem editoren), så jeg er lidt i tvivl om, jeg skal integrere hele applikationen i et NetBeans-modul (som dermed kører i samme JVM som NetBeans) - eller om jeg skal starte en ny JVM (som NetBeans gør, når et program afvikles på normal vis).

Integration som modul i samme JVM letter kommunikationen applikationen og NetBeans men der kræves nogen "housekeeping" for alligevel at holde tingene adskilt, bla. skal applikationen operere med egne classloadere, men det har jeg nu efterhånden fået til at virke bla. med hjælp fra din hånd :-)

Med en løsning med to JVM'er, er det nemmere at holde tingene adskilt (specielt omkring classloading), men omvendt er kommunikationen mellem JVM'erne så en anden udfordring. Her skal jeg måske overveje at bruge RMI som "grænseflade" mellem de to JVM'er i fald jeg vælger denne løsning.
Avatar billede jespersahner Nybegynder
08. september 2005 - 00:33 #34
->arne_v: Kommentar til 07/09-2005 16:33:24:

Dette var super-nemt, idet URLClassLoader har en constructor, der præcis kan tilføje en anden classloader: URLClassLoader(URL[] urls, ClassLoader parent),

- hvor ClassLoader parent blot her er: this.getClass().getClassLoader()

På denne måde sikres forbindelsen mellem de allerede load'ede klasser og de klasser, der load'es dynamisk. URLClassLoader'en er blot en udvidelse af classloader'en for den aktuelle klasse (this.getClass()). Egentlig helt oplagt, når man ved det :-)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester