Por que você iria querer fazer isso? A informação de genéricos é descartada após a compilação, portanto instanceof T teria que ser resolvido para alguma coisa concreta. Não sei o que você quer, mas que tal mudar para:
public class Teste<T> {
public boolean teste(T obj) {
// obj sempre é do tipo T, do contrário nem compila...
return true;
}
}
é mais eu estou querendo fazer justamente o contrario… heheh
o argumento que eu vou receber precisa ser um Object…
e eu preciso testar c é instancia de T antes de prosseguir, e se não for abortar…
estou querendo fazer isso…
public <T> Filter toGenericType(final Flter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
if (candidate instanceof T)
return false;
else
return filter.match((T)candidate);
}
};
}
em resumo… quero criar um filtro generico, recebendo como argumento um filtro especifico… e como esse filtro generico pode aceitar para testes objetos que não são do tipo T, eu preciso antes de fazer o cast para testar, verificar c o candidato é do tipo T…
o Filter<T> é uma interface assim
public Filter<T> {
public boolean match(T candidate);
}
c eu não fizer o teste de isntanceof, antes de fazer o cast, da CastException (não lembro extamente o nome da exceção)
essa amarração é simplismente ridicula, ter q passar uma Class<T> para poder obter a classe do meu parametro T … totalmente sem sentido isso do java… tenho fé que exista uma forma menos burocrata de se fazer isso… não há sentido em ser obrigado a passar a classe junto, afinal de conta a definição do parametro T é justamente pra servir a esse proposito…
acho ridiculo ter q apelar pra conseguir a classe, ate sei como fazer, mais deveria ter 1 forma mais facil… a unica forma q encontrei segue abaixo… se alguem encontrar uma forma menos agreciva, eu agradeço
public <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
private T temp;
public boolean match(Object candidate) {
Class clazz = getClass().getFields()[0].getType();
return (clazz.isInstance(candidate)) ?
filter.match((T)candidate) : false;
}
};
}
Lavieri, acho que você não está entendendo. O tal T quando compilado não existe mais, você quer usar os genéricos pra uma coisa que eles não foram feitos. Por que candidate tem que ser Object, se quando ele não é T o método aborta? Por que não abortar já em tempo de compilação?
vc não ta entendendo… eu simplismente kero criar um outro método… e esse outro método precisa saber qual é a classe do Tipo T, pra poder usa-lo corretamente…
preciso disso, pra montar um filtro generico… kero converter um filtro de um objeto especifico, que é tipado, em um filtro generico, ou seja… um filtro aplicavel a coisas não tipadas, pra isso preciso fazer um teste de instanceOf…
é um filtro dentro do outro…
Filter por exemplo, so pesquisa cidades, e so aceita cidades em seu parametro…
posso kerer criar um filtro que contenha esse filtro por exemplo…
//aki eu recebo uma lsita que contem as pessoas do primeiro filtro, ou as cidades do segundo filtro
List<?> list = CollectionUtils.findAll(listaContendoDiversosObjetos, pessoaOuCidade); [/code]
isso é apenas 1 exemplo…
eu simplismente kero conseguir transformar um Filtro tipado, em um não tipado…, e para isso preciso conseguir testar isntanceof
[quote=Lavieri] public <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
private T temp;
public boolean match(Object candidate) {
Class clazz = getClass().getDeclaredFields()[0].getType();
return (clazz.isInstance(candidate)) ?
filter.match((T)candidate) : false;
}
};
}
[/quote]
Esse tipo de código não funciona. Ele roda porque candidate é instância de clazz, mas clazz é Object e não T! O compilador converte “T temp” em “Object temp” no bytecode gerado. Como uma instância candidate é sempre um Object, seu código mesmo rodando não faz o que você quer.
[quote=Lavieri] public static <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
try {
return filter.match((T)candidate);
} catch(ClassCastException ex) {
return false;
}
}
};
}
[/quote]Isso é o mesmo que isso: public static <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
return filter.match((T)candidate);
}
};
}Que provavelmente vai ser equivalente a isso: public static <T> Filter toGenericType(final Filter<T> filter) {
return filter;
}E isso com certeza não é o que você quer.
Fazer um cast para T não funciona, o compilador vai apagar o T e vai virar um cast para Object. Um cast para Object nunca lança ClassCastException.
Tenta assim: public static <T> Filter toGenericType(Class<T> classe, final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
try {
return filter.match(classe.cast(candidate));
} catch(ClassCastException ex) {
return false;
}
}
};
}Edit: Pergunta: Porque que o Filter retornado não é genérico e o recebido por parâmetro é? Será que você não deveria tentar usar Filter<?> ou Filter<Object>?
[quote=Lavieri]eu sei… eu vi que não funciona… o que funciona mesmo é um assim
public static <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
Class clazz = filter.getClass().getMethods()[0].getParameterTypes()[0];
System.out.println(clazz);
return (clazz.isInstance(candidate)) ?
filter.match((T)candidate) : false;
}
};
}
mesmo o T, daquele filter T sumindo… ele não vira um Object, ele se transforma na mesma classe do T passado…
eu ja testei e assim fucniona… porem depende do numero de métodos que o filter tem…
[/quote]Tenta assim:[code] public static Filter toGenericType(final Filter filter) {
return new Filter() {
public boolean match(Object candidate) {
Method m = achaMetodo(filter.getClass());
Class clazz = m.getParameterTypes()[0];
return (clazz.isInstance(candidate)) ?
filter.match((T) candidate) : false;
}
};
}
private static Method achaMetodo(Class<?> clazz) {
for (Method m : clazz.getMethods()) {
if (m.getName().equals("match")
&& !m.isSynthetic()
&& !m.isBridge()
&& m.getParameterTypes().length == 1
&& m.getReturnType() == boolean.class) {
return m;
}
}
throw new IllegalArgumentException(clazz.getName());
}
[quote=victorwss][quote=Lavieri] public static <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
try {
return filter.match((T)candidate);
} catch(ClassCastException ex) {
return false;
}
}
};
}
[/quote]Isso é o mesmo que isso: public static <T> Filter toGenericType(final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
return filter.match((T)candidate);
}
};
}Que provavelmente vai ser equivalente a isso: public static <T> Filter toGenericType(final Filter<T> filter) {
return filter;
}E isso com certeza não é o que você quer.
Fazer um cast para T não funciona, o compilador vai apagar o T e vai virar um cast para Object. Um cast para Object nunca lança ClassCastException.
Tenta assim: public static <T> Filter toGenericType(Class<T> classe, final Filter<T> filter) {
return new Filter() {
public boolean match(Object candidate) {
try {
return filter.match(classe.cast(candidate));
} catch(ClassCastException ex) {
return false;
}
}
};
}Edit: Pergunta: Porque que o Filter retornado não é genérico e o recebido por parâmetro é? Será que você não deveria tentar usar Filter<?> ou Filter<Object>?[/quote]
não é verdade Victorwsss … isso que eu fiz funciona, e resolve o problema, porem eu acho feio… e o cast para (T) gera sim uma ClassCastException
não há sentido em enviar a classe como parametro, ja que na tipologia do Filter<T> ja contem a classe, não vejo logica em ter q enviar juntamente a classe T …
so para demostrar o que falei
[code] public static void main(String[] args) {
Filter cidadeFilter = new Filter() {
public boolean match(Cidade candidate) {
return candidate.getNome().equals(“João Pessoa”);
}
};
//converte o cidadeFilter em um filtro generico
Filter genericFilter = FilterUtils.toGenericType(cidadeFilter);
String s = “teste q gera exceção”;
System.out.println(genericFilter.match(s)); //posso testar o match com qualquer objeto
[quote=Lavieri]não é verdade Victorwsss … isso que eu fiz funciona, e resolve o problema, porem eu acho feio… e o cast para (T) gera sim uma ClassCastException
não há sentido em enviar a classe como parametro, ja que na tipologia do Filter<T> ja contem a classe, não vejo logica em ter q enviar juntamente a classe T …
so para demostrar o que falei
[code] public static void main(String[] args) {
Filter cidadeFilter = new Filter() {
public boolean match(Cidade candidate) {
return candidate.getNome().equals(“João Pessoa”);
}
};
//converte o cidadeFilter em um filtro generico
Filter genericFilter = FilterUtils.toGenericType(cidadeFilter);
String s = “teste q gera exceção”;
System.out.println(genericFilter.match(s)); //posso testar o match com qualquer objeto
ou seja… quando não é possivel realizar o cast, ele retorna false imediatamente, como é impresso na linha abaixo
[/quote]
Na verdade esse ClassCastException não vem do cast para T. Vem dos métodos bridge sintéticos que o compilador cria para resolver os generics.
Seu compilador criou na classe anônima de cidade filter um método assim: public boolean match(Object candidate) {
return match((Cidade) candidate);
}Repetindo, o compilador cria esses métodos por conta. Se você lançar uma exceção dentro do método match(Cidade), verá que no stacktrace aparecerá duas vezes o método match.
De qualquer forma, veja a minha segunda resposta que eu dei.
[quote=victorwss]
Na verdade esse ClassCastException não vem do cast para T. Vem dos métodos bridge sintéticos que o compilador cria para resolver os generics.
Seu compilador criou na classe anônima de cidade filter um método assim: public boolean match(Object candidate) {
return match((Cidade) candidate);
}Repetindo, o compilador cria esses métodos por conta. Se você lançar uma exceção dentro do método match(Cidade), verá que no stacktrace aparecerá duas vezes o método match.
De qualquer forma, veja a minha segunda resposta que eu dei.[/quote]
ora… e o que vc disse é exatamente o que eu disse… a intenção era essa… que T, se tranforme na classe tipada, no caso especifico Cidade…
ou seja… vc falar
public boolean match(Object candidate) {
return match((Cidade) candidate);
}
e falar
public boolean match(Object candidate) {
return match((T) candidate); //onde T é Cidade
}
da no mesmo ora… como disse… o cast para o tipo T, que no caso que exemplifiquei é Cidade, gera sim um ClassCastException… e a intenção era essa…
e o método criado pela classe anonima que o compilador gera é na verdade assim
a minha vontade era que fosse com isntanceof, mais por algum motivo bizarro o compilador não deixa fazer, não há sentido em não deixar, mais não deixa =/
era pra ser assim:
public boolean match(Object candidate) {
if (candidate instanceof Cidade))
return false;
return filter.match((Cidade) candidate);
}
So não entendo qual o motivo do compilador não deixar fazer instanceof com tipologia…
Você não entendeu o que eu disse. Esse é o seu código:[code]public static void main(String[] args) {
Filter cidadeFilter = new Filter() {
public boolean match(Cidade candidate) {
return candidate.getNome().equals(“João Pessoa”);
}
};
//converte o cidadeFilter em um filtro generico
Filter genericFilter = FilterUtils.toGenericType(cidadeFilter);
String s = “teste q gera exceção”;
System.out.println(genericFilter.match(s)); //posso testar o match com qualquer objeto
//isso abaixo obviamente não compilaria.
//cidadeFilter.match(s);
}
public static Filter toGenericType(final Filter filter) {
return new Filter() {
public boolean match(Object candidate) {
try {
return filter.match((T)candidate);
} catch(ClassCastException ex) {
System.out.println(“o cast (T) gerou exceção”);
return false;
}
}
};
}[/code]O compilador apaga os generics na compilação. Eles somem, desaparecem. O compilador transforma o seu código nisso:[code]public static void main(String[] args) {
Filter cidadeFilter = new Filter() {
// Esse método é colocado pelo compilador!
public boolean match(Object candidate) {
return match((Cidade) candidate); // É esse o cast que te dá o ClassCastException!
}
public boolean match(Cidade candidate) {
return candidate.getNome().equals("João Pessoa");
}
};
//converte o cidadeFilter em um filtro generico
Filter genericFilter = FilterUtils.toGenericType(cidadeFilter);
String s = "teste q gera exceção";
System.out.println(genericFilter.match(s)); //posso testar o match com qualquer objeto
//isso abaixo obviamente não compilaria.
//cidadeFilter.match(s);
}
public static Filter toGenericType(final Filter filter) {
return new Filter() {
public boolean match(Object candidate) {
try {
return filter.match((Object)candidate); // Não vai ser esse cast que vai dar ClassCastException!
} catch(ClassCastException ex) {
System.out.println(“o cast (T) gerou exceção”);
return false;
}
}
};
} [/code]
Os generics são apagados pelo compilador. Eles não estão no bytecode, logo, a máquina virtual não os vê e nem sabe que eles existem. Logo, não tem como ela fazer um instanceof durante a execução.
Apenas algumas poucas informações de assinatura de métodos e de classes ficam no bytecode para serem lidas via reflection apenas, de resto, é como se não existissem.
Observe que o compilador, ao criar os métodos sintéticos, para resolver o reflection, vai sobrecarregar alguns dos teus métodos. Por isso que getMethods[0] nem sempre trás o método correto. A solução para isso é procurar o método correto olhando para outros detalhes da sua assinatura, tal como no segundo exemplo que eu te mostrei.
Que o compilador some com o T, eu sei… so que da mesma forma que ele subistitui os T por Cidade e cria os métodos correspondentes…
ele poderia subistituir
candidate instanceof T
por
candidate instanceof Cidade
é tão simples substituir isso quando subistituir no resto, não entendo a dificuldade real de fazer isso… mais enfim… paciencia…
e de toda forma… eu vi que realmente o erro de cast é dentro do filter… fiz o seguinte e comprovei…
[code] Filter cidadeFilter = new Filter() {
public boolean match(Cidade candidate) {
return candidate.getNome().equals(“João Pessoa”);
}
//criando esse método abaixo, não da ClassCastException
public boolean match(Object o) {
System.out.println("Não da classCastException");
return false;
}
}; [/code]
public class FilterUtils_Sugestao {
static class Cidade {
public String getNome() {
return "João Pessoa";
}
}
interface Filter<T> {
public boolean match(T o);
public Class<? extends T> targetClass(); // Implementações são obrigadas a dizer que tipo de coisa elas filtram
}
public static <T> Filter<Object> toGenericType(final Filter<T> filter) {
return new Filter<Object>() {
public boolean match(Object candidate) {
// A implementação me dirá a classe com a qual o filtro trabalha
return filter.targetClass().isInstance(candidate)?
filter.match((T) candidate) : false;
}
public Class<? extends Object> targetClass() {
return Object.class;
}
};
}
public static void main(String[] args) {
Filter<Cidade> cidadeFilter = new Filter<Cidade>() {
public boolean match(Cidade candidate) {
return candidate.getNome().equals("João Pessoa");
}
public Class<? extends Cidade> targetClass() {
return Cidade.class; // Sou um filtro de Cidade
}
};
Filter<Object> genericFilter = FilterUtils_Sugestao.toGenericType(cidadeFilter);
System.out.println(genericFilter.match("teste"));
System.out.println(genericFilter.match(new Cidade()));
}
}
Realmente cara, dá uma lida sobre Generics, aí tu vai entender como instanceof T não tem lógica. Depois você pode até continuar insatisfeito, mas pelo motivo certo (não vou te dizer, vou deixar pra você concluir).