Avatar billede tobiashm Nybegynder
16. juli 2003 - 00:46 Der er 20 kommentarer og
1 løsning

load af jar i applet

Jeg vil gerne loade en jar-fil med classer fra min applet, så jeg senere kan instanser af disse. Men kan ikke få det til at virke pt.

Helt konkret vil jeg loade en jaxp pakke hvis brugeren ikke har jre 1.4+ (hvor jaxp er med) installeret.
Så jeg checker på f.eks:

try { Class.forName("org.xml.sax.XMLReader"); }
catch (ClassNotFoundException ignore) {
  ...
  URLClassLoader ucl = URLClassLoader(urls);
}

men jeg vil gerne slippe for at skulle kalde

Class c = ucl.loadClass(...);
Object o = c.newInstance();

for hver gang.
Vil gerne bare senere i koden kunne skrive

XMLReader xmlreader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();

Skal ucl have appletens classloader (ala this.getClass.getClassLoader()) som parent?
Kan ikke hitte helt styr på de classloadere :-(
Avatar billede arne_v Ekspert
16. juli 2003 - 06:08 #1
Du er klar over at en JAXP implementation er kvart-stor ?

(ca. 1 MB)
Avatar billede arne_v Ekspert
16. juli 2003 - 06:09 #2
Og du vil naturligvis ikke bruge den simple løsning: at lade alle
hente JAXP implementationen med en:
  Class-Path: jar-fil
i manifestet på din jar-fil ?
Avatar billede arne_v Ekspert
16. juli 2003 - 06:12 #3
Jeg vil mene at du "bare" skal have:
  - en classloader der virker
  - bruge den classloader til at loade den klasse der kalder
    XML klasserne med (så burde den blive brugt til at loade XML klasserne med)
Avatar billede tobiashm Nybegynder
16. juli 2003 - 10:24 #4
Ja, okay, det er ikke hele JAXP jeg vil have med ;-) Bare crimson.jar el.l.

Fik også lige kigget kortvarigt på det med class-path i manifest-filen. Hvis det virker, er det selvfølgelig smartest/mest elegant.

Må lige prøve det af.
Avatar billede arne_v Ekspert
16. juli 2003 - 10:33 #5
Det virker.

Det er lavet præcist til formålet.

Ulempen er at alle også dem der kører 1.4 henter den over nettet.

Crimson er ikke så stor kun 200K. Ikke noget problem over LAN eller ADSL. Men
over analog modem vil det kunne mærkes.
Avatar billede tobiashm Nybegynder
16. juli 2003 - 23:48 #6
En classloader der "bare" virker ;-)
Jeg har desvære bare ikke kunne få noget til at virke...
Avatar billede arne_v Ekspert
16. juli 2003 - 23:50 #7
class-path i jar-fil ??
Avatar billede arne_v Ekspert
16. juli 2003 - 23:51 #8
Det burde være lige ud af landevejen.

En special classloder er lidt mere tricky. Men jeg kan godt lave
et eksempel.
Avatar billede tobiashm Nybegynder
17. juli 2003 - 00:01 #9
Jo jo - class-path virker fint.
Men det resulterer i at jar filen bliver sendt med over, og det som sådan det jeg ville undgå.
Avatar billede tobiashm Nybegynder
17. juli 2003 - 00:01 #10
Så det er det med classloaderen der driller
Avatar billede arne_v Ekspert
17. juli 2003 - 00:07 #11
Jeg finder lige den kode.
Avatar billede arne_v Ekspert
17. juli 2003 - 00:15 #12
Du får det "råt".

C:\classloader\Test.java

import java.net.*;
import java.lang.reflect.*;

public class Test {
    public static void main(String[] args) throws Exception {
        URL[] url = new URL[1];
        url[0] = new URL("file:/C:/classloader/");
        ClassLoader cl = new SpecialClassLoader(url);
        Object o = Class.forName("Wrapper", true, cl).newInstance();
        Class[] noc = new Class[0];
        Object[] noo = new Object[0];
        Method m = o.getClass().getMethod("execute",noc);
        m.invoke(o, noo);
    }
}

C:\classloader\Dummy.java

public class Dummy {
    public void hello() {
        System.out.println("Hello");
    }
}

C:\classloader\SpecialClassLoader.java

import java.net.*;

public class SpecialClassLoader extends URLClassLoader {
    public SpecialClassLoader(URL[] url) throws Exception {
        super(url);
    }
}

C:\classloader\Wrapper.java

