Recargar una clase modificada.
SO: Windows XP
JVM: 1.4.2_02<br>
PROBLEMA: al recargar una clase, que ha sido modificada despu茅s de la primera carga, la JVM sigue manteniendo la versi贸n que carg贸 inicialmente.<br>
OPERATORIA: he creado dos clases:<b>Lanzador.java</b> y <b>Mutante</b>.java<br>
<b>Lanzador.java</b> crea un objeto <i>URLClassLoader</i>, carga la clase <b>Mutante.java</b> a trav茅s de este cargador.<br>
<b>Mutante.java</b> devuelve la versi贸n.<br>
<b>Lanzador.java</b>, entre carga y carga de la clase <b>Mutante.java</b>, espera a que se pulse una tecla. De esta forma, puedo recompilar la clase <b>Mutante.java</b> con otro n煤mero de versi贸n, y sustituir en <i>"c:\PRUEBAS\ADC\adc"</i> la clase <b>Mutante.java</b> recompilada.<br>
El resultado es siempre el mismo: el cargador de clases, que he creado, no carga la nueva clase modificada.<br>
/*********************Lanzador.java*************************/
package adc;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
public class Lanzador {
public Lanzador() {
while (true) {
try {
System.out.println("Pulse una tecla.");
System.in.read();
cargarNuevaVersion();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
private void cargarNuevaVersion() {
URLClassLoader cargador;
Class claseMutante;
Method metodoGetVersion;
try {
URL[] urls = {
new File("c:\PRUEBAS\ADC/").toURL()};
cargador = new URLClassLoader(urls);
System.out.println("Cargador actual:" +
Thread.currentThread().getContextClassLoader().
toString());
claseMutante = Class.forName("adc.Mutante", true,
cargador);
metodoGetVersion = claseMutante.getMethod("getVersion", null);
System.out.println( (String) (metodoGetVersion.invoke(null, null)));
metodoGetVersion = null;
claseMutante = null;
cargador = null;
System.gc();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
}
catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
catch (IllegalAccessException ex) {
ex.printStackTrace();
}
catch (SecurityException ex) {
ex.printStackTrace();
}
catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
Lanzador lanzador1 = new Lanzador();
}
}
/*********************Mutante.java*************************/
package adc;
public class Mutante {
private static String sVersion = "0.0.0.3";
public static String getVersion() {
return new String(sVersion);
}
}
JVM: 1.4.2_02<br>
PROBLEMA: al recargar una clase, que ha sido modificada despu茅s de la primera carga, la JVM sigue manteniendo la versi贸n que carg贸 inicialmente.<br>
OPERATORIA: he creado dos clases:<b>Lanzador.java</b> y <b>Mutante</b>.java<br>
<b>Lanzador.java</b> crea un objeto <i>URLClassLoader</i>, carga la clase <b>Mutante.java</b> a trav茅s de este cargador.<br>
<b>Mutante.java</b> devuelve la versi贸n.<br>
<b>Lanzador.java</b>, entre carga y carga de la clase <b>Mutante.java</b>, espera a que se pulse una tecla. De esta forma, puedo recompilar la clase <b>Mutante.java</b> con otro n煤mero de versi贸n, y sustituir en <i>"c:\PRUEBAS\ADC\adc"</i> la clase <b>Mutante.java</b> recompilada.<br>
El resultado es siempre el mismo: el cargador de clases, que he creado, no carga la nueva clase modificada.<br>
/*********************Lanzador.java*************************/
package adc;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
public class Lanzador {
public Lanzador() {
while (true) {
try {
System.out.println("Pulse una tecla.");
System.in.read();
cargarNuevaVersion();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
private void cargarNuevaVersion() {
URLClassLoader cargador;
Class claseMutante;
Method metodoGetVersion;
try {
URL[] urls = {
new File("c:\PRUEBAS\ADC/").toURL()};
cargador = new URLClassLoader(urls);
System.out.println("Cargador actual:" +
Thread.currentThread().getContextClassLoader().
toString());
claseMutante = Class.forName("adc.Mutante", true,
cargador);
metodoGetVersion = claseMutante.getMethod("getVersion", null);
System.out.println( (String) (metodoGetVersion.invoke(null, null)));
metodoGetVersion = null;
claseMutante = null;
cargador = null;
System.gc();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
}
catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
catch (IllegalAccessException ex) {
ex.printStackTrace();
}
catch (SecurityException ex) {
ex.printStackTrace();
}
catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
Lanzador lanzador1 = new Lanzador();
}
}
/*********************Mutante.java*************************/
package adc;
public class Mutante {
private static String sVersion = "0.0.0.3";
public static String getVersion() {
return new String(sVersion);
}
}
Yo ten铆a este problema y contact茅 con dmolano para saber si lo hab铆a conseguido resolver. Obtuve respuesta, y me envi贸 la soluci贸n y pidiendome que pusiera aqu铆 la respuesta ( cosa que ya ten铆a pensado hacer). A continuaci贸n va la soluci贸n que me envi贸, por cierto la he probado y funciona perfectamente.
****** Contenido del mail ********
El problema se soluciona cuando la clase que hace la carga de las dem谩s est谩 en un directorio y nivel diferente a ellas.
Te pongo un ejemplo.
Clase que carga:
C:AplicacionCargador de VersionesVersCli.class
Resto de las clases de la aplicaci贸n, que est谩n en el paquete jdist:
C:AplicacionResto de clasesInicioJdist*.class
La clase que carga las dem谩s "VersCli.class" es la siguiente:
package versjdist;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
public class VersCli {
static String asArgu = null;
public VersCli() {
while(true){
nuevaVersion();
try{
Thread.sleep(2000L);
}catch(Exception e){}
}
}
private void nuevaVersion(){
URLClassLoader urlcl = null;
Class classAplic = null;
Method metodoAplic = null;
try{
URL urls[] = {new File("C:\Aplicacion\Resto de clases\Inicio/").toURL()};
urlcl = new URLClassLoader(urls);
classAplic = Class.forName("jdist.ConexCli", true, urlcl); //-- Clase inicial
metodoAplic = classAplic.getMethod( "inicio",
new Class[] {Class.forName "java.lang.String")} );
Object obj[] = { asArgu }; //-- Par谩metros de la clase
metodoAplic.invoke(null, obj);
obj = null;
}catch( Throwable t){
t.printStackTrace();
}
}
public static void main( String args[] ) {
if(args.length > 0){
asArgu = args[0];
}
VersCli oInicio = new VersCli();
}
}
****** Contenido del mail ********
El problema se soluciona cuando la clase que hace la carga de las dem谩s est谩 en un directorio y nivel diferente a ellas.
Te pongo un ejemplo.
Clase que carga:
C:AplicacionCargador de VersionesVersCli.class
Resto de las clases de la aplicaci贸n, que est谩n en el paquete jdist:
C:AplicacionResto de clasesInicioJdist*.class
La clase que carga las dem谩s "VersCli.class" es la siguiente:
package versjdist;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
public class VersCli {
static String asArgu = null;
public VersCli() {
while(true){
nuevaVersion();
try{
Thread.sleep(2000L);
}catch(Exception e){}
}
}
private void nuevaVersion(){
URLClassLoader urlcl = null;
Class classAplic = null;
Method metodoAplic = null;
try{
URL urls[] = {new File("C:\Aplicacion\Resto de clases\Inicio/").toURL()};
urlcl = new URLClassLoader(urls);
classAplic = Class.forName("jdist.ConexCli", true, urlcl); //-- Clase inicial
metodoAplic = classAplic.getMethod( "inicio",
new Class[] {Class.forName "java.lang.String")} );
Object obj[] = { asArgu }; //-- Par谩metros de la clase
metodoAplic.invoke(null, obj);
obj = null;
}catch( Throwable t){
t.printStackTrace();
}
}
public static void main( String args[] ) {
if(args.length > 0){
asArgu = args[0];
}
VersCli oInicio = new VersCli();
}
}
