[RESOLVIDO] Como saber a classe de um objeto null? [onde n podemos chamar getClass()]

Pessoal, tem como saber a classe de um objeto mesmo se ele for null?

Sei que em Object tem o método getClass(), mas se eu chamá-lo a partir de um objeto null dá NullPointerException. Existe algum método estático em alguma classe que faça isso?

[]'s

Cara,

 Experimenta o operador [i]instanceof[/i]

pesquise sobre reflection

e tbm… nao tem como saber a classe de um objeto q nao existe certo

Conheco e uso algumas coisas ja de Reflection, mas com isso é possível eu saber a classe de um objeto? achei que a idéira de Reflection fosse operar em cima de Classes, para conhecermos em tempo de execução a estrutura da classe, se herda ou implementa alguem e quem, seus atributos incluindo tipo e talvez modificadores, seus métodos, incluindo tipos de argumento, tipo de retorno, excecoes, se tem anottations, etc.

Mas com Reflection dá pra operar em cima de um objeto? em especial um objeto null?

[quote=pango]Cara,

 Experimenta o operador [i]instanceof[/i][/quote]

O instanceof não funciona porque eu preciso saber qual a classe do objeto independente de qual seja… Não tenho um subconjunto de classes pra testar o tipo do objeto…

Se eu fosse usar o instanceof teria um zilhões de if/else’s e pra cada classe nova existente eu teria que colocar mais um if/else.

Mas valeu pela força!!

o reflection serve para vc saber de onde o objeto vem, quais seu metodos e variaveis entre outros.

isso ajuda no reconhecimento automatizado de um objeto e seu tipo…

Rafael,

Você pode nos ajudar e dar mais detalhes sobre o que, afinal de contas, queres fazer? :slight_smile:

Oi, o que eu quero é generalizar uma chamada a um método através de Reflection.

Quero criar um método que recebe o objeto a invocar um método, o nome do método a ser invocado e apenas os argumentos. Usando Reflection, pra fazermos isso, precisamos pegar o método e invocá-lo, com o código abaixo:

public Object invocaMetodo(Object objeto, String nomeMetodo, Class<?>[] argumentoClasses, Object[] argumentoObjetos) throws Exception {
   Method metodo = objeto.getClass().getMethod(nomeMetodo, argumentosClasses);
   return metodo.invoke(action, argumentosObjetos);
}

Esse foi mais ou menos o código que eu coloquei pra chamar um método por Reflection, pois vários pontos da aplicação precisam desse código e resolvi centralizá-lo.

Só que, pra simplificar a chamada a tal método, gostaria de saber se tem como a partir de um objeto saber a classe dele para eu poder trocar a assinatura, retirando o parâmetro argumentoClasses e pegando o valor das classes dentro do próprio método, através do parâmetro argumentoObjetos.

Inicialmente eu estava usando objeto.getClass(), só que tem casos em que um objeto é null e, nesses casos, dá NullPointerException. Portanto, gostaria de saber se dado um objeto tem alguma forma de saber a classe dele, mesmo que ele seja null.

RafaelVC:

Tecnicamente creio que seja impossível vc conseguir o class name de um objeto não instanciado, ate porque ele não existe e portanto não há informação sobre ele que possa ser recuperada por reflection. Creio que a unica solução seria ou vc desconsiderar objetos nulos ou quem sabe talvez, fazer uma análise lexica do codigo e capturar os caracteres antes do nome do objeto.

A não ser que haja alguma API maluca que faça isso… a que chega mais perto que conheço eh o commons-lang da apache… mas ficaria algo como:

ClassUtils.getShortClassName(obj,"NULO");

Ele daria o nome se houvesse instância, e no caso de ser nulo ele retorna a string.

Quem souber de alguma API que faça o trabalho por gentileza me comunique!!!

Eu acho que você não vai conseguir fazer isso não…

Se alguem com uma explicação teórica mais aprofundada puder me corrigir/completar fique à vontade, mas o que ocorre basicamente é que não existe um “null diferente para cada classe”.

Por exemplo, faça o teste abaixo:

[code]String s = null;

if (s instanceof String) {
System.out.println(“s é String”);
} else {
// Vai entrar aqui
System.out.println(“s NÃO é String.”);
}[/code]

Você verá que não importa como a variável foi declarada, ela aponta para “nada” e esse “nada” não é objeto de nenhuma classe.

Mas um NullPointerException é exactamente o que deve dar.
Vc pode testar se o objeto é nulo e lançar outra exceção, mas é isso ai.
Mesmo que vc conseguisse obter a classe vc iria precisar de um objeto não nulo na API de reflection.

