Java reflection e depois?

10 respostas
B

Buenas,

Seguinte estou tendo problema com reflection do tipo vector:

Field portas = loaded.getDeclaredField("listeners");
               
 portas.setAccessible(true);
 Vector[] a= new Vector[100] ;
            
 System.out.println(portas.isAccessible());
 System.out.println(portas.getClass());
               
 portas.set(loaded, a);

bom ai é o seguinte, ele retorna:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:57)

ótimo, agora alguem tem uma solućão ou ideia?

thanks!!!

10 Respostas

renzonuccitelli

Esse tópico deve te ajudar. Vc tem que ter um objeto do mesmo tipo do atributo para usar como alvo…

B

ótimo!!! isso funciona sim!!!

Mas o meu problema é outro, não quero pegar o valor de um campo e sim colocar novos valores, que no meu caso seria zerar o vetor!!!

Ou seja, eu tenho um vetor e preciso passar outro vetor zerado pra zerar ele, tem algum outro metodo??? consigo utilizar o metodo removeAll() da classe vector via reflection???

Alguem entendeu o que quero fazer???

HELPPPPPPPPPPPPPPPPPPPPPPPPPP!!!

renzonuccitelli

Não sei o contexto que vc está querendo fazer isso, cuidado com o uso da API Reflection pq ela degrada o desempenho. Pq vc simplesmente nao cria um método para zerar o vetor e chama esse método de maneira usual?

renzonuccitelli

Vai um exemplo para clarificar:

public class Blah {
	private List<String> listaTeste=new ArrayList<String>();

	public Blah() {
		super();
		listaTeste.add("string do construtor");
	}

	public void imprimirLista(){
		System.out.println(listaTeste);
	}

