2008-12-31 20 views
21
java -classpath ../classes;../jar;. parserTester 

¿Cómo puedo obtener la funcionalidad en el comando anterior programáticamente? Al igual que, ¿es posible ejecutar como:¿Es posible "agregar" dinámicamente a classpath en java?

java parserTester 

y obtener el mismo resultado? Intenté usar URLClassLoader pero modifica el classpath y no lo agrega.

Gracias!


Gracias por la respuesta Milhous. Pero eso es lo que estoy tratando de hacer ... ¿Cómo es posible poner el jar en el classpath primero? He intentado utilizar un cargador de clases a medida demasiado :(

que funciona .. Pero siento que necesito para funcionar sólo como: parserTester java Me gustaría saber si tal cosa es posible ???

Necesita ser tan bcoz tengo parserTester.java y .class en una carpeta separada. Necesito retener la estructura del archivo. El analizador sintáctico hace uso de un contenedor en una carpeta jar separada.

+0

tiene que comenzar con 1 clase/jar en el classpath. – Milhous

+0

¿por qué necesita ser java parserTest? – Milhous

+1

¿Por qué le gustaría ajustar dinámicamente la ruta de clase en tiempo de ejecución? –

Respuesta

1

Puede implementar su propio class loader , pero esa clase/jar debe estar en el classpath para que se ejecute.

tratar

java -cp *.jar:. myClass 

o

export CLASSPATH=./lib/tool.jar:. 
java myClass 

o

java -jar file.jar 
0

¿Entendí bien ?! ¿La única razón por la que lo tiene es que desea iniciar su clase sin especificar el classpath y cargarlo en tiempo de ejecución? ...

java parserTester

en lugar de

java -classpath ../classes;../jar ;. parserTester

Probablemente no entendí la razón. Pero si "eso es" lo que se desea se puede hacer lo siguiente (aunque no tiene mucho sentido para mí)

  • lanzamiento de la clase
  • Desde el principal método lauch otra clase un conjunto mediante programación la ruta de clase allí.
  • Fin de la historia.

algo como lo siguiente "java código -pseudo"

public static void main(String [] args) { 
    String classpath = "classes;../jar"; 
    Runtime.getRuntime().execute("java + classpath + " parserTester "); 
} 

por favor dígame si lo estoy haciendo bien. Si quieres hacer otra cosa, me gustaría ayudar.

1

Tengo que estar de acuerdo con los otros dos carteles, parece que está complicando demasiado una clase de prueba. No es tan inusual tener los archivos .java y .class en carpetas separadas, mientras que depende de los archivos jar aún en un tercio, sin cambiar programáticamente el classpath. Si lo hace porque no quiere tener que escribir classpath en la línea de comandos cada vez, sugeriría un script de shell o un archivo por lotes. Mejor aún, un IDE. La pregunta que realmente tengo es ¿por qué estás tratando de administrar el classpath en el código?

0

Puede escribir un archivo por lotes o un archivo de script de shell para exportar la ruta de clase y ejecutar el programa java. En Windows,

conjunto classpath =% ruta de clase%; ../ clases; ../ tarros/* java ParserTester

En Unix, export CLASSPATH =% ruta de clase%: ../ clases :. ./jars/* java ParserTester

Si nombra el nombre del archivo como parser.bat o parser.sh, puede ejecutarlo llamando al analizador en el sistema operativo respectivo.

desde Java 1.6, puede incluir todos los frascos en un directorio en la ruta de clase con sólo decir/*

Si usted está tratando de generar un archivo Java de forma dinámica, recopilar y agregar a la ruta de clases, establecer el directorio en el que el archivo de clase se genera en el classpath de antemano. Debería cargar la clase. Si está modificando la clase java ya generada, básicamente volviendo a compilar después de la modificación y si desea cargar la nueva clase, necesita usar su cargador de clases personalizado para evitar el almacenamiento en caché de la clase.

21

Puede utilizar un java.net.URLClassLoader para cargar clases con cualquier programa de lista definida de la URL del que desea:

URLClassLoader clase pública se extiende SecureClassLoader

Este cargador de clases se utiliza para cargar clases y recursos de una búsqueda ruta de URL que hace referencia a ambos archivos y directorios JAR . Se supone que cualquier URL que termina con un '/' hace referencia a un directorio. De lo contrario, el URL es se supone que se refiere a un archivo JAR que se abrirá según sea necesario.

El AccessControlContext de la rosca que crea la instancia de URLClassLoader se utilizará cuando clases posteriormente de carga y recursos.

Las clases que se cargan son por el permiso concedido por defecto sólo para el acceso los URL especificados cuando se creó el URLClassLoader.

Desde: 1.2

Y un poco de juego de piernas puede extenderlo para apoyar el uso de nombres de ruta comodín para recoger directorios enteros de archivos JAR (este código tiene algunas referencias a métodos de utilidad, pero su aplicación debería ser obvio en el contexto):

/** 
* Add classPath to this loader's classpath. 
* <p> 
* The classpath may contain elements that include a generic file base name. A generic basename 
* is a filename without the extension that may begin and/or end with an asterisk. Use of the 
* asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match 
* the specified basename will be added to this class loaders classpath. The case of the filename is ignored. 
* For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*" 
* means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files 
* that contain "abc" and end with ".jar". 
* 
*/ 
public void addClassPath(String cp) { 
    String        seps=File.pathSeparator;    // separators 

    if(!File.pathSeparator.equals(";")) { seps+=";"; }       // want to accept both system separator and ';' 
    for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens();) { 
     String pe=st.nextToken(); 
     File fe; 
     String bn=null; 

     if(pe.length()==0) { continue; } 

     fe=new File(pe); 
     if(fe.getName().indexOf('*')!=-1) { 
      bn=fe.getName(); 
      fe=fe.getParentFile(); 
      } 

     if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\\') { fe=new File(rootPath,fe.getPath()); } 
     try { fe=fe.getCanonicalFile(); } 
     catch(IOException thr) { 
      log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+")."); 
      continue; 
      } 
     if(!GenUtil.isBlank(bn)) { 
      fe=new File(fe,bn); 
      } 
     if(classPathElements.contains(fe.getPath())) { 
      log.diagln("Skipping duplicate classpath element '"+fe+"'."); 
      continue; 
      } 
     else { 
      classPathElements.add(fe.getPath()); 
      } 

     if(!GenUtil.isBlank(bn)) { 
      addJars(fe.getParentFile(),bn); 
      } 
     else if(!fe.exists()) {             // s/never be due getCanonicalFile() above 
      log.diagln("Could not find classpath element '"+fe+"'"); 
      } 
     else if(fe.isDirectory()) { 
      addURL(createUrl(fe)); 
      } 
     else if(fe.getName().toLowerCase().endsWith(".zip") || fe.getName().toLowerCase().endsWith(".jar")) { 
      addURL(createUrl(fe)); 
      } 
     else { 
      log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.zip' or '.jar'"); 
      } 
     } 
    log.diagln("Class loader is using classpath: \""+classPath+"\"."); 
    } 