[quote=gomesrod]Eu acho que você não vai conseguir fazer isso não…

Se alguem com uma explicação teórica mais aprofundada puder me corrigir/completar fique à vontade, mas o que ocorre basicamente é que não existe um “null diferente para cada classe”.

Por exemplo, faça o teste abaixo:

[code]String s = null;

if (s instanceof String) {
System.out.println(“s é String”);
} else {
// Vai entrar aqui
System.out.println(“s NÃO é String.”);
}[/code]

Você verá que não importa como a variável foi declarada, ela aponta para “nada” e esse “nada” não é objeto de nenhuma classe.[/quote]

É exatamente isso!
Não existe objetos null especificos para cara objeto.
Não há instância não há informação sobre o objeto, ate porque ele nao existe.
E mesmo que vc ocnseguisse o nome da classe, vc nao poderia executar os metodos dele ja que daria NullPointerException de qualquer forma.

Como Java é fortemente tipada, eu achei que talvez tivesse alguma forma de Java saber isso buscando, em último caso, o tipo da variável. Porque isso ele conhece em tempo de compilação e, portanto, achei que tivesse uma forma de conhecer isso tb em tempo de execução. Algo como se o objeto for diferente de null, retorne o tipo do objeto que foi instanciado e se for igual a null retorne o tipo da variavel.

[quote=sergiotaborda][quote=RafaelVS]

Inicialmente eu estava usando objeto.getClass(), só que tem casos em que um objeto é null e, nesses casos, dá NullPointerException. Portanto, gostaria de saber se dado um objeto tem alguma forma de saber a classe dele, mesmo que ele seja null.
[/quote]

Mas um NullPointerException é exactamente o que deve dar.
Vc pode testar se o objeto é nulo e lançar outra exceção, mas é isso ai.
Mesmo que vc conseguisse obter a classe vc iria precisar de um objeto não nulo na API de reflection.[/quote]

Usando o código que eu postei anteriormente eu consigo chamar métodos através de Reflection mesmo passando os argumentos nulos.

Ex.:

public Object invocaMetodo(Object objeto, String nomeMetodo, Class<?>[] argumentoClasses, Object[] argumentoObjetos) throws Exception {
   Method metodo = action.getClass().getMethod(this.metodo, argumentosClasses);
   retorno = (ActionForward)metodo.invoke(action, argumentosObjetos);
}

public void meuMetodo(String a, String b){}

Se eu fizer uma chamada assim:

...
String parametro1 = "a";
String parametro2 = null;
invocaMetodo(objetoInstanciado, "meuMetodo", new Class<?>[]{String.class, String.class}, new Object[]{parametro1, parametro2});
...

O meuMetodo será invocado onde os parâmetros terão os valores: a=“a” e b=null.

Só que o que eu queria era retirar isso do meu código:
Class<?>[]{String.class, String.class} ( o 3. argumento do método invocaMetodo)

Dado que os tipos de parametro1 e parametro2 são String, gostaria, se possível, de uma forma que eu conseguisse as classes dos parametros.

Eu não disse “argumentos nulos” eu disse “objeto nulo”
A API de reflection como o proprio nome indica reflete sobre o objeto
Ora se não ha nenhum objeto, ela vai refletir no quê ?
(na realidade sem objeto ela pode refletir na classe e invocar metodos estáticos, mas não o caso aqui)

É ilogico invocar um método sobre uma variável null, mesmo que seja por reflection. Por isso a exceção NullPointerException é a exceção correta.

Enfim, vc não deve invocar a sua API sobre variáveis nulas.

[quote=RafaelVS]Como Java é fortemente tipada, eu achei que talvez tivesse alguma forma de Java saber isso buscando, em último caso, o tipo da variável. Porque isso ele conhece em tempo de compilação e, portanto, achei que tivesse uma forma de conhecer isso tb em tempo de execução. Algo como se o objeto for diferente de null, retorne o tipo do objeto que foi instanciado e se for igual a null retorne o tipo da variavel.
[/quote]

  1. Os tipos de variáveis estão presentes para fins de debug opcionalmente, dependendo de opções de compilação. Nem sempre.

  2. Obter essa informação (quando presente) é possível, mas trabalhoso.

  3. Você ainda precisaria de mapear seu null a um variavel. E isso, para fins práticas, acho impossível. Pode ser que não há nenhum variavel. Pode ser que alguém esteja chamando seu método passando o null literal, etc.