	public static void  alterarAtributoViaReflection(Blah blah){
		try {
			Field campoListaTeste=Blah.class.getDeclaredField("listaTeste");
			campoListaTeste.setAccessible(true);
			List<String> lista=new ArrayList<String>();
			lista.add("lista alterada via reflection");
			campoListaTeste.set(blah,lista);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static void main(String[] a){
		Blah blah=new Blah();
		blah.imprimirLista();
		Blah.alterarAtributoViaReflection(blah);
		blah.imprimirLista();
	}
}

Mas como eu disse, já que vc vai ter que informar a instancia que vc deseja alterar, seria bem mais fácil vc procer na própria classe um método que alterasse seu vetor. Para te esclarecer melhor quando o uso de reflection é uma boa, de uma olhada no artigo: "Reflexão + Anotações, uma combinação explosiva" presente na Mundo Java número 19.

B

Acho que tem alguns pontos que preciso deixar claro neste topico.

Seguinte o valor que quero alterar, é de uma biblioteca que não tenho o codigo fonte, por isso tal dificildade, mas creio que seja possivel fazer isso.

É o seguinte tenho uma classe ClassedoReflection (este eu não tenho o codigo, sei os campos mas não consigo alterar o codigo dela), e tenho a ClassequeChamaOReflection (esta eu estou escrevendo).

Bem na ClassedoReflection tenho um campo do tipo: Vector (talvez o problema esteja em não saber vetor do que é), pois bem, esta faz parte de um driver da Serial no caso javacomm, que possui o elemento listeners (protegido).

Toda vez que faćo reflection pra carregar a porta USB-serial, que por sua vez nunca sei qdo estará conectada. ele sobrecarrega o vetor de portas, ou seja, guarda o ele ja tinha e mais o que ele achou, com isso vai aumentando o tamanho do vetor, e com portas repetidas.

O que eu quero fazer é alterar o valor deste objeto em tempo de execucao, ou seja, cria um limpa vetor pra ele.

vai ter como eu fazer isso?

tem como eu chamar um metodo de um objeto instanciado, ou sei la eu como limpar isso…

B

Acho que tem alguns pontos que preciso deixar claro neste topico.

Seguinte o valor que quero alterar, é de uma biblioteca que não tenho o codigo fonte, por isso tal dificildade, mas creio que seja possivel fazer isso.

É o seguinte tenho uma classe ClassedoReflection (este eu não tenho o codigo, sei os campos mas não consigo alterar o codigo dela), e tenho a ClassequeChamaOReflection (esta eu estou escrevendo).

Bem na ClassedoReflection tenho um campo do tipo: Vector (talvez o problema esteja em não saber vetor do que é), pois bem, esta faz parte de um driver da Serial no caso javacomm, que possui o elemento listeners (protegido).

Toda vez que faćo reflection pra carregar a porta USB-serial, que por sua vez nunca sei qdo estará conectada. ele sobrecarrega o vetor de portas, ou seja, guarda o ele ja tinha e mais o que ele achou, com isso vai aumentando o tamanho do vetor, e com portas repetidas.

O que eu quero fazer é alterar o valor deste objeto em tempo de execucao, ou seja, cria um limpa vetor pra ele.

vai ter como eu fazer isso?

tem como eu chamar um metodo de um objeto instanciado, ou sei la eu como limpar isso…

T

Acho que entendi mais ou menos o que você quer. Vou dar um exemplo.

import java.util.*;
import java.lang.reflect.*;

class Porta {
    public Porta(final int p_) {p = p_;}
    private int p;
    public String toString() { return "[p=" + p + "]"; }
}

class ClasseComMembroPrivado {
    private Vector portas; // este é o fulano que queremos limpar
    public ClasseComMembroPrivado () {
        portas = new Vector();
    }
    public void addPorta (Porta porta) {
        portas.add (porta);
    }
    public String listPortas () { return portas.toString(); }
}

class TesteAcessandoMembroPrivado {
    public static void limpaPortas (ClasseComMembroPrivado c) throws Exception {
        Field fldPortas = c.getClass().getDeclaredField ("portas");
        fldPortas.setAccessible (true); // embora seja um campo privado...
        Vector v = (Vector) fldPortas.get (c);
        v.clear();
    }
    public static void main(String[] args) throws Exception {
        ClasseComMembroPrivado c = new ClasseComMembroPrivado();
        c.addPorta (new Porta (1));
        c.addPorta (new Porta (2));
        c.addPorta (new Porta (3));
        c.addPorta (new Porta (4));
        System.out.println (c.listPortas());
        limpaPortas (c);
        System.out.println (c.listPortas());
    }   
}

A saída deve ser:

[[p=1], [p=2], [p=3], [p=4]]
[]
B

Vamos a meu codigo!!!

try{
             
               String class_path = System.getProperty("java.ext.dirs") + System.getProperty("file.separator") + "comm.jar";
               System.out.println(class_path);
               URL class_path_url  = new File(class_path).toURL();	   
               URLClassLoader tempLoader = new URLClassLoader(new URL[]{class_path_url}); //create a new URLClassLoader
               Method findClass_Method = URLClassLoader.class.getDeclaredMethod("findClass", new Class[]{String.class}); //get the method findClass(String name)
               findClass_Method.setAccessible(true);
               Class loaded = (Class) findClass_Method.invoke(tempLoader, new Object[]{"javax.comm.CommPortIdentifier"} ); //call it as if it was the member method of a new URLClassLoader object. If this call succeeds, it should return the Class object for the class. 	        
               
               // pra tentar zerar o vetor
               Field portas = loaded.getDeclaredField("listeners");
               
               portas.setAccessible(true);
               
               Vector<Object> a = new Vector<Object>();
               
               System.out.println(portas.getGenericType());
               System.out.println(portas.isAccessible());
               System.out.println(portas.getType());
               
               portas.set(loaded, a);     
           
           } 
         
         catch (NoSuchMethodException x) {
	    x.printStackTrace();
	}
        catch (InvocationTargetException x) {
	    x.printStackTrace();
	} 
        catch (NoSuchFieldException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (IOException x) {
	    x.printStackTrace();
	} catch (SecurityException x){
            x.printStackTrace();
        }

este codigo me devolve a seguinte exception:

class java.util.Vector true class java.util.Vector Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:57) at java.lang.reflect.Field.set(Field.java:656) at pncaCom.SerialCom.enumeratePorts(SerialCom.java:163) at pncaCom.SerialCom.ListarPortas(SerialCom.java:40) at pncaCom.SerialCom.(SerialCom.java:20) at pncaCom.SComm.(SComm.java:49) at pncaRobo.Robo.(Robo.java:30) at legal2008.ControlarDispositivos.(ControlarDispositivos.java:24) at legal2008.principal.btControlarDispositivosMouseClicked(principal.java:234) at legal2008.principal.access$1000(principal.java:16) at legal2008.principal$5.mouseClicked(principal.java:123) at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:212) at java.awt.Component.processMouseEvent(Component.java:5520) at javax.swing.JComponent.processMouseEvent(JComponent.java:3135) at java.awt.Component.processEvent(Component.java:5282) at java.awt.Container.processEvent(Container.java:1966) at java.awt.Component.dispatchEventImpl(Component.java:3984) at java.awt.Container.dispatchEventImpl(Container.java:2024) at java.awt.Component.dispatchEvent(Component.java:3819) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3901) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822) at java.awt.Container.dispatchEventImpl(Container.java:2010) at java.awt.Window.dispatchEventImpl(Window.java:1791) at java.awt.Component.dispatchEvent(Component.java:3819) at java.awt.EventQueue.dispatchEvent(EventQueue.java:463) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149) at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

