Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Lenovo IdeaPad Slim 3: un notebook Snapdragon X economico
Lenovo IdeaPad Slim 3: un notebook Snapdragon X economico
Forte della piattaforma Qualcomm Snapdragon X, il notebook Lenovo IdeaPad Slim 3 riesce a coniugare caratteristiche tecniche interessanti ad uno chassis robusto, con autonomia di funzionamento a batteria che va ben oltre la tipica giornata di lavoro. Un notebook dal costo accessibile pensato per l'utilizzo domestico o in ufficio, soprattutto con applicazioni native per architettura ARM
Recensione OnePlus Watch 3 43mm: lo smartwatch che mancava per i polsi più piccoli
Recensione OnePlus Watch 3 43mm: lo smartwatch che mancava per i polsi più piccoli
OnePlus risponde alle esigenze di chi cerca un dispositivo indossabile dalle dimensioni contenute con OnePlus Watch 3 43mm. La versione ridotta del flagship mantiene gran parte delle caratteristiche del modello maggiore, offrendo un'esperienza completa in un formato compatto. Il suo limite più grande è abbastanza ovvio: l'autonomia non è il punto di forza di questo modello, ma si raggiungono comodamente le due giornate piene con un uso normale.
BOOX Note Air4 C è uno spettacolo: il tablet E Ink con Android per lettura e scrittura
BOOX Note Air4 C è uno spettacolo: il tablet E Ink con Android per lettura e scrittura
BOOX Note Air4 C rappresenta l'ultima incarnazione della categoria dei tablet E Ink a colori di Onyx, e combina le prestazioni di un dispositivo Android con l'ottima tecnologia Kaleido 3 per il display. Con schermo da 10,3 pollici, un processore Qualcomm Snapdragon 750G e 6 GB di RAM, promette un'esperienza completa per lettura, scrittura e produttività. Il prezzo lo posiziona nel segmento premium, ma questo dispositivo è un vero spettacolo!
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 05-02-2010, 00:41   #1
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
[JAVA] Caricare jar dinamicamente/a runtime

Ragazzi ho bisogno del vostro aiuto, le ho provate tutte, ma mi continua sempre a dare noClassDefFoundError...

Ho provato con classloader custom che estendono ClassLoader oppure URLClassloader, ad aggiungere le url dei jar al Classloader corrente, etc etc, non so più dove

Grazie mille a chiunque decida di aiutarmi,
Rob
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 05-02-2010, 12:19   #2
fero86
Senior Member
 
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
se il deploy lo fai con JNLP basta che imposti a "lazy" l'attributo download del tag jar.
http://java.sun.com/javase/6/docs/te...html#resources
fero86 è offline   Rispondi citando il messaggio o parte di esso
Old 05-02-2010, 13:45   #3
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Cosa intendi per "caricare dinamicamente un jar"? Lo chiedo perchè i jar non sono soggetti ad alcun caricamento mentre ciò che i jar contengono è sempre caricato dinamicamente.

Se usi URLClassLoader tieni conto che il suo comportamento cambia a seconda che l'url di base termini o no con uno slash /

L'eccezione che incontri riporta per caso un'indicazione "wrong name:" seguita da un nome di tipo?
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 05-02-2010, 15:05   #4
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Codice:
import java.net.URL;
import java.io.*;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.util.jar.*;

public class JarFileLoader extends URLClassLoader {

    public JarFileLoader (URL[] urls){
        super(urls);
    }

    public void addFile (String path) throws MalformedURLException{
        String urlPath = "jar:file://" + path + "!/";
        URL url = new URL (urlPath);
        File file = new File(path);
        addURL (file.toURI().toURL());
    }
    
