View Full Version : [JAVA-ECLIPSE-JAR] Un'odissea senza fine. Problemi con JAR non funzionanti
fbcyborg
10-11-2009, 18:49
Salve gente,
Ho sviluppato un'applicazione in Java piuttosto corposa e vorrei fare un file jar per motivi di praticità.
L'applicazione ha diversi package, e nella root del progetto ho un file chiamato config.xml che mantiene alcune proprietà, e impostazioni.
Se avvio l'applicazione da riga di comando senza jar file, tutto procede liscio. Se creo un JAR file con Eclipse, non appena lo avvio mi dice che non riesce a trovare questo file config.xml, anche se in realtà c'è, ed è nella root dell'archivio.
Sono mesi che provo a farlo funzionare senza esito positivo, ma ora ne ho davvero bisogno. Qualcuno può darmi una mano?
Grazie
Se il file è nel jar del programma (o nella root di un qualsiasi altro jar o zip incluso nel classpath) allora il suo percorso è:
URL config = getClass().getResource("/config.xml");
Se il file non è all'interno di un jar allora il suo percorso assoluto è relativo alla proprietà di sistema user.dir - che varia secondo il percorso della directory di esecuzione del programma.
Se il file non è all'interno del jar ma è comunque in una posizione determinabile a partire da uno dei jar parte del tuo programma puoi determinarne la posizione assoluta rispetto alla posizione di quel jar - che acquisici trasformando il percorso assoluto di uno dei file .class contenuti in quel jar.
fbcyborg
10-11-2009, 22:51
Ciao e grazie per l'aiuto.
Allora, nel frattempo sono stato contattato in privato anche da ^TiGeRShArK^ che al momento non può postare.
Siamo arrivati a questa conclusione, a partire da quanto scritto qui (http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html).
Magari nel frattempo ho capito male io, ma vediamo come ho fatto io fin'ora:
private FileInputStream fis = null; // variabile di istanza
[...]
// all'interno di un metodo di inizializzazione
properties = new Properties();
try {
fis = new FileInputStream("config.xml");
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(getThis(),
"File di configurazione mancante.",
"Errore", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
try {
properties.loadFromXML(fis);
} catch (InvalidPropertiesFormatException e) {
JOptionPane.showMessageDialog(getThis(),
"File di configurazione corrotto.",
"Errore", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
} catch (IOException e) {
JOptionPane.showMessageDialog(getThis(),
"Errore di I/O.",
"Errore", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
Usando il sistema che dite appunto voi, dovrei fare:
private InputStream fis = null; // variabile di istanza
[...]
properties = new Properties();
fis = getClass().getResourceAsStream ("/config.xml");
try {
properties.loadFromXML(fis);
} catch (InvalidPropertiesFormatException e) {
JOptionPane.showMessageDialog(getThis(),
"File di configurazione corrotto.",
"Errore", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
} catch (IOException e) {
JOptionPane.showMessageDialog(getThis(),
"Errore di I/O.",
"Errore", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
In questo modo però, sebbene il programma da Eclipse parta, facendo il jar, parte, mi crea un file config.xml (uguale a quello nella root del jar) al di fuori del file jar, poi dopo aver dato l'OK su quello che sarebbe un form di login, il programma viene chiuso.
Ora, dal tuo post mi sembra di capire che invece dovrei utilizzare la classe URL.
Però poi non posso usare il metodo loadFromXML(fis) su properties.
Allora la questione è questa: dovrei cambiare radicalmente il modo di caricare ed usare il file, ma non sapendo esattamente come, ho un attimo di disorientamento in merito.
La creazione del file xml al di fuori del jar non avviene ad opera del codice che hai incollato: getResource non genera file, nè direttamente nè indirettamente.
Se hai un file config.xml nella radice del jar del tuo programma quel getClass().getResourceAsStream("/config.xml") lo becca al 100%.
Non c'è differenza tra getResource e getResourceAsStream (il secondo è uno shortcut per getResource("abc").openStream()): entrambi danno come risultato l'accesso ad una risorsa inclusa nel classpath.
fbcyborg
11-11-2009, 08:21
No ma infatti lo becca, solo che poi le cose non funzionano come dovrebbero.
La trama si infittisce.
L'altro config.xml, quello che appare nella cartella in cui si trova il jar che contiene il "vero" config.xml, dove lo crei?
fbcyborg
11-11-2009, 15:31
Allora, c'è un solo config.xml.
La situazione è questa. Nella root del progetto ho il file config.xml che semplicemente contiene 2 proprietà, due campi che devono essere modificabili e leggibili, a seconda di quello che fa l'utente.
All'avvio, questo file, config.xml viene caricato e vengono letti questi parametri.
Fino a che non ho il bisogno di fare un file .jar, il programma si avvia e funziona tutto correttamente, ma dal momento che creo il jar il file di configurazione non viene letto.
Ora, apportando le modifiche che mi hai detto tu, e ^TiGeRShArK^ in privato, e sono modifiche che propongono la stessa soluzione, quando vado ad avviare il programma da jar, mi compare il form di login del programma, poi, nella stessa dir dove si trova il jar, viene creato un file config.xml che è la copia esatta di quello che si trova nel jar, e una volta dato l'OK nel form di login, invece di comparire la finestra principale del programma, quest'ultimo viene terminato senza dare altro segno.
Comunque, se tanto i files non possono essere modificati quando sono all'interno del jar file, allora è un problema. Io ho anche un altro file che viene modificato per memorizzare/leggere delle proprietà, e anch'esso verrebbe a trovarsi nel jar file.
A questo punto non so se conviene creare il .jar o no, anche se "esteticamente" mi sembrerebbe più elegante.
Con ogni probabilità il secondo file config.xml lo crei quando vai ad aggiornare le proprietà contenute nel file config.xml.
E' un po' curiosa come faccenda perchè in genere uno sa con certezza quali file crea la sua applicazione e dove li crea :D.
Nota che se un programma non funziona quando è impacchettato in un Jar allora il suo funzionamento in versione non-jar è meramente accidentale nel senso che dipende dal valore di una variabile di sistema - che in quanto variabile varia da "evviva" a "braghe di tela".
Ciò premesso, puoi scrivere nel jar eliminando il vecchio e sostituendolo con un jar nuovo - in cui il vecchio file config.xml risulti sovrascritto.
Puoi scrivere il tuo file config.xml in una delle cartelle predefinite del sistema operativo dedicata ai file delle applicazioni: tieni quello che hai nel jar come base e lo carichi solo se manchi quell'altro.
Puoi scrivere il tuo file config.xml nella cartella in cui si trova il jar.
Personalmente uso l'ultima opzione, con questo strumento:
package it.tukano.datacoat;
import java.net.*;
import java.io.*;
/** Determina il percorso di base del programma. Il percorso di base è la
cartella in cui si trova il file .jar che contiene questa classe o la radice
del package a cui appartiene questa classe. */
class PathFinder {
private static final PathFinder instance = new PathFinder();
/** Restituisce un'istanza condivisa di PathFinder. */
public static final PathFinder getInstance() {
return instance;
}
private final String BASE_PATH;
/** Costruisce un PathFinder inizializzando il percorso di base */
public PathFinder() {
BASE_PATH = computeBasePath();
}
/** Restituisce il percorso di base del programma. */
public String getBasePath() {
return BASE_PATH;
}
/** Restituisce un file il cui percorso è relativo alla cartella di base del
programma. */
public File getRelativeFile(String relativeName) {
return new File(BASE_PATH + File.separator + relativeName);
}
/** Computa il percorso della cartella di base del programma. */
private String computeBasePath() {
Class<?> thisClass = PathFinder.class;
String name = thisClass.getSimpleName() + ".class";
String classPath = thisClass.getResource(name).toString();
String fullName = thisClass.getCanonicalName().replace('.', '/');
classPath = classPath.substring(0, classPath.indexOf(fullName));
try {
classPath = URLDecoder.decode(classPath, "utf-8");
} catch(UnsupportedEncodingException ex) {
throw new InternalError("utf-8 unsupported?"); //utf-8 deve essere supportato
}
if(classPath.startsWith("jar")) {
return parseJarPath(classPath);
} else if(classPath.startsWith("file")) {
return parseFilePath(classPath);
} else {
return null;
}
}
private String parseFilePath(String path) {
path = path.substring("file:/".length(), path.length());
if(path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
path = path.replace('/', File.separatorChar);
return path;
}
private String parseJarPath(String path) {
path = path.substring("jar:file:/".length(), path.length());
int exIndex = path.lastIndexOf('!');
path = path.substring(0, exIndex);
int slashIndex = path.lastIndexOf('/');
path = path.substring(0, slashIndex);
path = path.replace('/', File.separatorChar);
return path;
}
}
Quando mi serve il percorso di un file relativo alla posizione del programma nel filesystem ospite, dico:
File file = PathFinder.getInstance().getRelativeFile("config.xml");
e "file" risulterà essere un file nella cartella in cui si trova il jar, a prescindere da qualsiasi variabile d'ambiente.
L'approccio standard è tuttavia quello di usare cartelle di sistema, tipo "application data" o quel che è.
fbcyborg
11-11-2009, 16:42
Con ogni probabilità il secondo file config.xml lo crei quando vai ad aggiornare le proprietà contenute nel file config.xml.
E' questo il punto. Al momento del caricamento, le proprietà non vengono in alcun modo modificate, vengono solo lette.
E' un po' curiosa come faccenda perchè in genere uno sa con certezza quali file crea la sua applicazione e dove li crea :D.E' vero. Ma la mia applicazione non "crea" alcun file!!! Si limita ad usare quelli che ha.Nota che se un programma non funziona quando è impacchettato in un Jar allora il suo funzionamento in versione non-jar è meramente accidentale nel senso che dipende dal valore di una variabile di sistema - che in quanto variabile varia da "evviva" a "braghe di tela".No dai, non scherziamo! :D ti posso assicurare che questo non è il mio caso. Questo comportamento anomalo piuttosto lo attribuisco a qualche politica interna della JVM, che non mi so spiegare.Ciò premesso, puoi scrivere nel jar eliminando il vecchio e sostituendolo con un jar nuovo - in cui il vecchio file config.xml risulti sovrascritto.Ok, ma la cosa mi sembra un po' elaborata, nel senso che vanificherebbe la versatilità del file properties. Che senso avrebbe usare un meccanismo di modifica "rapida" delle proprietà di un file xml, se poi andrei a sovrascriverlo ogni volta per intero?
Puoi scrivere il tuo file config.xml in una delle cartelle predefinite del sistema operativo dedicata ai file delle applicazioni: tieni quello che hai nel jar come base e lo carichi solo se manchi quell'altro.Su questo non sono d'accordo. Java è multipiattaforma, e anche se è vero che potrei scegliere dinamicamente dove piazzare i files di configurazione a seconda del sistema operativo (e questo richiederebbe un'ulteriore classe interamente dedicata a questo compito), vorrei avere un'applicazione che dove la piazzi gira, senza piazzare in locazioni particolari del disco, eventuali files di configurazione. Al massimo sarebbe opportuno metterli nella stessa dir del jar, come appunto dicevi anche tu in seguito. Ad esempio, nel caso di windows, potrei avere nella directory del mio programma (c:\program files\MioProgramma) sia il file jar che il config.xml.
Puoi scrivere il tuo file config.xml nella cartella in cui si trova il jar.
Personalmente uso l'ultima opzione, con questo strumento:
[...]
Quando mi serve il percorso di un file relativo alla posizione del programma nel filesystem ospite, dico:
File file = PathFinder.getInstance().getRelativeFile("config.xml");
e "file" risulterà essere un file nella cartella in cui si trova il jar, a prescindere da qualsiasi variabile d'ambiente.
Questa cosa è interessante, e non mancherò di approfondirla non appena avrò un attimo!!!
Per ora ti ringrazio !!!!
fbcyborg
16-02-2010, 18:56
Quando mi serve il percorso di un file relativo alla posizione del programma nel filesystem ospite, dico:
File file = PathFinder.getInstance().getRelativeFile("config.xml");
e "file" risulterà essere un file nella cartella in cui si trova il jar, a prescindere da qualsiasi variabile d'ambiente.
Ciao,
sto provando finalmente la tua classe.
Purtroppo però non mi funziona.
Il file config.xml è nella root del progetto:
.
|-- Images
|-- bin
|-- config.xml
|-- lib
`-- src
Il file dal quale eseguo il seguente codice:
File file = PathFinder.getInstance().getRelativeFile("config.xml");
FileInputStream fis = new FileInputStream(file);
si trova in /{bin|src}/gui.
Prima facevo semplicemente
FileInputStream fis = new FileInputStream("config.xml");
E tutto funzionava.
Adesso proprio non trova il file se faccio come dici tu.
Perché, secondo te?
Devo forse modificare la classe PathFinder?
EDIT: Ho scoperto che il basepath che mi trova è:
home/fbcyborg/workspace/ProjectName/bin
Quindi è per questo che non trova il file.
Questo
FileInputStream fis = new FileInputStream("config.xml");
funziona se e solo se il valore di "user.dir" è la cartella in cui è contenuto "config.xml".
PathFinder risolve il percorso rispetto alla radice del package (per classi "sfuse") o alla cartella che contiene il jar.
Se le classi sono in "bin" allora il PathFinder.findeccetera("config.xml") restituisce y:\qualcosa\bin\config.xml
Il tuo config sembra invece essere nella cartella superiore.
fbcyborg
16-02-2010, 19:38
Il tuo config sembra invece essere nella cartella superiore.
Esattamente! Quindi come modifico la classe PathFinder, e in particolar modo il metodo computeBasePath() affinché mi restituisca la dir al livello superiore?
La cartella superiore sarebbe new File(pathFinder.getBasePath()).getParentFile() ma ha poco senso che il file di configurazione stia nella cartella superiore, di solito è in una inferiore:
programma
/librerie
/risorse
/configurazione
Comunque tutto dipende da dove decidi tu di mettere il file.
Tieni conto che la struttura dei file che eclipse usa è ad uso e consumo di eclipse. Quando distribuirai il programma non darai all'utente un progetto eclipse. Gli darai un jar
fbcyborg
16-02-2010, 22:03
OK,
mi sono creato una directory config e vi ho piazzato dentro due files, fra cui il mio config.xml, ma quando faccio
File file = PathFinder.getInstance().getRelativeFile("config.xml");
il file continua a non essere trovato.
E questo perché secondo questa classe la root del programma è MyProject/bin
:D
Il problema si può risolvere con uno qualsiasi degli strumenti che hai già tentato, dal new File("config.xml") al getResourceAsStream("/config.xml") passando per PathFinder eccetera.
Devi prima di tutto stabilire dove si trova il file config.xml.
"Dove si trova" signifca percorso assoluto O percorso relativo.
Nel nostro caso è relativo, quindi devi stabilire "relativo a che cosa" Posto che non puoi usare la struttura di cartelle del progetto eclipse perchè quelle valgono solo in eclipse, la posizione del tuo file config.xml è relativa a che cosa?
fbcyborg
16-02-2010, 22:30
Ok ok..
Allora ho capito quello che vuoi dire.
A me serve usare un percorso relativo, o meglio voglio caricare un certo file tramite l'utilizzo di un path relativo.
Ti posto (in parte) l'albero del progetto:
.
|-- Images
|-- bin
| `-- gui
| `-- Login.class
|-- config
| `-- config.xml
|-- lib
`-- src
`-- gui
`-- Login.java
Dalla classe Login io devo caricare il file config.xml come FileInputStream.
Ora, finché il file config.xml si trovava nella root del progetto (ovvero allo stesso livello di Images, bin, lib e src) mi era sufficiente fare
FileInputStream fis = new FileInputStream("config.xml");
Dal momento che ho bisogno che l'applicazione funzioni anche quando sarà impacchettata come jar, voglio sistemare le cose, e ho piazzato il config.xml dentro l'apposita directory.
Ora, utilizzando la classe PathFinder, la root del progetto che viene restituita è bin/.
Spero che le indicazioni che ti ho dato ora, siano sufficienti per capire come meglio risolvere la questione.
Grazie davvero!
EDIT: OK, dovrei aver risolto semplicemente con:
fis = new FileInputStream("config"+SLASH+"config.xml");
E quindi senza l'utilizzo della classe PathFinder.
Ora provo con il file jar... ti faccio sapere.
fbcyborg
16-02-2010, 23:08
Niente da fare :(
Ora sembra che nel jar Eclipse non voglia impacchettare la directory config/ e giustamente il programma si lamenta che non trova il file config.xml in essa contenuto.
Non ci sto più capendo nulla.
Se faccio Export Runnable Jar File, non riesco a mettere questa directory nel jar. Se faccio Export Jar File, posso mettercela, ma non funziona lo stesso (non mi mette molte delle librerie esterne che ho usato).. :mc:
Che stress!
Se funziona come netbeans, per fargli impacchettare anche la cartella config/config.xml devi metterla tra i sorgenti (sotto src).
.
|-- Images
|-- bin
| `-- gui
| `-- Login.class
|-- lib
`-- src
-- config
-- config.xml
`-- gui
`-- Login.java
In questo caso recuperi il file con:
getClass().getResource("/config/config.xml");
A patto che eclipse te lo impacchetti.
fbcyborg
17-02-2010, 08:37
OK!
Grazie, ora in effetti funziona!
L'unico problema è quando faccio il jar, perché non mi trova il file di configurazione, ma questa volta per un motivo chiaro:
il path nel quale va a cercarlo è:
null/config/config.xml
Forse c'è qualcosa nella classe PathFinder che va aggiustato.
La classe PathFinder l'ho modificata, ma di poco.
Per esempio ho modificato una riga nel metodo computeBasePath():
} else if(classPath.startsWith("file")) {
return File.separator + parseFilePath(classPath);
} else {
Altrimenti non mi metteva uno slash all'inizio e non funzionava.
Inoltre la classe l'ho messa pubblica, sennò mi veniva vista solo nel package in cui l'avevo messa.
Perché compare quel null?
Grazie davvero, ci siamo quasi..
fbcyborg
17-02-2010, 09:37
Ho indagato.
In pratica quando lancio il jar, il classPath inizia con "rsrc" invece che con "jar".
Non so bene perché, ma la stringa che esce fuori è soltanto "rsrc", che non so da dove esca fuori.
Inoltre l'eccezione che esce fuori quando lancio il jar, dopo aver sostituito nel codice la stringa "jar" con "rsrc" (pensando di risolvere) è la seguente:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
Caused by: java.lang.ExceptionInInitializerError
at gui.Login.<clinit>(Login.java:64)
at Main.main(Main.java:5)
... 5 more
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -5
at java.lang.String.substring(String.java:1937)
at util.PathFinder.parseJarPath(PathFinder.java:67)
at util.PathFinder.computeBasePath(PathFinder.java:49)
at util.PathFinder.<init>(PathFinder.java:22)
at util.PathFinder.<clinit>(PathFinder.java:11)
... 7 more
Che diavolo può essere?
EDIT:
Ecco quali sono i valori delle variabili quando lancio il jar:
String name = thisClass.getSimpleName() + ".class";
String classPath = thisClass.getResource(name).toString();
String fullName = thisClass.getCanonicalName().replace('.', '/');
name: PathFinder.class
classPath: rsrcutil/PathFinder.class
fullName: util/PathFinder
Dopo la seguente istruzione:
classPath = classPath.substring(0, classPath.indexOf(fullName));
name: PathFinder.class
classPath: rsrc
fullName: util/PathFinder
banryu79
17-02-2010, 10:35
Ho indagato.
In pratica quando lancio il jar, il classPath inizia con "rsrc" invece che con "jar".
Non so bene perché, ma la stringa che esce fuori è soltanto "rsrc", che non so da dove esca fuori.
Non so se hai notato questo:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
Caused by: java.lang.ExceptionInInitializerError
at gui.Login.<clinit>(Login.java:64)
at Main.main(Main.java:5)
... 5 more
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -5
at java.lang.String.substring(String.java:1937)
at util.PathFinder.parseJarPath(PathFinder.java:67)
at util.PathFinder.computeBasePath(PathFinder.java:49)
at util.PathFinder.<init>(PathFinder.java:22)
at util.PathFinder.<clinit>(PathFinder.java:11)
... 7 more
Da cui (presumo):
classPath: rsrcutil/PathFinder.class
Alla quale, se poi applichi:
classPath = classPath.substring(0, classPath.indexOf(fullName));
(ovvero tieni tutto fino a:"util/PathFinder") rimane:
classPath: rsrc
fbcyborg
17-02-2010, 10:41
Sì l'ho notato, e con maggior attenzione ora che me l'hai messo in evidenza, ma non capisco dove sia il problema.
Siccome non sono molto ferrato con questi jar quello che posso intuire è che si sta tentando di caricare quel file con un sistema di caricamento che è proprio di eclipse. Ma non saprei come fare per cambiare questo comportamento.
EDIT: sono su gentoo, e la jdk di default è Sun JDK 1.6.0.17 [sun-jdk-1.6]
E non funziona nemmeno su Windows XP, dando sempre lo stesso problema.
...
OK, ho notato che c'è qualcosa che non va nel Manifest...
...
Niente... non funziona. :(
fbcyborg
17-02-2010, 13:10
Forse sbagliavo il modo di fare il Jar, ma comunque anche cambiando non funziona uguale.
Prima facevo Export...-> Runnable Jar File ed avevo i problemi sopra descritti.
Ora invece faccio Export... -> Jar file e comunque ho problemi di path con il file config.xml.
Ecco cosa succede:
Dalla dir: /home/fbcyborg/workspace:
java -jar myProject.jar:
Prima dell'assegnazione della variabile classPath
name: PathFinder.class
classPath: jar:file:/home/fbcyborg/workspace/myProject.jar!/util/PathFinder.class
fullName: util/PathFinder
(non capisco quel punto esclamativo, e quel "jar:file:". O jar o file, no?)
Dopo l'istruzione che modifica classPath:
name: PathFinder.class
classPath: jar:file:/home/fbcyborg/workspace/myProject.jar!/
fullName: util/PathFinder
Ed in console ottengo:
java.io.FileNotFoundException: home/fbcyborg/workspace/config/config.xml (No such file or directory)
In pratica il problema è che a classe PathFinder non restituisce il path corretto.
Quando l'applicazione parte con il jar, dovrebbe cercare il config.xml usando un percorso relativo e interno
al jar stesso. Secondo me c'è qualche modifica da fare in questa classe ma non saprei bene quale.
E questo non dovrebbe accadere: perché mi cerca il config.xml in quella dir? Oltretutto senza mettere lo slash iniziale.
Possibile tutto sto casino per fare uno stupido jar?
Calma e gesso. L'eccezione è un bug di PathFinder - che non è una classe delle librerie standard ma una roba che uso io. In verità quel problema l'avevo anche risolto, insieme allo slash iniziale, e in effetti la versione che ho postato è vecchia. La più recente - e testata - è:
package it.tukano.datacoat;
import java.net.*;
import java.io.*;
/** Determina il percorso di base del programma. Il percorso di base alla
cartella in cui si trova il file .jar che contiene questa classe o la radice
del package a cui appartiene questa classe. */
class PathFinder {
private static final String OS = System.getProperty("os.name");
private static final boolean UNIX = OS.toLowerCase().contains("linux") ||
OS.toLowerCase().contains("unix") || OS.toLowerCase().contains("mac") ||
OS.toLowerCase().contains("bsd") || OS.toLowerCase().contains("osx");
private static final PathFinder instance = new PathFinder();
/** Restituisce un'istanza condivisa di PathFinder. */
public static final PathFinder getInstance() {
return instance;
}
private final String BASE_PATH;
/** Costruisce un PathFinder inizializzando il percorso di base */
public PathFinder() {
BASE_PATH = computeBasePath();
}
/** Restituisce il percorso di base del programma. */
public String getBasePath() {
return BASE_PATH;
}
/** Restituisce un file il cui percorso è relativo alla cartella di base del
programma. */
public File getRelativeFile(String relativeName) {
return new File(BASE_PATH + File.separator + relativeName);
}
/** Computa il percorso della cartella di base del programma. */
private String computeBasePath() {
Class<?> thisClass = PathFinder.class;
String name = thisClass.getSimpleName() + ".class";
String classPath = thisClass.getResource(name).toString();
String fullName = thisClass.getCanonicalName().replace('.', '/');
classPath = classPath.substring(0, classPath.indexOf(fullName));
try {
classPath = URLDecoder.decode(classPath, "utf-8");
} catch(UnsupportedEncodingException ex) {
throw new InternalError("utf-8 unsupported?"); //utf-8 deve essere supportato
}
if(classPath.startsWith("jar")) {
String val = parseJarPath(classPath);
return UNIX ? "/" + val : val;
} else if(classPath.startsWith("file")) {
String val = parseFilePath(classPath);
return UNIX ? "/" + val : val;
} else {
return null;
}
}
private String parseFilePath(String path) {
path = path.substring("file:/".length(), path.length());
if(path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
path = path.replace('/', File.separatorChar);
return path;
}
private String parseJarPath(String path) {
path = path.substring("jar:file:/".length(), path.length());
int exIndex = path.lastIndexOf('!');
path = path.substring(0, exIndex);
int slashIndex = path.lastIndexOf('/');
path = path.substring(0, slashIndex);
path = path.replace('/', File.separatorChar);
return path;
}
}
Comunque non devi usare questa classe se vuoi recuperare il file dal JAR.
PathFinder NON prende il percorso del classpath. Cerca nella radice del package O nella directory in cui si trova il jar.
Per prendere un percorso in un jar devi usare getResource.
fbcyborg
17-02-2010, 19:08
Per prendere un percorso in un jar devi usare getResource.
Ok, ma io vorrei un sistema in modo che posso sviluppare la mia applicazione e pacchettizzarla quando voglio io.
Perché se voglio creare un jar, devo cambiare il codice?
Non c'è un modo automatico per fargli capire che si tratta di un jar e quindi prendere i files nel modo corretto?
Oramai comunque quella classe l'ho usata, e infatti ti ringrazio! ma allora come faccio se voglio il jar?
Mi sembra assurdo come ciò sia così senza senso.
Per fare quello che vuoi tu c'è getResource. Funziona in base al classpath. Devi fare in modo che l'ide esporti il file di configurazione quando crea il jar. L'esportazione deve avvenire in un punto che sia incluso nel classpath del jar. Il classpath del jar include il jar stesso e tutto ciò che è specificato nell'attributo Class-Path del file manifesto del jar.
fbcyborg
17-02-2010, 22:48
OK,
Quindi ad esempio se l'albero del mio progetto è questo:
.
|-- Images
|-- bin
| | -- config
| | -- config.xml
| `-- gui
| `-- Login.class
|-- lib
`-- src
| -- config
| -- config.xml
`-- gui
`-- Login.java
La directory config è all'interno della root del progetto e quindi quando verrà pacchettizzato con il jar verrà inclusa.
Ora se eseguo il progetto da eclipse, e voglio fare riferimento a config.xml, basta che faccio
File f = new File("config/config.xml");
Ora, se lascio le cose così, quando vado a fare il jar, non funziona.
Quindi se ho capito bene, usando getResource(), posso ottenere un FileInputStream dal file config/config.xml sia che mi trovi "dentro" al jar sia che stia avviando l'applicazione da Eclipse.
=====================
Ebbene ho provato, e da
File file = PathFinder.getInstance().getRelativeFile("config"+SLASH+"config.xml");
fis = new FileInputStream(file);
sono passato a:
URL url = this.getClass().getResource("config"+SLASH+"config.xml");
fis = new FileInputStream(url.getFile());
Ma non appena eseguo il codice da Eclipse ottengo:
Exception in thread "main" java.lang.NullPointerException
Chiedo scusa se forse non afferro subito quello che mi suggerite, e soprattutto ringrazio per la pazienza, ma vorrei uscire fuori da questa situazione che purtroppo mi sta portando via un sacco di tempo. :(
EDIT:
Se metto
URL url = this.getClass().getResource(SLASH + "config"+SLASH+"config.xml");
fis = new FileInputStream(url.getFile());
Allora funziona, ma quando creo il jar siamo da capo e 12, e non ne vuole sapere.
java.io.FileNotFoundException: file:/home/fbcyborg/workspace/myproject.jar!/config/config.xml (No such file or directory)
Eclipse e la struttura del progetto non devi neanche guardarli.
Quando scrivi:
File f = new File("config/config.xml");
stai dicendo:
File f = user.dir + config/config.xml
Quanto vale user.dir? user.dir vale "la directory di lavoro"
Vuoi che il percorso sia relativo alla directory di lavoro? In genere la risposta è no perchè la directory di lavoro può variare da sessione a sessione (dipende da come lanci il programma).
Quindi sai in partenza che File f = new File("config/config.xml") non va bene. Anche se apparentemente funziona, non va bene. La ragione per cui funziona è un incidente: in eclipse apparentemente la directory di lavoro al momento dell'esecuzione del programma coincide con bin. Questo però non è vero in generale. Ergo, opzione scartata.
Va bene il getResource? Sì, per le ragioni già dette. E perchè a me non funziona, dirai.
Ti manca una "/". Javadoc di getResource:
•If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
•Otherwise, the absolute name is of the following form:
modified_package_name/name
Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').
Quindi:
1. il nome della risorsa è "/config/config.xml"
2. quella cartella deve essere nel classpath.
La cartella è nel classpath? Quando config/config.xml è nel jar, certamente. Quando non è nel jar dipende da come lanci il programma. La cartella "bin" è già nel classpath quando esegui il programma con eclipse (o almeno credo) quindi è funzionerà.
EDIT:
Se metto
URL url = this.getClass().getResource(SLASH + "config"+SLASH+"config.xml");
fis = new FileInputStream(url.getFile());
Allora funziona, ma quando creo il jar siamo da capo e 12, e non ne vuole sapere.
java.io.FileNotFoundException: file:/home/fbcyborg/workspace/myproject.jar!/config/config.xml (No such file or directory)
Bingo.
Occhio all'eccezione. Non dice che non trova la risorsa: sputerebbe una NPE. Dice una cosa diversa:
file:/home/fbcyborg/workspace/myproject.jar!/config/config.xml
Dice che non trova questo file. E sfido che non lo trovi: non è un file quello.
In generale ogni File può essere espresso come un URL ma non ogni URL può essere espresso come File (pensa ai percorsi di rete).
Non usare FileInputStream. Se hai un URL crei un flusso con url.openStream.
fbcyborg
18-02-2010, 10:15
OK, innanzitutto grazie infinite.
Le cose piano piano si stanno aggiustando.
Ora per leggere un file faccio:
URL url = this.getClass().getResource(SLASH+"config"+SLASH+"config.xml");
is = url.openStream();
Dove is è un InputStream.
E fin qui, tutto ok.
Il problema è che devo anche scriverci sui files di configurazione (per cambiare le impostazioni da programma), ed ho scoperto che c'è un modo per aprire uno stream in output su file, ovvero:
url.openConnection().getOutputStream()
Il problema è che mentre in lettura va tutto bene, in scrittura ottengo sempre una IOException.
java.net.UnknownServiceException: protocol doesn't support output
at java.net.URLConnection.getOutputStream(URLConnection.java:792)
E questo quando faccio la seguente cosa:
property.store(url.openConnection().getOutputStream(), null);
Dove property ovviamente è un oggetto di tipo Properties.
Prima con il FileOutputStream non c'era problema.
banryu79
18-02-2010, 11:02
Consultando i javadoc si scopre che URLConnection è una classe astratta e che il metodo openConnection() della classe URL restituisce una sottoclasse specifica di URLConnection: in genere o HttpURLConnection oppure JarURLConnection.
Ovviamente ad una specifica sottoclasse corrisponde uno specifico protocollo di comunicazione a cui quella "connection" obbedisce.
Il tuo caso è quello del JarURLConnection; se si consultano i javadoc di questa classe, ad un certo punto si legge questo:
JarURLConnection instances can only be used to read from JAR files. It is not possible to get a OutputStream to modify or write to the underlying JAR file using this class.
Mistero spiegato.
fbcyborg
18-02-2010, 11:30
No, un momento, il problema che ho descritto sopra accade quando avvio il programma da Eclipse!
Già così facendo non riesco a scriverci.
Quindi fammi capire, se l'applicazione deve girare "con un jar" devo scrivere un determinato codice sorgente, altrimenti un altro...
Ma è assurdo!
Io devo poter sviluppare le mie applicazioni in modo che siano avviabili in entrambi le situazioni. Non è che siccome l'applicazione verrà eseguita come jar, allora devo compilarla con del codice diverso.. La cosa non è per niente bella!
EDIT: OK, quindi? come posso fare per scrivere su un file di configurazione nel jar? Ho modificato 2000 cose nel progetto per renderle "compatibili" quando sarà fatto il jar, e ora? Non posso scrivere su un file? -_-
JarURLConnection instances can only be used to read from JAR files. It is not possible to get a OutputStream to modify or write to the underlying JAR file using this class.
Ma quindi... è possibile o no scrivere su un file all'interno di un jar? Non l'ho mica capita questa cosa.
In giro ho letto che non è possibile, ma a giudicare da questa frase sopra sembra non sia possibile solo usando questa classe. Allora qual'è l'alternativa?
E' possibile - tutto è possibile - ma non direttamente.
E se usassi un Preferences? A me non piace perchè non mi piace scrivere cose in cartelle diverse da quelle del programma ma è molto comodo.
Un Preferences è una mappa di valori che Java salva dove il sistema operativo concentra le impostazioni delle applicazioni. Fa tutto da solo, tu devi solo fornirgli i valori di default nel caso in cui non siano stati precedentemente salvati.
Esempio:
package it.tukano.test;
import java.util.prefs.*;
import java.util.concurrent.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Preferences pref = Preferences.userNodeForPackage(Main.class);
String valore1 = pref.get("valore1", DefaultPreferences.VALORE_1);
String valore2 = pref.get("valore2", DefaultPreferences.VALORE_2);
Double valore3 = pref.getDouble("valore3", DefaultPreferences.VALORE_3);
System.out.println("Valore1: " + valore1);
System.out.println("Valore2: " + valore2);
System.out.println("Valore3: " + valore3);
pref.put("valore1", "bye bye world");
pref.put("valore2", "bongo");
pref.putDouble("valore3", 33.3);
}
}
interface DefaultPreferences {
String VALORE_1 = "hello world";
String VALORE_2 = "bingo";
Double VALORE_3 = 10.5;
}
fbcyborg
18-02-2010, 15:44
Preferirei non usare Preferences. Ti ringrazio.
Il punto è questo. Io potrei anche fare in modo di avere una directory per il programma, in cui all'interno sono presenti:
myproject.jar
config
print
config e print sono due directory. La prima come sapete contiene config.xml e inoltre un file che uso per altri scopi, ma che anch'esso deve poter essere scritto. In print ci sono dei file che usa Jasper Reports, ed anch'essi devono essere scrivibili a runtime.
E' chiaro, che preferirei avere tutto in un jar, senza files o directory esterni, ma se proprio non ne posso fare a meno lo faccio.
Ora qui due grossi problemi.
1) come già si è capito, accedo alle risorse con getResource(), ma va bene in lettura e non in scrittura per gli OutputStream. Qui vorrei capire come fare per scriverci, usando sempre questo sistema, altrimenti sono nei guai, visto che ho modificato tutto.
2) nel caso in cui voglia lasciare fuori la dir config e print, vorrei capire come accedervi (sempre con getResource), e la cosa vorrei che funzionasse sia mentre sto sviluppando con Eclipse, sia quando decido di fare il jar. Non è che siccome devo fare il jar, devo scrivere un codice diverso, e rimodificarlo quando devo tornare a sviluppare su Eclipse (non so se mi spiego).
Ho letto una marea di cose su Internet, ma non riesco a venirne fuori.
Quindi i miei obiettivi sono:
1) a prescindere da qualsiasi situazione, vorrei poter sviluppare, creare il jar e fare in modo che funzioni, sia se sto avviando l'applicazione (diciamo) da riga di comando, sia che sia sotto forma di jar.
2) risolvere il problema della scrittura su file (e questo anche in base alla scelta di lasciare le dir config e print fuori o meno dal jar (la mia preferenza si è capita)
Grazie ancora.
EDIT: al momento ho risolto con la scrittura nel seguente modo:
Ho messo
properties.storeToXML(new FileOutputStream(new File(url.getFile())), null);
al posto di
properties.storeToXML(url.openConnection().getOutputStream(), null);
Ma chiaramente non funzionerà nel jar...
Per getResource, senza jar puoi:
1. dire ad eclipse di non includere la cartella config nel jar ma di copiarla nella cartella dist
2. assicurarti che quella cartella sia nel classpath di eclipse e del jar
3. convertire l'url a file e poi aprire uno stream in scrittura per aggiornarlo (new File(url.toURI()))
Se usi il jar puoi:
1. determinare il percorso del jar sul filesystem
2. clonare il contenuto in memoria
3. creare un secondo jar con lo stesso contenuto del primo salvo il nuovo file config
4. sostituire il vecchio jar col nuovo
fbcyborg
18-02-2010, 16:51
Per getResource, senza jar puoi:
Senza jar intendi "caricare il progetto senza fare il jar e quindi, ad esempio da riga di comando"?
1. dire ad eclipse di non includere la cartella config nel jar ma di copiarla nella cartella dist
2. assicurarti che quella cartella sia nel classpath di eclipse e del jar
Ho smanettato parecchio per capire come si fa, ma ho dei dubbi. Tipicamente modifico il classpath andando in Proprietà del progetto->java build path->Add JARs... Ma per una qualunque directory non ho capito bene come fare.
3. convertire l'url a file e poi aprire uno stream in scrittura per aggiornarlo (new File(url.toURI()))
Ok, quindi, questo l'ho fatto, come ho scritto nel precedente post. Funziona.. non so se funzionerà quando avvierò l'applicazione con il jar.
Se usi il jar puoi:
Ok, quindi intendi dire "carico l'applicazione tramite un jar file" (ma secondo il mio modesto parere, deve funzionare sia che lo stia caricando con il jar sia da Eclipse (per esempio).
1. determinare il percorso del jar sul filesystem
2. clonare il contenuto in memoria
3. creare un secondo jar con lo stesso contenuto del primo salvo il nuovo file config
4. sostituire il vecchio jar col nuovo
2, 3 e 4 mi sembrano un po' troppo laboriosi :(
Ad esempio, sarebbe possibile fare la seguente cosa?
Sviluppare l'applicazione in modo che utilizzi il file di configurazione che si trovi "fuori" dalla root .. o meglio:
Progetto
--bin
--src
--config
Se io sono in bin/ ed eseguo l'applicazione, la dir config è un livello sopra alla classe che sto eseguendo.
(Attualmente config è sia in src/ che in bin/)
Allora in base a questa cosa, sarebbe "bello" che quando esporto il jar, mi ritrovo dentro ad una directory con:
Progetto.jar
config
Le due cose mi piacerebbe che funzionino, sia che mi trovi ad eseguirlo con il jar, sia che mi trovi ad eseguirlo da dentro bin/, e questo senza modificare il codice.
Sui dettagli di eclipse purtroppo non so aiutarti perchè non lo uso nè mai lo userò. Comunque il build lo dovrebbe fare con ant quindi puoi modificare il build.xml per personalizzare il procedimento.
La possibilità di far funzionare la faccenda da ide, jar, console o javaws non è un parere, è una certezza :D.
E' tra l'altro una questione elementare solo che dev'esserci qualcosa che ti sfugge, la classica minuzia a cui non pensi e che ti frega sghignazzando - quante volte m'è capitato! - ma non riesco a capire cosa sia.
Sicuro di non voler usare Preferences? E' lì bello pronto...
fbcyborg
18-02-2010, 17:29
Sì sono sicuro.
Non voglio cambiare il sistema per il quale ho penato tanto durante la realizzazione. :)
Per quanto riguarda Eclipse, io lo uso da diversi anni, anche se ovviamente non posso conoscerne tutti i meandri.
fbcyborg
18-02-2010, 17:42
Allora scusa eh..
supponiamo che io voglia tenere dentro src/ e bin/ tutto ciò che è sorgente e binario rispettivamente; solo per quanto riguarda classi e librerie.
Supponiamo che io metta allo stesso livello di src/ e bin/ le directory, images, config e print (dir che uso per Jasper Reports).
A questo punto, quando farò il jar, il suo contenuto corrisponderà al contenuto della directory bin/ e si troverà in una directory con le dir config print e images.
Come faccio ad accedere a queste dir esterne alla dir bin/ e quindi al futuro jar, usando sempre getResources()?
Anche volendo non riesco ad andare su di un livello con quel metodo.
Il contenuto della directory bin viene cancellato ad ogni compilazione.
Comunque dato un file X passi alla cartella superiore con X.getParentFile().
Se hai un URL devi trasformarlo in file (ammesso che sia un file):
File file = new File(url.toURI());
e passi alla cartella superiore come prima.
fbcyborg
18-02-2010, 21:12
Ok, ma nel caso di un'immagine ad esempio come faccio?
Ad esempio se devo mettere un'immagine in una JLabel, faccio:
jLabel5.setIcon((new ImageIcon(this.getClass().getResource(IMAGES_DIR +"logo.png"))));
Per ora, IMAGES_DIR è la dir images all'interno di src/ che poi io copio anche in /bin.
Il problema è che in questo caso io passo un URL al costruttore ImageIcon, non un File, quindi non potrei fare getParentFile(),
se volessi mettere la dir images un livello sopra, che quindi poi sarà fuori dal jar.
Se ha un file puoi usare il costruttore di ImageIcon che prende il percorso di un file.
fbcyborg
18-02-2010, 22:02
Ok, con un
jLabel5.setIcon(new ImageIcon("images/logo.png"));
vede le immagini che ho messo ad una dir allo stesso livello di bin/ e src/.
Ma per i file di configurazione? siamo sempre lì.
File ha un metodo, getPath, che restituisce il percorso di quel file ed è una stringa. La stringa puoi usarla per costruire un ImageIcon.
fbcyborg
18-02-2010, 22:09
Ok, scusa, ho aggiornato il post precedente, pare che in quel modo le immagini vadano.. anche se rimane il problema dei files di conf.
Quindi così, intanto, la dir delle immagini la metto fuori dal jar, e così dovrebbe funzionare.
Non funziona.
Il modo che hai scelto dipende dal valore della variabile user.dir che cambia secondo la directory di lavoro del programma.
fbcyborg
18-02-2010, 22:17
Noooo!
Ma ho appena modificato tutto!
Sto diventando pazzo!!!
Menomale che ho SVN.
fbcyborg
20-02-2010, 13:27
Penso di aver risolto.
Mettendo la dir delle immagini, quella che contiene i files di configurazione e quella per i files richiesti da JasperReports, allo stesso livello del jar (e quindi allo stesso livello di bin/ e src/) pare che non ci siano problemi. Ho usato File per caricare i files in tutti i casi, e quando faccio partire il jar trova sempre i files che servono.. Immagini e config files.
Ora però ho un altro problema.
L'applicazione parte, sia da Eclipse che da jar, solo che quando parte con il jar ad un certo punto viene terminata senza motivo.
La mia applicazione parte con un Form di login, e dopo aver premuto OK, viene chiuso e caricata la finestra principale del programma.
Quando premo su questo tasto OK, il programma termina senza dare eccezioni.
Ma non capisco perché.
Forse ho un problema con il driver jdbc che non viene trovato.
L'applicazione parte, sia da Eclipse che da jar, solo che quando parte con il jar ad un certo punto viene terminata senza motivo.
eh eh, questa non è male :D.
A meno che il tuo PC non sia assurto all'autocoscienza un motivo ci sarà.
Se non hai una traccia dell'eccezione è perchè da qualche parte viene ingoiata - che è male.
Le cause possono essere le più varie, senza l'eccezione non si può dir nulla.
Al limite potrebbe essere un errore della jvm. In questo caso dovresti trovarti un file di log con le cause nella cartella di esecuzione del programma (hs pid qualcosa.txt).
fbcyborg
20-02-2010, 14:23
Ho abilitato il printStackTrace() e ho avviato il jar in modalità verbosa ed ho trovato l'eccezione:
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
In pratica va in errore all'istruzione:
Class.forName("com.mysql.jdbc.Driver");
Eppure quando lancio da Eclipse funziona benissimo.
La versione del connector che uso è la 5.1.6. Pensavo di aggiornarla ma non capisco perché non dovrebbe caricarsi con il jar.
EDIT: niente.. anche aggiornando alla 5.1.12 non cambia nulla.
Verifica che il file manifesto del del jar creato da eclipse contenga la proprietà "Class-Path" e tra i suoi valori ci sia il jar del driver jdbc che usi. Una cosa tipo:
Manifest-Version: 1.0
Main-Class: qualcosa
Class-Path: lib/connectorjxyz.jar
Verifica inoltre che eclipse esporti i jar da cui dipende il tuo programma nella cartella dist (o l'equivalente in cui si trova il jar del tuo programma)
fbcyborg
20-02-2010, 14:32
Effettivamente il connector c'è nel jar, ma il MANIFEST file non ha alcun classpath settato.
Strano che non lo faccia in automatico.
fbcyborg
20-02-2010, 15:00
Dici che è corretto scrivere un Manifest del genere?
Manifest-Version: 1.0
Main-Class: Main
Class-Path: lib/jcalendar-1.3.2.jar lib/looks-2.0.1.jar lib/mysql-connector-java-5.1.12-bin.jar lib/print/*
Ho messo l'asterisco perché se li aggiungevo tutti mi dava un "line too long" in generazione del manifest.
L'ultima volta che ho provato l'asterisco non lo prendeva. Comunque puoi andare a capo.
fbcyborg
20-02-2010, 17:13
Il fatto è che se imposto il mio manifest così, mi da invalid header field
Manifest-Version: 1.0
Main-Class: Main
Class-Path: lib/jcalendar-1.3.2.jar
lib/looks-2.0.1.jar
lib/mysql-connector-java-5.1.12-bin.jar
lib/print/ant-1.7.1.jar
lib/print/ant-apache-log4j.jar
lib/print/antlr-2.7.5.jar
lib/print/barbecue-1.5-beta1.jar
lib/print/barcode4j-2.0.jar
lib/print/batik-anim.jar
lib/print/batik-awt-util.jar
lib/print/batik-bridge.jar
lib/print/batik-css.jar
lib/print/batik-dom.jar
lib/print/batik-ext.jar
lib/print/batik-gvt.jar
lib/print/batik-parser.jar
lib/print/batik-script.jar
lib/print/batik-svg-dom.jar
lib/print/batik-svggen.jar
lib/print/batik-util.jar
lib/print/batik-xml.jar
lib/print/bcel-5.2.jar
lib/print/bsh-2.0b4.jar
lib/print/commons-beanutils-1.8.0.jar
lib/print/commons-collections-2.1.1.jar
lib/print/commons-digester-1.7.jar
lib/print/commons-javaflow-20060411.jar
lib/print/commons-logging-1.0.4.jar
lib/print/groovy-all-1.5.5.jar
lib/print/hibernate3.jar
lib/print/hsqldb-1.8.0-10.jar
lib/print/iText-2.1.7.jar
lib/print/jasperreports-3.7.1.jar
lib/print/jaxen-1.1.1.jar
lib/print/jcommon-1.0.15.jar
lib/print/jdt-compiler-3.1.1.jar
lib/print/jfreechart-1.0.12.jar
lib/print/jpa.jar
lib/print/jxl-2.6.jar
lib/print/log4j-1.2.15.jar
lib/print/mondrian-3.1.1.12687.jar
lib/print/png-encoder-1.5.jar
lib/print/poi-3.5-FINAL-20090928.jar
lib/print/rhino-1.7R1.jar
lib/print/saaj-api-1.3.jar
lib/print/servlet.jar
lib/print/spring-beans-2.5.5.jar
lib/print/spring-core-2.5.5.jar
lib/print/xalan-2.6.0.jar
lib/print/xercesImpl-2.7.0.jar
lib/print/xml-apis-ext.jar
lib/print/xml-apis.jar
EDIT: ho scoperto che mancava uno spazio prima di ogni linea.
Solo che non mi parte uguale. Non trova questo driver com.mysql.connector.
Continuo a cercare il problema.
devi metterci due spazi davanti:
Class-Path: linea1
linea2
linea3
linea4
Prova anche con:
Class-Path: lib/print/
Cioè senza asterisco.
fbcyborg
20-02-2010, 17:34
Grazie, ne è bastato uno di spazio. :)
Ora invece si avvia ma continua a killarsi il programma, dopo che ho premuto OK, e anche con java -jar -verbose, non riesco a catturare alcuna eccezione.
Mamma mia che nervi sta cosa... da eclipse gira, da jar no! :muro:
fbcyborg
21-02-2010, 15:34
Di nuovo problemi con questo dannato:
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
Ogni tanto ce n'è una... eppure il jar è nel classpath del manifest ed è incluso nel jar del programma.
EDIT: finalmente l'odissea sembrerebbe finita. :yeah:
Ho spostato i jar delle librerie usate, fuori dal jar del programma. Mea culpa.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.