certo???

bom agora talvez seja o tipo que esta com problemas... pois o campo (field) que quero manipular foi encontrado, mas a linha em vermelho que crio o tipo vetor, que não consigo saber como q eh na biblioteca, ela da pau, na hora do set... linha em azul

ja tentei trocar por:

Vector a = new Vector();

e outras formas, mas não funcionou e retorna o mesmo exception...

tem como eu saber exatamente como um campo ta declarado numa classe, o tipo dela eu pego, se reparar no codigo e na saiba onde aparece java.util.Vector

a ideia é pegar um vetor vazio e colocar no lugar do cheio, mas o cheio ta longe pra ser alcanćado na boa!!!

valews ateh agora

71C4700
bodninja, vc ta fazendo assim
Field portas = loaded.getDeclaredField("listeners");  
                  
              portas.setAccessible(true);  
                 
            Vector<Object> a = new Vector<Object>();  
                  
             System.out.println(portas.getGenericType());  
              System.out.println(portas.isAccessible());  
             System.out.println(portas.getType());  
                  
               portas.set(loaded, a);

Tenta ao inves disso, fazer assim:

Blha blha = new Blah();// Pense que vc sabe quem seja este objeto, certo?!
// Repita seu algoritmo.. até
portas.set(blha, a);  // Voce atribui o valor deste field(postras), do objeto instanciado (blha) o valor(a)

Não sei ao certo, mas se nao me engano o field só seria atribuido aquele valor, caso fosse pra algum Objeto..

Marky.Vasconcelos

Então…

o método set da classe Field recebe uma instancia da classe que tem o Field que voce quer mudar e um Objeto que sera o valor

portas.set(loaded, a);

Com esse código voce esta passando um objeto Class, talvez a sua idéia é mudar direto no Class e todos os objetos virem modificados, mas isso é impossivel no Java já que não temos acesso as Classes desse modo em Runtime.
Mas para mudar apenas do objeto voce tem que passar uma instancia dele.

CommPortIdentifier cm = //incializa ele
portas.set(cm, a);
Criado 1 de dezembro de 2008
Ultima resposta 8 de dez. de 2008
Respostas 10
Participantes 5