Tipologia <T> como fazer isntanceof T

agora me deparei com uma duvida… como saber c um Object é do tipo de uma classe T…

por exemplo…

[code]public class Teste {

public boolean teste(Object obj) [
    if (!(obj instanceof T))
       return false;
    else
       // ....
}

}[/code]

este teste não funciona… não posso usar instanceof T … tem q por uma classe la… so que eu não tenho essa classe no meu objeto Teste<T>…

como fazer ? esse teste ?? tem como ?

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)

Você precisa arrumar alguma forma de passar um objeto do tipo Class<T>, seja no construtor ou como parâmetro do método toGenericType() mesmo.

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…

Filter<Cidade> filterCidade; Filter<Pessoa> filterPessoa; Filter<?> pessoaOuCidade = FilterUtils.or(filterCidade,filterPessoa);

agora eu tenho uma lsita assim

[code]List<?> listaContendoDiversosObjetos;

//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

Não dá pra descobrir se um objeto é do tipo T porque quando o código rodar, T terá sido removido pelo compilador no bytecode gerado.

http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html

[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.

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…

to vendo que vou acabar fazendo a versão mais feia =/ …

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=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());
}

[/code]

[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

    //isso abaixo obviamente não compilaria.
    //cidadeFilter.match(s);
}

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) {
                System.out.println("o cast (T) gerou exceção");
                return false;
            }
        }
    };
}[/code]

a resposta do console é

o cast (T) gerou exceção false

ou seja… quando não é possivel realizar o cast, ele retorna false imediatamente, como é impresso na linha abaixo

[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

    //isso abaixo obviamente não compilaria.
    //cidadeFilter.match(s);
}

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) {
                System.out.println("o cast (T) gerou exceção");
                return false;
            }
        }
    };
}[/code]

a resposta do console é

o cast (T) gerou exceção false

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

public boolean match(Object candidate) { try { return filter.match((Cidade) candidate); } catch (ClassCastException ex) { return false; } }

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]

[quote=Lavieri]candidate instanceof Cidade

é tão simples substituir isso quando subistituir no resto, não entendo a dificuldade real de fazer isso… mais enfim… paciencia…[/quote]

É simples mas não tem lógica alguma. Raciocina…

Que tal isso aqui:


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()));	
	}

}

eu acho triste, ter que informar a classe quando há tipologia…

hora, a tipologia devia vim para facilitar esse trabalho, ter q informar a classe em 2 lugares acho algo triste =/

mas talvez seja obrigado a fazer isso =/

Eu acho triste você querer coisas sem sentido.

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).