[quote=sergiotaborda][quote=RafaelVS]

Usando o código que eu postei anteriormente eu consigo chamar métodos através de Reflection mesmo passando os argumentos nulos.
[/quote]

Eu não disse “argumentos nulos” eu disse “objeto nulo”
A API de reflection como o proprio nome indica reflete sobre o objeto
Ora se não ha nenhum objeto, ela vai refletir no quê ?
(na realidade sem objeto ela pode refletir na classe e invocar metodos estáticos, mas não o caso aqui)

É ilogico invocar um método sobre uma variável null, mesmo que seja por reflection. Por isso a exceção NullPointerException é a exceção correta.

Enfim, vc não deve invocar a sua API sobre variáveis nulas.
[/quote]

Entendi, mas foi por isso que em umas respostas anteriores eu disse que gostaria de saber se não existe alguma outra classe com um método estático que receba a variável e retorne seu tipo, seja o do objeto ou o tipo da variável.

E, em relação ao que Sami Koivu falou, no caso do desenvolvedor passar a literal null aí realmente não tem como saber seu tipo, mas como o que eu estou fazendo é para eu mesmo utilizar, eu não passaria nunca o literal null e não precisaria de controle sobre isso. Caso eu por acaso passe a literal null sem querer, pode estourar erro porque seria erro de programação mesmo.

[quote=RafaelVS]Oi, o que eu quero é generalizar uma chamada a um método através de Reflection.

Quero criar um método que recebe o objeto a invocar um método, o nome do método a ser invocado e apenas os argumentos. Usando Reflection, pra fazermos isso, precisamos pegar o método e invocá-lo, com o código abaixo:

public Object invocaMetodo(Object objeto, String nomeMetodo, Class<?>[] argumentoClasses, Object[] argumentoObjetos) throws Exception {
   Method metodo = objeto.getClass().getMethod(nomeMetodo, argumentosClasses);
   return metodo.invoke(action, argumentosObjetos);
}

[/quote]

É possível chamar metodo.invoke(null), desde que o método em questão seja static, o que não é recomendável. O que sugiro?

Adaptadores:

public final class InvokeAdapter {
  final Method method;

  public InvokeHandler(Class<?> nomeClasse, String nomeMetodo, Class<?>... argumentos) throws MethodNotFoundException {
    this.method = nomeClasse.getMethod(nomeMetodo, (Class<?>[]) argumentos);
  }

  public Object invoke(Object instancia, Object... argumentos) throws Exception {
    return this.method.invoke(instancia, (Object[]) argumentos);
  }

  public Object invokeStatic(Object... argumentos) throws Exception {
    return invoke(null, (Object[]) argumentos);
  }
}

Não testei. Boa sorte. :slight_smile:

Putz… pelo que tou vendo, o método que escrevi, invocaMetodo que vc citou, faz a mesma coisa que o que vc escreveu, só que é mais simples de usar.

  1. para usar o método que escrevi é só uma chamada ao método:
    a) recebe o objeto, nome do metodo, classes dos argumentos, argumentos
    b) pega o método e o invoca.

  2. para usar o método que vc sugeriu preciso instanciar um objeto e chamar um método:
    a) constrói um objeto InvokeAdapter passando o nome da classe, nome do metodo e as classes dos argumentos
    b) invoca o método passando a instancia e os argumentos.

No final das contas o resultaodo é o mesmo e ainda não resolve o problema que estou tentando, que é evitar passar Class<?>[] argumentos.

Mas obrigado pela ajuda, Aldrin!

[quote=RafaelVS]Putz… pelo que tou vendo, o método que escrevi, invocaMetodo que vc citou, faz a mesma coisa que o que vc escreveu, só que é mais simples de usar.
[/quote]

Simples?

[quote=H. L. Mencken]There is always an easy solution to every human problem - neat, plausible and wrong.
[/quote]

Não sei se a sua definição de simples bate com a minha. Na verdade, acho que bate com a que o H. L. Mencken cita. Mas enfim, vou ignorar esta Thread a partir de agora, por motivos de ignorância da minha parte :).

Você esqueceu o detalhe sutil da coisa: O que define o método é, na ordem, é:

  • Classe
  • Nome
  • Tipos do Argumento (<- E ISTO ENVOLVE O Class<?>[])

A idéia do InvokeAdapter é apenas usar o mínimo possível da Reflection. E quando o fizê-lo, não ser por Object.getClass(), e sim pela definição do InvokeAdapter.

Enfim, boa sorte. Você irá precisar dela :slight_smile: