Re:Quem me chamou?

16 respostas
Guerr

Você tem que criar um objeto do tipo Throwable e através deste objeto acessar o stack de chamada de métodos. Com isto você consegue saber qual foi o método que o chamou… Que eu saiba esta é a única forma de sefazer isto em Java.

É acochambrado, mas funciona!!!

16 Respostas

furutani

Eu acho que AOP te ajudaria nesse caso.

Guerr

Puxa!!! Que droga!!!

Neste caso talvez a melhor opção seja fazer a modelagem e passar algum parâmetro que permita a identificação de onde aquele método foi chamado.

Guerr

Vamos lá!! O problema está ficando mais complicado…

Como não dá para acessar de onde chamou o método e nem passar um parâmetro para o método, uma sugestão seria você colocar alguma coisa em um ThreadLocal e acessar de dentro do método… Se você criar um proxy antes de chamar o método (não dá para ser dinâmico por causa da JDK 1.3) dá para você colocar nesta variável ThreadLocal o método que você vai chamar. Se você quiser criar o proxy dinamicamente e quiser aprender uma parada hardcore, você pode fazer isto utilizando a CGLIB.

Resolve o problema?

Guerr

Valeu!!! Heheheh!!!

Quando você descobrir como o Log4J faz você posta aí que eu fiquei curioso… E vai ser mais uma coisa na manga para soluções mirabolantes como esta!!!

T

Atenção: o código abaixo é só um esboço - há um monte de StringWriters/Readers e PrintWriters que devem ser fechados.

import java.io.*;

class TesteThrowable {
     public void funcao3 () {
         Throwable th = new Throwable();
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter (sw);
         th.printStackTrace (pw);
         System.out.println ("*** O stack trace gerado artificialmente ***");
         System.out.println (sw);
         
         BufferedReader br = new BufferedReader (new StringReader (sw.toString()));
         try {
             System.out.println ("*** Quem me chamou? ***");
             String quemMeChamou;
             br.readLine(); // pulo a primeira linha que é lixo
             br.readLine(); // pulo a segunda que é esta própria rotina
             quemMeChamou = br.readLine(); 
             System.out.println (quemMeChamou); // o resultado deve ser "funcao2"
         } catch (IOException ex) {
         }
     }
     public void funcao2 () {
         funcao3();
     }
     public void funcao1 () {
         funcao2();
     }
     
     public static void main(String[] args) {
         TesteThrowable tt = new TesteThrowable();
         tt.funcao1();
     }
}
Guerr

Caramba!!! Cada manobra hein!!! Vai dar um trabalhinho, mas eu acho que o caminho é este…

T

O .NET (pelo menos na versão 1.1) tem uma coisa semelhante ao getStackTraceElement(), só que ele faz uma coisa muito feia - se a rotina for considerada passível de ser posta “inline”, o stack trace começa a “pular” níveis de rotinas - e então, muitas vezes, você não consegue saber exatamente “quem me chamou”.

Em contraste, mesmo que o JIT do Java faça a mesma otimização (“pular rotinas”), o stack trace sempre é correto (acho que é por isso que o tratamento de exceptions é relativamente lento em Java, já que tem de ser feita uma “desotimização” em tempo de execução).

Eu tive esse problema quando tive de fazer algo parecido com isso em .NET - argh!

cv1

Ja deu uma olhada em Thread.currentThread().getStackTrace()?

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html#getStackTrace()

seufagner

como faço para saber, runtime, qual metodo/construtor invocou um suposto método alvo…

Ex:

class A{

String getB(){

return new B().get(); // aqui retornaria os valores da class A e método getB

}

}

class B(){

String get(){

return "Método chamado a partir da classe “++”, método "+;

}

}

seufagner

Não é a maneira mais elegante (se bem que a única) nem a “semanticamente correta”, mas rola mesmo…

valeu Guerra!

seufagner

o ambiente é muito restrito e nao vejo necessidade em acoplar um framework aop para o caso… adicionaria complexidade desnecessaria, ja que é um cenario unico e isolado, dentro do sistema, que dificilmente vai ser modificado…

valeu a força furutani :wink:

seufagner

funciona… a partir do 1.4… o weblogic daqui roda 1.3 rsrs
ouvi falar que o log4j utiliza algo parecido, analisando seu fonte, e roda no 1.3… vou dar mais uma investigada, posto a solução aqui depois

seufagner

o caso é: uma manutenção no framework proprietário. a intenção Guerra é realmente eliminar a parametrizacao. ao executar um execute(), executeUpdate() etc… montar o comentario para a sentenca sql “por baixo dos panos”… isto mostra-se necessário devido ao fato da equipe ser relativamente grande e com muita gente inexperiente, esquecida ou adjetivos semelhantes… rsrs…

só para atenuar, o sistema é grande, com muito jsp “macarrônico” acessando classes diretamente ou não… ou seja, pode ter impactos desagradáveis, claro, qualquer tipo de remodelagem…

o gostoso da nossa área é justamente isso… os desafios, não só codificar ou utilizar o framework mais high-tec… rs

seufagner

nao da pra rebuscar nao… embora threadlocal tenha bom desempenho por usar codigo hash o lance de utiliza-la vai ficar custoso, tendo em vista que todas as classes de acesso a dados terao q ter seu proxy… mesmo que pudesse usar proxy dinamico, ainda sim ia ficar custoso, acredito. ja usei o cglib num projeto, o garoto é poderoso… mas nao tem no meu classpath e ninguem quer colocar ele por aqui nao, é uma burocracia do caralho acrescentar um lib q seja… rsrs… mas ficou bonita essa tua ideia, gostei mesmo Guerra…

em tempo, to olhando a api do log4j pra sentir a solucao dos caras… exatamente a classe PatternLayout que implementa o %C2% na hora de formatar o Layout que o cara configurou… %C2% mostra a classe e o metodo, mesmo na 1.3… to curioso pra ver como o cara implementou isso…

seufagner

o lance é que assim vai sempre supor que está na terceira linha… nem sempre será assim… consegui emular aqui uma situação que retornou null… o lance é por aí mesmo, similar à utilizada pelo Log4J, porém a jogada de como manipular o string correspondente ao stack é diferente… valeu thingol!

matando a curiosidade (minha inclusive), no Log4J, quem diria, eles fazem um jogo de lastIndexOf, substring e tosqueiras a parte! rsrsrs… tudo pela compatibilidade com o 1.3 q ainda nao tinha metodo algum que devolvesse o stack… (vide classe LocationInfo)

a partir da 1.4 ja se encontra o getStackTraceElement() que retorna um array de objetos de StackTraceElement… uma beleza!

[]s pessoal!

seufagner

aqui usam 1.3 e nao vao mudar nem tao cedo por varias questoes, inclusive o medo que quiçá surjam incompatibilidades aos artefatos. e, mais ainda, porque a versao do weblogic daqui so roda na 1.3… logo é sempre um “se vira nos 30” rsrs

Criado 4 de dezembro de 2006
Ultima resposta 5 de dez. de 2006
Respostas 16
Participantes 5