/** 
* Adds a set of JAR files using a generic base name to this loader's classpath. See @link:addClassPath(String) for 
* details of the generic base name. 
*/ 
public void addJars(File dir, String nam) { 
    String[]       jars;         // matching jar files 

    if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); } 

    if(!dir.exists()) { 
     log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'"); 
     return; 
     } 
    if(!dir.canRead()) { 
     log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'"); 
     return; 
     } 

    FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true); 
    if((jars=dir.list(fs))==null) { 
     log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'"); 
     } 
    else if(jars.length==0) { 
     log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'"); 
     } 
    else { 
     log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'"); 
     Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER); 
     for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); } 
     } 
    } 

private URL createUrl(File fe) { 
    try { 
     URL url=fe.toURI().toURL(); 
     log.diagln("Added URL: '"+url.toString()+"'"); 
     if(classPath.length()>0) { classPath+=File.pathSeparator; } 
     this.classPath+=fe.getPath(); 
     return url; 
     } 
    catch(MalformedURLException thr) { 
     log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL"); 
     return null; 
     } 
    } 
+0

SoftwareMonkey. No entendí la pregunta. Parece una cuestión avanzada, pero luego la explicación que da no tiene ningún sentido: "porque tengo parserTester.java y .class en una carpeta separada. Necesito conservar la estructura del archivo". Creo que su respuesta servirá para una pregunta más correcta :) +1 – OscarRyz

-1

excelente buen puesto, en mi caso me hizo esto funcione bien (nota: Windows específica):

set classpath=%classpath%;../lib/* 
java -cp %classpath% com.test.MyClass 
+0

Este enfoque responde a una pregunta un poco diferente de la publicación. El uso del enfoque de ruta de clase "comodín", que está disponible en Java 1.6+, permitiría cargar todos los JAR/clases en la carpeta determinada, lo que evitaría tener que definir cada archivo explícitamente, pero no ayudaría con la carga dinámica. – jwj

0

Creo que lo que quiere es un "Ejecución Envoltura" o una plataforma específica "Launcher" ... normalmente, este componente se usa para detectar su sistema operativo, arquitectura y dependencias, y luego realiza ajustes antes de iniciar su aplicación. Es un patrón de diseño de la vieja escuela (hablando de los años 80 y anteriores) pero todavía se usa mucho hoy en día. La idea es que el programa puede ser independiente del sistema y del entorno y el iniciador hará los preparativos y le dirá al software todo lo que necesita saber. Muchos programas modernos de código abierto lo hacen con scripts de Shell y archivos por lotes, etc. Apache Tomcat, por ejemplo. Podría hacer el envoltorio en java y lanzar el software con un comando de línea de ejecución (asegúrese de agregar "&" al final de su comando exec en * NIX para que su envoltorio pueda salir dejando solo el software en ejecución. .. también le permite cerrar la ventana del shell sin matar el proceso)

Cuestiones relacionadas