    public void loadClasses(String jarName) throws ClassNotFoundException{
        JarInputStream jis = null;
        JarEntry entry = null;
            try {
                jis = new JarInputStream(new FileInputStream(jarName));
                entry = jis.getNextJarEntry();
                while (entry != null) {
                String name = entry.getName();
                if (name.endsWith(".class")) {
                    name = name.substring(0, name.length() - 6);
                    name = name.replace('/', '.');
                    System.out.print("> " + name);
                    try {
                        loadClass(name);
                        System.out.println("\t- loaded");
                    } catch (Throwable e) {
                    }
                }
              entry = jis.getNextJarEntry();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }       
      }
}
Ad esempio una cosa di questo tipo. Nella main class creo la mia istanza di JarFileLoader, chiamo addFile(jarURL) per aggiungere il jar al classpath, e poi di nuovo loadClasses(jarName) per caricare le singole classi dentro il jar.
La print
System.out.println("\t- loaded");
viene correttamente stampata per ogni classe, ad es
mio.package.MyClassA loaded
mio.package.MyClassB loaded
etc

Poi nel main:

Codice:
URL urls [] = {};
JarFileLoader cl = new JarFileLoader (urls);
cl.addFile("E:\\test2\\real_time_monitoring_all.jar");
cl.loadClasses("E:\\test2\\real_time_monitoring_all.jar");
In teoria quindi ho aggiunto il jar al classpath con addFile, e ho caricato i .class con loadClasses.
Tuttavia dopo lancio:

Class.forName("real_time_monitoring.RealTimeMonitoring");

ed ottengo un NoClassDefFoundError su tale classe....

> real_time_monitoring.Event - loaded
> real_time_monitoring.Login$1 - loaded
> real_time_monitoring.Login - loaded
> real_time_monitoring.RealTimeMonitoring - loaded
> real_time_monitoring.Utilities - loaded
> real_time_monitoring.VersionChecker - loaded
> real_time_monitoring.WindowPersistence - loaded
Success!
java.lang.ClassNotFoundException: real_time_monitoring.RealTimeMonitoring
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at newguiupdater.Main.main(Main.java:372)

Credo che mi potrei stare ad incartare anche tra il manifest e java -cp...

Ultima modifica di tylerdurden83 : 05-02-2010 alle 15:14.
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 05-02-2010, 15:41   #5
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
La classe caricata da un URLClassLoader non è individuata dal forName. Cioè devi scrivere:

Class<?> c = ilJarFileLoader.loadClass(ilNomeDellaClasse)

e non

Class<?> c = Class.forName(ilNomeDellaClasse)

Nel codice che hai incollato ingoi l'eccezione eventualmente rilasciata dal loadClass quindi nulla sai circa l'effettivo esito del tentativo del tuo class loader di trovare ciò che cerchi.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 05-02-2010, 15:47   #6
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
La classe caricata da un URLClassLoader non è individuata dal forName. Cioè devi scrivere:

Class<?> c = ilJarFileLoader.loadClass(ilNomeDellaClasse)

e non

Class<?> c = Class.forName(ilNomeDellaClasse)

Nel codice che hai incollato ingoi l'eccezione eventualmente rilasciata dal loadClass quindi nulla sai circa l'effettivo esito del tentativo del tuo class loader di trovare ciò che cerchi.
In realtà ho tolto un po di print, compresa quella del catch throwable, per questioni di leggibilità qui sul forum, nel codice c'è e non dà alcuna eccezione. Anche il main, mi spiego meglio...

cl.loadClasses(System.getProperty("user.dir").concat("\\real_time_monitoring_all.jar"));

loadClasses è void, e quello che fa è chiamare loadClass su ogni .class contenuto nel jar passatogli, quindi effetticamente non uso Class.forName per caricare real_time_monitoring.RealTimeMonitoring, ma loadClass.
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 05-02-2010, 17:28   #7
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Se loadClass funziona nel try funziona anche fuori. L'unico errore possibile è che il class loader non sia lo stesso.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 06-02-2010, 00:33   #8
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Se loadClass funziona nel try funziona anche fuori. L'unico errore possibile è che il class loader non sia lo stesso.
Ti chiedo di verificare se ho afferrato bene il concetto, tra l'altro credo di aver ottenuto una soluzione funzionante al problema....

Aspetto numero 1:
- Il bootstrap class loader carica classi di rt.jar, tipo Object
- L' extended class loader è figlio del bootstrap e carica roba che ora non ci interessa
- L'application class loader è figlio dell extended e carica l'applicazione vera e propria. Questo è un'estenzione della classe astratta ClassLoader, generalmente URLClassLoader.
- MyURLClassLoader è figlio dell'application loader.

Ho un jar principale, MyProject.jar, in cui è presente MyURLClassLoader.
Questo jar vuole caricare RealTimeMonitoring.jar, che NON è nel manifest, ne nella clausola java -cp. Il meccanismo di caricamento delle classi è che un class loader demanda al padre il caricamento di una certa classe, ripetitivamente verso l'alto. Se il padre non può caricarla, si riscende verso il basso.

Leggendo qui ho capito che la cosa migliore da fare per caricare/ricaricare dinamicamente una classe è questa:

- Definire un'interfaccia, facciamo MyPlugin, senza niente dentro
- Far sì che real_time_monitoring.RealTimeMonitoring implementi quell'interfaccia
- Mettere l'interfaccia in un jar a parte, presente nel classpath, dato che come dice su quel link: To make this work you will of course need to implement your class loader to let the interface or superclass be loaded by its parent.

Ricapitolando, abbiamo:

package real_time_monitoring
import myinterface.MyPlugin
public class RealTimeMonitoring implements MyPlugin{...}

package my_project
import myinterface.MyPlugin
import real_time_monitoring
public class MyProject{...}

uso java -cp "MyInterface.jar" my_project.MyProject

A questo punto però nonostante la classe RealTimeMonitoring è caricata usando loadClass del MyURLClassLoader, se provo a crearne una nuova istanza ottengo comunque quell'error.

Mi pare, devo fare altre prove, che se invece di fare
RealTimeMonitoring rtm = (RealTimeMonitoring)myClass.newInstance();

faccio

MyPlugin rtm = (MyPlugin)myClass.newInstance();

Ti torna? Ho detto fesserie?
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 06-02-2010, 15:01   #9
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Il blog non dev'essere recente e, immagino per ragioni di sintesi, è un po' vago.

Non è recente perchè le librerie standard includono URLClassLoader (dalla versione 1.2) all'esatto scopo di permettere il caricamento di classi salvate su file contenuti in percorsi non inclusi nel classpath di un programma java.

La necessità di usare un proprio sottotipo di ClassLoader nasce quando le classi non sono contenute in file (come capita ad esempio se compili un sorgente in memoria o in un database) o quando il codice byte che definisce la classe deve essere manipolato prima del caricamento.

Dunque caricamento di classi contenute in file -> URLClassLoader.

E' vago sulla questione dell'interfaccia. Ci sono due premesse:

1. una classe Java è identificata dal suo nome pienamente qualificato (it.bingo.piripicchio.NomeSemplice) E dal ClassLoader che l'ha caricata. Significa che la classe A caricata dal ClassLoader C1 è diversa dalla classe A caricata dal ClassLoader C2.
2. La richiesta di caricamento nominativa di una certa classe fatta a un certo classloader restituisce sempre la stessa classe finchè questa non sia scaricata dalla jvm. Significa che se io ho una classe A a cui corrisponde un certo codice byte e chiedo ad un class loader C di caricarla una prima volta, ogni ulteriore richiesta di caricamento restituirà sempre la versione di quella classe caricata la prima volta.

Supponiamo di avere questo codice:

it.bingo.Bingo istanza = (it.bingo.Bingo) new MyClassLoader().loadClass("it.bingo.Bingo").newInstance();

Quando viene eseguito il classloader della classe in cui si trova l'enunciato, prima di tutto, carica la classe it.bingo.Bingo (perchè istanza è di questo tipo).

Quando l'URLClassLoader va a caricare una classe con lo stesso nome pienamente qualificato, si danno due casi:

1) MyClassLoader è un delegante rispetto al ClassLoader che ha caricato it.bingo.Bingo per il tipo it.bingo.Bingo: in questo caso la classe restituita è la stessa che è già presente nella JVM ("marchiata" dal ClassLoader che per primo l'ha caricata). Ogni mutamento eventualmente occorso al byte code su file non è considerato - semplicemente perchè il file non è più esaminato.
2) MyClassLoader non è un delegante: in questo caso l'esecuzione fallisce perchè newInstance restituisce un valore di tipo [it.bingo.Bingo, caricato da C1] e la conversione esplicita a cui è sottoposto quel valore è di tipo [it.bingo.Bingo, caricato da C0].

E' chiaro che per poter caricare e aggiornare un certo tipo durante l'esecuzione del programma:

1) Non deve esserci delega rispetto al tipo che si vuole caricare-ricaricare, altrimenti lo carichi ma non lo ri-carichi
2) Non devono esserci tentativi di conversione a tipi ugualmente denominati - perchè pur avendo lo stesso nome la mancanza di delega fa si che i tipi siano diversi.

Nell'esempio di prima, se io dicessi:

Object istanza = new MyClassLoader().loadClass("it.bingo.Bingo").newInstance()

Avremmo un classloader C0 che carica Object, un classloader C1 che carica it.bingo.Bingo ed un assegnamento di un'istanza di it.bingo.Bingo a Object. Funziona? Bingo estende Object. Se l'Object esteso da Bingo è lo stesso Object caricato da C0 allora non ci sono eccezioni dovute all'incompatibilità tra tipi. Permette di ricaricare la definizione di it.bingo.Bingo? Se i delegati di MyClassLoader non hanno accesso alla definizione di it.bingo.Bingo, la classe viene ricaricata ad ogni esecuzione di quell'enunciato.

Nota bene che se anzichè dire new MyClassLoader usassimo una stessa istanza di MyClassLoader per la premessa 1 (un ClassLoader restituisce sempre la stessa classe dopo il primo caricamento finchè la stessa non sia scaricata dalla JVM) il codice non restituirebbe eccezioni ma la classe non verrebbe ricaricata.

Dunque per il caricamento di una classe non inclusa nel classpath del programma, residente su file (locale o remoto) si usa URLClassLoader.
La sostituzione della definizione di un tipo con un altra definizione dello stesso tipo richiede l'uso di un tipo intermedio.

Il tipo intermedio può essere benissimo java.lang.Object. Il problema è che usando Object l'accesso ai metodi specifici della classe che vogliamo poter ricaricare deve avvenire tramite riflessione e facendo ciò si perde il controllo che il compilatore esegue sull'integrità dei tipi: il tentativo di invocare un metodo privato o non esistente è rigettato dal compilatore a meno che quel tentativo non sia riflessivo, caso in cui il compilatore alza le mani e dice "be', io qui nulla posso dire".

Chiudo con l'esempio più breve che si possa fare. Ho una cartella, poniamo "x:\urlclassloaderclasses" in cui c'è una classe Bingo il cui sorgente è:

Codice:
package it.tukano;

public class Bingo implements Runnable {
	private final String TEST_MESSAGE = "hello world";

	public void run() {
		System.out.println(TEST_MESSAGE);
	}
}
compilata in un file Bingo.class in "x:\urlclassloaderclasses\it\tukano\".

Il programma che segue carica per 10 volte la classe it.tukano.Bingo con un intervallo di 10 secondi:

Codice:
package it.tukano.uc;

import java.net.URL;
import java.net.URLClassLoader;

public class Main {

	public static void main(String[] args) throws Throwable {
		URL classpath = new URL("file:///x:/urlclassloaderclasses/");
		URL[] classLoaderUrls = { classpath };
		String reloadableClassName = "it.tukano.Bingo";
		for(int i = 0; i < 10; i++) {
			Class<?> c = new URLClassLoader(classLoaderUrls).loadClass(reloadableClassName);
			Runnable instance = (Runnable) c.newInstance();
			instance.run();
			Thread.sleep(10000);
		}
	}
}
Se durante l'esecuzione del programma cambiamo il contenuto della stringa TEST_MESSAGE in Bingo e ricompiliamo il file sorgente sostituendo il precedente file Bingo.class, il programma Main rifletterà quel cambiamento.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 06-02-2010, 16:17   #10
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Grazie della risposta ora sono su cell dopo mi leggo tutto per bene, grazie 1000 ancora!
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 06-02-2010, 23:59   #11
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Direi che mi è rimasto solo un dubbio, ossia il meccanismo di delega del caricamento delle classi. Ho paura che usare new URLClassLoader, specialmente se non uso il costruttore (url, parentClassLoader), potrebbe non funzionare correttamente...

Ad esempio, quale è più corretto usare tra:

URLClassLoader ldr = new URLClassLoader(urls, getClass().getClassLoader());

e

URLClassLoader ldr = new URLClassLoader(urls);

Mi verebbe da dire il primo. Se uso il secondo per caricare una classe, e questa classe contiene altre classi, ldr proverà a caricare queste classi, e non avendo padri, le caricherà nuovamente di persona, invece di riusare quelle caricate in precedenza?

La cosa mi ha fatto ricordare di aver letto da qualche parte che uno consigliava di creare nel main thread un custom class loader, settarlo come "default" class loader del thread(e quindi del resto dell'applicazione), in modo che da quel momento in poi ogni classe che verrà caricata, passerà per questo custom class loader. Il custom class loader è fatto in modo da non delegare il caricamento di certe classi ai classloader superiori, e di passare il caricamento di altre ai class loader superiori.
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 07-02-2010, 00:27   #12
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Non c'è differenza tra i due (a meno che la classe del getClassLoader non sia caricata da un class loader personalizzato).

A prescindere, il problema non sussiste nel senso che URLCLassLoader delega il caricamento delle classi che non sono definite nei percorsi che gli affidi.

Cioè se la classe ricaricabile usa Object, l'Object è quello che già è in memoria. Idem per tutti quei tipi che la tua classe può voler usare ma che non sono soggetti a mutazione (e che quindi non saranno nella cartella "ricaricabile" ma faranno parte delle librerie principali del programma).

Tieni naturalmente presente che se la classe ricaricabile usa altre classi quelle classi devono trovarsi o nelle cartelle (o jar) usate dall'URLClassLoader, e saranno ricaricate, o nel classpath del programma, e non saranno ricaricate.

Puoi anche "imparentare" il tuo URLClassLoader con un altro URLClassLoader nel caso in cui tu non voglia includere nel classpath classi non ricaricabili.

Quando al classloader nel main farlo in generale non è consigliabile. La ragione principale sta nel fatto che il classloading è soggetto a restrizioni di sicurezza: l'utente può sempre applicare una policy restrittiva che manda a ramengo un programma solo perchè usa un classloader di cui magari non c'è bisogno.

Dal punto di vista pratico, la necessità sorge perchè in Java l'istanziazione (il new) è statica e monomorfa. Se un certo programma da qualche parte dice:

Object x = new Qualcosa();

l'unico modo "linguistico" per far sì che "new Qualcosa()" restituisca un'istanza di un sottotipo di "Qualcosa" è... cambiare il codice sorgente. Se non si ha accesso al codice sorgente l'alternativa è passare per il classloading e fare in modo che a "Qualcosa" corrisponda qualcos'altro.

Il che si può tranquillamente fare in un secondo momento. Qualsiasi programma Java è sempre avviabile da un altro programma Java e, in quanto precedente, l'altro programma può iniettare un suo classloader.

Per questo genere di manipolazione, tuttavia, oggi si usa la "byte code instrumentation" (cioè vai a mettere le mani direttamente nella JVM durante la sua esecuzione).
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 07-02-2010, 12:34   #13
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Continuo a prendere errore, ho scritto questo codice molto simile al tuo per fare un caso base...

Codice:
package helloworld;

public class Hello {
    public Hello(){
        System.out.println("Hello Loaded!");
    }
}
Codice:
package mytestloader;

import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import helloworld.Hello;

public class Main {

    public static void main(String[] args) {
        try {
            String path = "C:/Users/Costanza/Documents/NetBeansProjects/HelloWorld/build/classes/helloworld/Hello.class";
            //String path = "C:/Users/Costanza/Documents/NetBeansProjects/HelloWorld/dist/HelloWorld.jar";
            File file = new File(path);
            System.out.println("Can the file be read? "+file.canRead());
            URL classpath = file.toURI().toURL();
            System.out.println("URL="+classpath);
            URL[] classLoaderUrls = { classpath };
            String reloadableClassName = "helloworld.Hello";
            Class<?> c = new URLClassLoader(classLoaderUrls).loadClass(reloadableClassName);
            Hello instance = (Hello) c.newInstance();
Il manifest di MyTestLoader.jar non ha riferimenti a HelloWorld.jar, solo il puntamento alla main class mytestloader.Main

Risultati:

- OK se lanciato con: java -cp "C:/myPath/HelloWorld.jar;MyTestLoader.jar" mytestloader.Main
- KO se lanciato con java -jar MyTestLoader.jar
ClassNotFoundException: helloworld.Hello
at mytestloader.Main.main(24) (ossia "Class<?> c = new URLClassLoader(classLoaderUrls).loadClass(reloadableClassName);")

Tu mi dirai, e ti credo, dovevi puntare il jar, non il class, con l'url passata al class loader...
Sempre riguardo il codice sopra, se commento la prima String path che punta al class e scommento la seconda che punta al jar, ho un risultato un po' strano...

L'output, lanciandolo sempre come java -jar MyTestLoader.jar, è, usando anche -verbose:

Codice:
[Loaded java.security.Principal from shared objects file]
[Loaded mytestloader.Main from file:/D:/java%20test/MyTestLoader.jar]
[Loaded java.lang.IllegalAccessException from shared objects file]
[Loaded java.lang.InstantiationException from shared objects file]
[Loaded java.net.MalformedURLException from shared objects file]
Can the file be read? true
[Loaded java.net.URI from shared objects file]
[Loaded java.net.URI$Parser from shared objects file]
URL=file:/C:/Users/Costanza/Documents/NetBeansProjects/HelloWorld/dist/HelloWorl
d.jar
[Loaded helloworld.Hello from file:/C:/Users/Costanza/Documents/NetBeansProjects
/HelloWorld/dist/HelloWorld.jar]
Hello Loaded!
Exception in thread "main" java.lang.NoClassDefFoundError: helloworld/Hello
        at mytestloader.Main.main(Main.java:27)(ossia "Hello instance = (Hello) c.newInstance();")
Caused by: java.lang.ClassNotFoundException: helloworld.Hello
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
        ... 1 more
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
Quindi non riesco a capire nè dove sta il mio errore rispetto al tuo codice, nè perchè alla fine sembra funzionare ma da cmq errore...

EDIT: ho aggiornato lo stacktrace con uno piu completo...

Ultima modifica di tylerdurden83 : 07-02-2010 alle 12:47.
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 07-02-2010, 13:06   #14
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Gli URL accettati da URLClassLoader sono o file jar o cartelle. Non file class.

Gli url che denotano cartelle devono terminare con uno slash /.

Se vuoi caricare la classe Hello.class devi "puntare" l'URLClassLoader alla directory che contiene il package "helloworld", cioè:

"file:///C:/Users/Costanza/Documents/NetBeansProjects/HelloWorld/build/classes/"

Nel primo caso funziona perchè includi il jar nel classpath del programma (quindi carichi la classe ma non la puoi ricaricare perchè è soggetta a delega).

Nel secondo caso non funziona perche l'URL dell'URLClassLoader non è corretto.

Il terzo caso, quello bizzarro, è dovuto ad un conflitto tra classi ugualmente denominate ma caricate da due class loader diversi.

Quando in mytestloader.Main scriviamo:

Hello instance = (Hello) c.newInstance();

Le classi di nome "helloworld.Hello" sono due: la prima è quella del "c.newInstance", la seconda è quella che nel codice corrisponde al nome "Hello".

"c" è l'Hello del tuo URLClassLader. Questa viene caricata e istanziata correttamente (e infatti ti stampa "Hello loaded").

MA l'Hello della conversione (Hello) e del tipo "Hello" di instance è un'altra classe, è la classe "helloworld.Hello" il cui caricamento spetto al ClassLoader di mytestloader.Main.

Alla base del comportamente apparentemente strano sta il fatto che puoi compilare una classe (in questo caso mytestloader.Main) rispetto ad un certo classpath ottenendo un certo bytecode ed eseguire quel bytecode con un classpath diverso.

In generale devi evitare di menzionare nel codice che fa uso della classe ricaricabile il nome di questa classe. Vale a dire che in "mytestloader.Main" non dovrebbe mai apparire il nome "Hello".
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 07-02-2010, 13:19   #15
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
In generale devi evitare di menzionare nel codice che fa uso della classe ricaricabile il nome di questa classe. Vale a dire che in "mytestloader.Main" non dovrebbe mai apparire il nome "Hello".
Ottimo, non avevo capito la questione del doppio caricamento...

Nel tuo esempio, hai evitato di mensionare Bingo perchè Bingo implementa Runnable.
Nel mio caso, come è più corretto risolvere secondo te?
Mi viene in mente, o interfaccia o definire un custom class loader che carichi personalmente sempre e solo lui certe classi, per evitare che Hello venga caricato da 2 class loaders ad es...

Nota: la necessità sorge dal seguente problema. Ho un programma/jar principale, facciamo MyMainJar.jar. Dal client lancio un jar chiamato updater.jar, che si connette ad un server via socket e provvede all'eventuale update di MyMainJar.jar. Terminato l'update, dentro il codice di updater.jar c'è il lancio di una nuova instanza di MyMainJar. Siccome MyMainJar.jar viene rimpiazzato dopo aver lanciato updater.jar, e potrebbe anche utilizzare librerie come jdbc che prima non usava, mi servirebbe appunto di "caricare" i jar dinamicamente, invece che al momento del java -cp updater.jar.

Ultima modifica di tylerdurden83 : 07-02-2010 alle 13:37.
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 07-02-2010, 13:37   #16
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Una possibilità è quella di dichiarare un'interfaccia in una libreria separata. Questa interfaccia astrare le funzionalità minime garantire dal tuo modulo ricaricabile.

Potrebbe essere una cosa tipo:

Codice:
package programma.updater;

public interface Updater {
    void update();
}
Usi una libreria a parte perchè poi questa interfaccia ti serve per compilare sia il progetto principale sia il modulo del concreto uploader - che può benissimo essere un progetto remoto. Eviti di doverti portare in giro l'intero progetto nel caso in cui, ad esempio, l'updater sia mantenuto da qualcun'altro.

Nel programma principale apparirà sempre e solo questo "Updater". Nel programma del concreto "updater" la classe ricaricabile concretizzerà l'interfaccia Updater.

Il custom classloader lascialo perdere. I casi in cui è effettivamente necessario estendere un ClassLoader sono assolutamente marginali.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 07-02-2010, 13:57   #17
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Perfetto grazie 1000, dovrebbe essere tutto
In caso dovessi imbattermi in altri problemi ti farò sapere, intanto ti ringrazio infinitamente per avermi aiutato prima a capire e poi a risolvere concretamente questo marasma!
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 08-02-2010, 01:54   #18
tylerdurden83
Senior Member
 
Iscritto dal: Nov 2004
Messaggi: 691
Ummm in effetti un altro dubietto mi sta sorgento nella testolina...

Aggiungere implements Updater alle mie classi dovrebbe essere facile, ma come mi comporto con il caricamento dinamico di classi/jar di terze parti, tipo driver jdbc per mysql/oracle?...
tylerdurden83 è offline   Rispondi citando il messaggio o parte di esso
Old 08-02-2010, 17:25   #19
fero86
Senior Member
 
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
JNLP?
fero86 è offline   Rispondi citando il messaggio o parte di esso
Old 08-02-2010, 17:32   #20
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Se possono cambiare le metti tra gli URL del tuo URLClassLoader, se fanno parte del "core" del programma le metti nel programma.

Io direi che vanno tra le classi ri-caricabili se sono usate solo da queste ultime. Non avere particolare timore della quantità di classi da caricare o ricaricare. Basti pensare che il numero di classi richieste per il solo avvio della JVM è nell'ordine delle diverse migliaia e la procedura occupa frazioni di secondo.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Lenovo IdeaPad Slim 3: un notebook Snapdragon X economico Lenovo IdeaPad Slim 3: un notebook Snapdragon X ...
Recensione OnePlus Watch 3 43mm: lo smartwatch che mancava per i polsi più piccoli Recensione OnePlus Watch 3 43mm: lo smartwatch c...
BOOX Note Air4 C è uno spettacolo: il tablet E Ink con Android per lettura e scrittura BOOX Note Air4 C è uno spettacolo: il tab...
Recensione Sony Xperia 1 VII: lo smartphone per gli appassionati di fotografia Recensione Sony Xperia 1 VII: lo smartphone per ...
Attenti a Poco F7: può essere il best buy del 2025. Recensione Attenti a Poco F7: può essere il best buy...
Molte novità per TrueNAS 25.10 Go...
Eureka J15 Ultra vs J15 Pro Ultra: il ro...
Microsoft registra milioni di telefonate...
Xiaomi 16 Pro in arrivo anche con una va...
Tenta il furto di un monopattino elettri...
Guida assistita in mezzo al traffico? Se...
Design futuristico e prestazioni top: No...
2 computer portatili da gamer top: ASUS ...
La mastodontica scheda video ASUS per il...
Tesla, incendio alla fabbrica tedesca: c...
ECOVACS GOAT A1600 RTK a 949€: il robot ...
Imperdibile su Amazon: DJI Osmo Action 5...
Nascono i 'vegani dell'AI': chi rinuncia...
I prezzi delle batterie per auto crollan...
Gemini arriverà nelle vostre case...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 12:02.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v