public class Wrapper {
    public Wrapper() {
    }
    public void execute() {
        Dummy d = new Dummy();
        d.hello();
    }
}

javac *.java
copy Test.class without
copy SpecialClassLoader.class without
copy Test.class with
copy SpecialClassLoader.class with
copy Dummy.class with
cd with
java Test
cd ..
cd without
java Test
cd ..

with og without er directories under.

Det er meget meget vigtigt at Wrapper.class ikke er i without (i normal
classpath), fordi så virker det ikke !
Avatar billede tobiashm Nybegynder
17. juli 2003 - 00:23 #13
Jeg får en:
java.lang.InstantiationException: com.mypackage.MyApplet$MyRunnable
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    ...

og MyRunnable har en 'tom' constructor og er ikke abstract eller interface, så iflg. api docs betyder det "or if the instantiation fails for some other reason."
Avatar billede arne_v Ekspert
17. juli 2003 - 08:33 #14
Har du lavet en ClassLoader klasse, puttet denne i din jar, ændret URL
for denne til at indeholde både jar med Wrapper og Crimson jar ?
Avatar billede tobiashm Nybegynder
17. juli 2003 - 10:27 #15
Hvad skulle der være i vejen med at bruge URLClassLoader direkte?

Jeg har oprettet en ny URLClassLoader med appletens classloader som parent, så tilføjer jeg crimson.jar til den nye classloader og derefter bruger jeg den nye classloader til at loade en klasse som ligger inlejret i min applet-klasse. Og så langt går det fint, klassen bliver loaded.
Men når jeg så forsøger at oprette en ny instans, fejler den.

URL[] urls = new URL[] { getURL("crimson.jar") };
ClassLoader cl = getClass().getClassLoader();
URLClassLoader ucl = URLClassLoader.newInstance(urls, cl);
Class c = ucl.loadClass("com.mypackage.MyApplet$MyRunnable");
Object o = c.newInstance();


Ps. Fejlene oven over er fra denne kode, ikke dit eksempel. Jeg skrev dem før jeg havde set dit indlæg.
Avatar billede arne_v Ekspert
17. juli 2003 - 11:14 #16
Nej det burde være ligegyldigt hviklen klasse classloader det er
bare det er en ny instans.

Hvis MyApplet$MyRunnable kan loades af den almindelige classloader (fordi
den er i din applet jar fil) *og* den i constructor bruger nogle
af de ting der skal loades via den specielle classloader, så virker det
ikke.
Avatar billede arne_v Ekspert
17. juli 2003 - 11:16 #17
Af forskellige (sikkerhedsmæssige) årsager, så forsøger den fra
oven af i classloader ghirakiet - ikke fra neden af.
Avatar billede tobiashm Nybegynder
18. juli 2003 - 10:39 #18
Så pointen er måske at når den klasse som skal loade noget via den nye classloader, er loaded af en classloader højere oppe i hirakiet, så virker det ikke -- altså det er ikke nok at den nye classloader er med/kaldes :-/

-

Men MyApplet$MyRunnable laver ikke noget i dens constructor. Først i dens start() metode bliver xml-klasserne brugt.

Under alle omstændigheder bliver det for kedeligt (omstændigt) at skulle lave en klasse som  ligger på serveren og kalder tilbage osv. kun hvis der ikke allerede er en parser på klienten. Så må brugeren bare leve med altid at downloade en parser ;-)
Jeg kan jo bruge Piccolo.jar som fylder ~50kB mindre og skulle være hurtigere.
Avatar billede arne_v Ekspert
18. juli 2003 - 11:01 #19
Netop.

Du skal have en classloader med 2 URL's: wrapper og JAXP jar.

Så bruger du classloaderen til at loade wrapperen med og fordi wrapperen
ikke kan loades af den normale classloader så bliver din classloader
faktisk brugt. Og derfor kan den senere loade far JAXP jar'en.

Og ja det er bøvlet - og jeg mener også at jeg en 15 indlæg oppe
startede lidt med at forske i alternativerne.
Avatar billede tobiashm Nybegynder
18. juli 2003 - 11:21 #20
Men det var jo netop alternativet (at downloade alle klasserne) jeg ville undgå ;-)

Hvis bare class-path'en kunne være 'sløv' så den kun blev brugt hvis en klasse ikke fandtes blandt de allerede eksisterende -- når nu classloaderen alligvel starter oppefra.
Avatar billede arne_v Ekspert
18. juli 2003 - 12:01 #21
Skal jeg prøve at lave et "applet-JAXP" eksempel i weekenden ?
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