Compilação em Runtime

Olá, galera.

Tenho um problema com a compilação de classes java em runtime, adianto que já olhei os tópicos e não obtive solução para meu problema, dessa forma, solicito a ajuda de todos.

Tenho uma aplicação hipotética, com duas classes, A e B, sendo que A é superclasse de B

A classe A está num pacote diferente da classe B, dessa forma:

C:\apps\java\br\com\empresa\teste\pkg1\A.java
C:\apps\java\br\com\empresa\teste\pkg2\B.java

No caso, “C:\apps\java” é o root do contexto da aplicação, os pacotes seriam “br.com.empresa.teste.pkg1” e “br.com.empresa.teste.pkg2”

Em um programa java, chamo o método com.sun.tools.javac.Main.compile, que embute o javac, pra compilar as classes. Qdo vai compilar a classe B, rodando o comando

com.sun.tools.javac.Main.compile(new String[]{"C:\apps\java\br\com\empresa\teste\pkg2\B.java"},log);

ocorre o erro abaixo:

C:\apps\java\br\com\empresa\teste\pkg2\B.java:5: package br.com.empresa.teste.pkg1 does not exist
import br.com.empresa.teste.pkg1.A;
                                                   ^
C:\apps\java\br\com\empresa\teste\pkg2\B.java:7: cannot find symbol
symbol: class A
public class B extends A {
                 ^
2 errors

Se eu estivesse no prompt de comando, era fácil, era só digitar

C:> cd \apps\java
C:\apps\java> javac br\com\empresa\teste\pkg2\B.java

E a classe compilaria corretamente. Mas, nesse caso, não sei mudar o diretório corrente.

Se eu passar o caminho relativo no comando, ou seja:

com.sun.tools.javac.Main.compile(new String[]{"br\com\empresa\teste\pkg2\B.java"},log);

Ocorre o erro:

error: cannot read: br\com\akasha\irissoftware\bb\core\bean\Bbcom010.java
1 error

Ou seja, de jeito algum dá certo.

Alguem sabe como resolvo esse impasse?

Agradeço a todos a paciência e a força.

Abraços,
Buosi. :smiley:

da uma olhada nesse source. ele é auto explicativo

e lembre-se que ao usar os pacotes com.sun.tools o papai noel da portabilidade nao vai trazer seu presentinho no fim do ano :wink:

Olá,

O teu porblema esta no Class path…

No projeto Netuno.org se fizeres o download vais poder testar isto e ver como esta sendo feito… mas vou tentar te explicar…

Quando inicia a tua aplicação no ClassPath tem que ter o tools.jar e as pastas onde contem os packages completos e as clases, no caso do Netuno:
-cp “C:/develop/sdk/j2sdk1.4.2_12/lib/tools.jar;BUILD;PUBLIC

Repare que o BUILD e o PUBLIC são duas pastas, onde em PUBLIC vais ter o arquivos .java e em BUILD os arquivos .class…

Ai para compilar podes ver esta class do projeto Netuno:
http://netuno.googlecode.com/svn/trunk/src/org/netuno/server/Compile.java

Veja este pedaço de código:

/**
* Compile Java files in Class files
* @param netuno Netuno
* @param fileJava Java file to compile
* @param fileClass Class file to compile from Java file
*/
public static void engineClass(Netuno netuno, File fileJava, File fileClass) {
        if (fileClass.exists()) {
            fileClass.delete();
        }
        if (fileClass.lastModified() < fileJava.lastModified()) {
            try {
                com.sun.tools.javac.Main.compile(
                    new String[] {fileJava.toString()}, 
                    new PrintWriter(new PrintWriter(netuno.out))); 
                new File(fileJava.toString().substring(0, 
                    fileJava.toString().lastIndexOf(".")) 
                    + ".class").renameTo(fileClass);
            } catch (Exception e) {
            	logger.error("Compile java "+ fileJava +" to class "
                    + fileClass, e);
            }
        }
}

Mas o segredo esta em incluir a pasta do source no ClassPath da tua aplicação, por que se não o javac não consegue montar a tua hierarquia de classes…

E depois para executar a tua class…

Podes dar uma olhada na class Run do projeto Netuno:
http://netuno.googlecode.com/svn/trunk/src/org/netuno/server/Run.java

Neste pedaço de código:

File dir = new File(Config.getPublic());
ClassLoader loader = new URLClassLoader(new URL[] {dir.toURL()});
Class aClass = loader.loadClass(file.replace('/', '.'));
Object objectParameters[] = {netuno};
Class classParameters[] = {objectParameters[0].getClass()};
Method theMethod = aClass.getDeclaredMethod("netunoMain", classParameters);
theMethod.invoke(null, objectParameters);

Qualquer dúvida é só dize…

:wink:

Se fizers o download do projeto netuno em www.netuno.org podes testar fazer isto de duas class extender uma da outra, e veras que compila e funcina perfeitamente… exemplo:

Dentro de PUBLIC cria uma pasta com o nome test depois lá dentro coloca este arquivo Test.java:

package test;

import org.netuno.server.Netuno;

public class Test {
	protected Netuno netuno = null;
	
	public Test(Netuno netuno) {
		this.netuno = netuno;
		
	}
	
	public String getTestString() {
		return "Ok Test";
	}
}

Depois no arquivo PUBLIC/logic/Form.java faz as seguintes alterações:

public class Form extends test.Test {

public Form(Netuno netuno) {
	[b]super(netuno);[/b]
	[b]System.out.println(getTestString());[/b]

E depois roda a aplicação e quando acessares o localhost no teu browser, e depois clicar em Form vera que no prompt vai ter a saida na tela Ok Test… que esta na classe extendida pela class Form…

Compilou e executou na boa :smiley:

Tenta dar uma explorada nisto…

:wink:

Galera,

Consegui compilar a classe. Realmente, o que resolveu foi colocar o root do contexto no atributo -cp, e rodou. Assim:

sun.com.tools.javac.Main.compile(new String[]{"-cp","c:\apps\java","c:\apps\java\br\com\empresa\teste\pkg2\B.java"});

Agradeço muito ao Eduveks e Fmeyer pela ajuda.

Buosi.

Boa assim é uma ótima solução.

Mas consegues executar a classe depois de compilar? Com o ClassLoader?