Mirror DSL 1.2

49 respostas
J

A equipe de desenvolvimento do projeto Mirror está muito orgulhosa em anunciar o primeiro release publico do projeto.

Mirror é uma simples camada sobre a Java Reflection API para torná-la mais simples de utilizar.

Da versão 1.0 até este ponto a DSL estava sofrendo muitas mudanças, por isso decidimos não publicá-la.

O site oficial é http://projetos.vidageek.net/mirror/ (em inglês).

Críticas e sugestões são muito bem vindas.

Equipe de Desenvolvimento do Mirror.

49 Respostas

F

Parabéns pelo projeto; sensacional!

Não acompanhei o desenvolvimento, mas como trabalho com toda a equipe aqui na Caelum, conheço o trabalho de todos: Jonas Abreu, Adriano Almeida e Diego Feitosa.

Desta equipe excelente só poderia sair algo assim bem legal!

F

hAHhahaha curti o “You don’t even know it’s a tutorial” Tutorial.

Putz mão na roda…

Parabéns pelo projeto

M

Cool
Isso apareceu em boa hora.
Estou desenvolvendo um mini framework de persistencia que preciso de reflection. fiz umas classes meia boca.

Isso vai me servir muito bem.

Valew

Edit:
Onde posso postar sugestões?
Ja tenho uma lista de coisas que seriam uteis.

D

Muito bom. A flexibilidade do código certamente é maior do que o código procedural, além de mais simples de usar do que a própria API de Reflection nua e crua.

No entanto, esse ‘syntatic sugar’ torna-se mais verboso. Cabe ai a analisar os trade-offs e ver se vale mesmo a pena entrar no purismo do OO ou simplesmente criar um código procedual totalmente straight forward (direto/objetivo).

M

Aproveitando o assunto, gostaria de tirar uma dúvida, é uma dificuldade que tambem tenho na API de Reflection.

Tem como chamar o metodo liga da classe carro sem ter que instancia o obj carro dentro da classe teste, poderia até instaciar mas pegando esse carro por uma variavel String?
Carro obj = new Carro();

Gostaria de passar esse “Carro” atravez de uma variavel String como paramentro de um metodo…

Teste

import net.vidageek.mirror.Mirror;

public class Teste {

	public static void main(String[] args) {
		
		Carro obj = new Carro();
		Mirror.on(obj).invoke().method("liga").withoutArgs();
			
	}

}

Carro

public class Carro {

	public void liga() {
		System.out.println("Ligado");
	}

}
M

No caso que você passou agora, nem faz sentido fazer isso. A menos talvez que você queria invocar um metodo estatico

Se voce quer invocar um metodo estatico, no reflection mesmo voce usa algo como:

Method seno = Math.class.getMethod(“sin”);
seno.invoke(null,new Double(1.123));

D

Tem sim:

M

Algum motivo especial pra invoke() e set() não poderem receber direto o nome do método/campo?

M

Tem sim:

Valew Daniel! Resolveu, era isso mesmo que eu precisava.

Mikhas, esse exemplo é um material de estudo, não faz sentido mesmo mas é o que encontrei pra tentar explicar minha dúvida.
Não conhecia esse “newInstance();”. Valew.

J

Olá Maniezo,

com o Mirror, o código ficaria mais ou menos assim:

Object carro = Mirror.on(“pacote.Carro”).invoke().constructor().withoutArgs();
Mirror.on(carro).invoke().method(“liga”).withoutArgs();

Mauricio,

o invoke() não recebe direto o nome porque ele pode ser usado para instanciar um objeto (como no exemplo acima) e o set() para manter o padrão.

Até!

M

jonasabreu:
Olá Maniezo,

com o Mirror, o código ficaria mais ou menos assim:

Object carro = Mirror.on(“pacote.Carro”).invoke().constructor().withoutArgs();
Mirror.on(carro).invoke().method(“liga”).withoutArgs();

Mauricio,

o invoke() não recebe direto o nome porque ele pode ser usado para instanciar um objeto (como no exemplo acima) e o set() para manter o padrão.

Até!

Bacana, valew!

M

Opa Jonas,

O código fonte tá aonde?

D

Então o “invoke()” e o “set()” não poderiam ser abolidos?

J

Olá Mauricio,

por um erro acabei esquecendo de colocar no site (vou corrigir isso o mais rápido possível).

O source está em http://svn.vidageek.net/mirror .

Até!

M

Eu acho que um invoke e set que já recebem o campo/método como parâmetro são o ideal. No caso de construtor eu acho que seria mais simples ter um método “create” que já receberia os parâmetros do contrutor.

J

Um dos focos era deixar o código bem legível (por isso uma DSL). Portanto, abolindo os dois ficaria bem menos legivel.

Até!

D

Quase um pseudo-código… hehehehe… Só não vamos falar de mnemônicos… kkkkk

M

Repetindo a pergunta, onde está o código fonte?

E eu tinha pensado em algo assim:

Object o = Mirror.on("some.Class").create( "A String" );
Mirror.on(o).invoke( "aMethod" ).with( 13);
Mirror.on(o).get("color");

Acho bem mais intuitivo e menos burocrático :slight_smile:

J

jonasabreu:
Olá Mauricio,

por um erro acabei esquecendo de colocar no site (vou corrigir isso o mais rápido possível).

O source está em http://svn.vidageek.net/mirror .

Até!

F

parabéns pelo projeto. a api de reflection ficou mais simples e em poucas linhas você já faz muita coisa.

o tal do invokeMethod é muito chato ter que verificar e tratar exceções e ficou bem mais interessante.
está lembrando algumas características do smalltalk. só não lembro agora o nome desta característica, vários métodos aninhados.

E

A título de conhecimento, existe uma API com proposta se não idêntica, muito parecida, fest-reflect. Parabéns pela iniciativa.

T

Mauricio Linhares:
Repetindo a pergunta, onde está o código fonte?

E eu tinha pensado em algo assim:

Object o = Mirror.on("some.Class").create( "A String" );
Mirror.on(o).invoke( "aMethod" ).with( 13);
Mirror.on(o).get("color");

Acho bem mais intuitivo e menos burocrático :)

Deixe-me aproveitar o gancho e dar uma sugestão ao projeto. Que tal criar junto a documentação do site uma sugestão de como se criar um ‘Wrapper’ para o Mirror, possibilitando que cada projeto possa elaborar/customizar a gramática que será usada?

Ou seja, a Mirror continua como está (que está bem legal), e ensina para seus usuários um jeito fácil de criar sua própria sintaxe usando uma classe que encapsule o Mirror.

Não sei se seria fácil, mas acho que seria bem legal :wink:

T

Outra sugestão,

não sei se na opinião de vocês isso se enquadraria no perfil do Projeto Mirror. Mas algo que tem sido dificil de encontrar por aí de forma simples é uma forma fácil de se fazer uma busca por classes que atendam algum determinado critério no classpath.

Por exemplo: imaginem que quero encontrar todas as classes que possuam uma annotation do tipo @Entity e configurá-lo no hibernate.

@Override
protected void configureHibernate(AnnotationConfiguration config) {
	super.configureHibernate(config);

	List l = Mirror.onClasspath().findAll(javax.persistence.Entity.class);
	
	for (...) { // iterar em l
		Object o = l.next();
		config.addAnnotatedClass(o);
	}
}

Como já disse, não sei se este tipo de recurso estaria no escopo do projeto de vocês. Mas fica aqui a sugestão ;)
Caso gostarem da idéia, um ótimo ponto inicial para começar é estudar a seguinte classe do Spring: ClassPathScanningCandidateComponentProvider

Valeu!

F

Ótima idéia. Gostei!
Talvez algo usando os Matchers do hamcrest (que o JMock usa), para criar alguma forma de customizar a DSL interna.

Outra ótima idéia! Acho que esse seria mais simples. Bastaria integrar com algo como o http://scannotation.sourceforge.net/

T

Eu não conhecia o Hamcrest e o Scannotation. Valeu pela dica, Kung.

B

Achei bem interessante o projeto, mas se entendi bem o conceito de DSL, como não existe schema definido para representação abstrata da linguagem, ela não pode ser considerada uma DSL, seria por enquanto apenas uma classe de utilidades.

P

boaglio:

Achei bem interessante o projeto, mas se entendi bem o conceito de DSL, como não existe schema definido para representação abstrata da linguagem, ela não pode ser considerada uma DSL, seria por enquanto apenas uma classe de utilidades.

creio que nao. quando a dsl é interna, estamos limitados pela sintaxe da propria linguagem (que ja possui uma sintaxe formalizada), fazendo a interseccao dela com a API exposta.

repare que o exemplo do fowler, a time and money API, nao define schema nenhum, e “segue as linhas de uma DSL”, nas proprias palavras do Fowler:

R

Paulo Silveira:

creio que nao. quando a dsl é interna, estamos limitados pela sintaxe da propria linguagem (que ja possui uma sintaxe formalizada), fazendo a interseccao dela com a API exposta.

repare que o exemplo do fowler, a time and money API, nao define schema nenhum, e “segue as linhas de uma DSL”, nas proprias palavras do Fowler:
http://martinfowler.com/bliki/FluentInterface.html

Legal! Isto já responde o comentário/dúvida que deixei no post http://blog.caelum.com.br/2008/11/17/mirror-dsl-facilitando-o-uso-da-api-de-reflection/

Sucesso!

C

boaglio:

Achei bem interessante o projeto, mas se entendi bem o conceito de DSL, como não existe schema definido para representação abstrata da linguagem, ela não pode ser considerada uma DSL, seria por enquanto apenas uma classe de utilidades.

Qual trecho do artigo afirma isso?

B

Faça uma busca pela palavra “schema” que vc encontra o trecho.

Sinceramente ainda não está claro pra mim a diferença de uma DSL interna para uma classe de utilidades que usa Method Chaining.

J

No caso específico do Mirror, foi usado Method Chaining para criar a DSL. O objetivo da DSL é manter uma “linguagem” dentro do domínio (no caso, reflection).

O method chaining é apenas encadear diversos métodos de forma a facilitar o código, mas não existe nenhum compromisso em se construir uma linguagem.

@Mauricio,
Sobre a sua sugestão de mudança da libguagem, ela está sendo discutida na lista de desenvolvimento (http://lista.vidageek.net/listinfo.cgi/mirror-dev-vidageek.net) e acredito que vire um feature request para a próxima versão.

@Ednelson,
Não conhecia esta API. Vou dar uma olhada nela. Obrigado!

@Thiago Senna
Isso é uma funcionalidade (Classpath LookUp) que eu gostaria muito que existisse, mas não sei se entra no escopo do projeto.

@Kung
Usando o Hacrest, a DSL teria que ser completamente alterada por causa da forma como ele trabalha (não daria pra usar method chaining).
Ou usaria diversos imports estáticos (ruim porque pelo menos o eclipse não faz eles direito) ou usaria classes anonimas (como o JMock). Mas vale pensar sobre isso.

Obrigado a todos pelo feedback!

O

Alguem ai, poderia me dizer, para quem já utilizou esse framework, como pegar o nome do método, os seus parâmetros, e valores dos parâmetros em runtime?
abraços.

F

OCESN:
Alguem ai, poderia me dizer, para quem já utilizou esse framework, como pegar o nome do método, os seus parâmetros, e valores dos parâmetros em runtime?
abraços.

Cara vc entrou no site pelo menos?

http://projetos.vidageek.net/mirror/method/reflecting/

M

jonasabreu:
@Mauricio,
Sobre a sua sugestão de mudança da libguagem, ela está sendo discutida na lista de desenvolvimento (http://lista.vidageek.net/listinfo.cgi/mirror-dev-vidageek.net) e acredito que vire um feature request para a próxima versão.

Opa Jonas,

Vou fazer umas alterações aqui e mandar pra vocês darem uma olhada :slight_smile:

Outra coisa, peloamordedeus, lista no googlegroups velho, listinfo é uma tristeza :smiley:

O

Foxlol:
Cara vc entrou no site pelo menos?

http://projetos.vidageek.net/mirror/method/reflecting/

Claro que sim, o problema é pegar os seus parâmetros e valores, sem saber quais parâmetros, apenas com o nome no método.
Tipo…

public class Teste1 {

	public void executa(String arg1){
		TempoProcessamento tempo = new TempoProcessamento();
		
		//blablabla.
		
		tempo.finaliza(this);
	}
}
class TempoProcessamento{
	private long inicio = 0L;
	private long termino = 0L;
	
	public TempoProcessamento(){
		inicio = System.currentTimeMillis();
	}
	
	public void finaliza(Object classe){
		termino = System.currentTimeMillis();
		System.out.println("Classe: " +classe.getClass().getName());
		System.out.println("Método: " +Thread.currentThread().getStackTrace()[2].getMethodName());
		
 //O problema??
		//Pegar os argumentos, e os seus valores em RunTime.
		//Lista de argumentos com os sesus respectivos valores...
		//for
		String param1 = "java.lang.String";
		String value1 = "Teste OCESN";
		System.out.println("Parâmetro: "+ param1 +"Valor: "+ value1);
		//End for
		
		System.out.println("Total: " + (termino-inicio));
	}
}

ah, e para o exemplo do site deles…
Method m = Mirror.on(clazz).reflect().method().withArgs(String.class, Object.class);
ao chamar o .method(), não aceita sem passar o nome de algum método.

abraços.

F

OCESN:
Foxlol:
Cara vc entrou no site pelo menos?

http://projetos.vidageek.net/mirror/method/reflecting/

Claro que sim, o problema é pegar os seus parâmetros e valores, sem saber quais parâmetros, apenas com o nome no método.
Tipo…

public class Teste1 {

	public void executa(String arg1){
		TempoProcessamento tempo = new TempoProcessamento();
		
		//blablabla.
		
		tempo.finaliza(this);
	}
}
class TempoProcessamento{
	private long inicio = 0L;
	private long termino = 0L;
	
	public TempoProcessamento(){
		inicio = System.currentTimeMillis();
	}
	
	public void finaliza(Object classe){
		termino = System.currentTimeMillis();
		System.out.println("Classe: " +classe.getClass().getName());
		System.out.println("Método: " +Thread.currentThread().getStackTrace()[2].getMethodName());
		
 //O problema??
		//Pegar os argumentos, e os seus valores em RunTime.
		//Lista de argumentos com os sesus respectivos valores...
		//for
		String param1 = "java.lang.String";
		String value1 = "Teste OCESN";
		System.out.println("Parâmetro: "+ param1 +"Valor: "+ value1);
		//End for
		
		System.out.println("Total: " + (termino-inicio));
	}
}

ah, e para o exemplo do site deles…
Method m = Mirror.on(clazz).reflect().method().withArgs(String.class, Object.class);
ao chamar o .method(), não aceita sem passar o nome de algum método.

abraços.

Class clazz;
Method m = Mirror.on(clazz).reflect().method("methodName");

O código acima não te retorna um Method baseado em um nome de um método?
E com este Method você não tem as informações que vc precisa?

http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html

[]'s

O

Cara tem não.
Consegui pegar só os paransTypes…
agora o nome do parâmetro, e os seus valores que foram setados na chamada do método, não estou conseguindo.
ah… mas uma vez…

Class clazz;  
Method m = Mirror.on(clazz).reflect().method("methodName");

o método retorna um objeto do tipo MethodReflector e não um do tipo Method.
E tipo… você está com uma versão diferente do Mirror, pois os códigos que você está inserindo aqui, nenhum está batendo com a versão que estou utilizando… 1.2/ 15-Nov-2008 17:38 - , ou não está testando os códigos.
abraços.

F

OCESN:
Cara tem não.
Consegui pegar só os paransTypes…
agora o nome do parâmetro, e os seus valores que foram setados na chamada do método, não estou conseguindo.
ah… mas uma vez…

Class clazz;  
Method m = Mirror.on(clazz).reflect().method("methodName");

o método retorna um objeto do tipo MethodReflector e não um do tipo Method.
E tipo… você está com uma versão diferente do Mirror, pois os códigos que você está inserindo aqui, nenhum está batendo com a versão que estou utilizando… 1.2/ 15-Nov-2008 17:38 - , ou não está testando os códigos.
abraços.

Cara os codigos são da propria pagina do projeto.
Não to criando nada…muito menos testando…são todos exemplos do proprio site.

http://projetos.vidageek.net/mirror/mirror/

EDITADO:

Baixei o jar aqui e realmente os exemplos do site não estão batendo com a versão 1.2.

Testou com alguma versão anterior?

Flw

F

Fiz uns teste aqui.

Será que isso resolve?

Class classe = null;  
List<Method> listaMetodos = Mirror.on(classe).reflectAll().methods();
String nomeMetodo = "teste";
        
for (Method metodo : listaMetodos) {
   if (nomeMetodo.equals(metodo.getName())) {
      //Do stuff
   }
}

Ai sim ele retorna objetos do tipo Method.

Se tiver outra maneira alguem posta ai.

Flw

O

afff

Baixei o jar aqui e realmente os exemplos do site não estão batendo com a versão 1.2.

como que pode... realmente achei estranho mesmo... os exemplos não baterem com o que está no src. E realmente não estão, testei vários outros.

..... Não testei em outras versões. Mas isso ai...
Class classe = null;  
List&lt;Method&gt; listaMetodos = Mirror.on(classe).reflectAll().methods();
String nomeMetodo = "teste";
        
for (Method metodo : listaMetodos) {
   if (nomeMetodo.equals(metodo.getName())) {
      //Do stuff
   }
}
resolveu em partes... pois ainda não consegui pegar os nomes dos argumentos e os valores deles. Já engoli a API Reflect e não achei... [url]http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html[/url] Mas desde já agradeço a atenção. abraços.
F

É verdade cara…muito estranho…to testando aqui e não consigo pegar o nome do parâmetro por nada.

Achei isso aqui enquanto procurava alguma solução: http://paranamer.codehaus.org/

Vê se funciona…abraços.

J

@OCESN,

existe um erro na documentação.

Para refletir um método, o correto seria Mirror.on(clazz).reflect().method("methodName).withoutArgs();

Faltou a última chamada, pois você só consegue garantir a unicidade de um método se tiver o nome e os parâmetros.

Vou criar um issue pra corrigir isso.

Quanto ao nome dos parâmetros, eles não existem em tempo de execução. Você tem como recuperar os tipos dos parâmetros, mas não o nome (a não ser que você use o paranamer e compile em modo de debug, se não me engano).

E para pegar os valores que foram passados para o método, apenas reflection não resolveria. Você precisaria instrumentar seu método utilizando AOP (uo simplesmente colocar código no método para que ele exponha os parâmetros).

Z

Jonas,

Baixei o código fonte do projeto e, tive um problema no eclipse.
Todos os métodos que implementavam um método de uma interface e tinham a anotação @Overrride ocorria o seguinte erro:
“The method XXX must override a superclass method”.
Parece que este era um comportamento do compilador java na versao 1.5.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6399361

Alterei o pom para:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin>
E o erro parou de acontecer.

Vocês estão utilizando a versão 1.6 mesmo?
E parabens à equipe pelo trabalho …

A

Oi Rafael, tudo bom?

Estranho, no meu ambiente aqui não está dando nenhum erro de compilação. Em qual método, de qual classe isso está acontecendo aí no seu ambiente?

Sobre a versão, no nosso release nós lançamos como versão mínima a 6, no entanto, ontem colocamos no /trunk como 5, pois, no final das contas não há diferença e os usuários que por algum motivo não podem migrar para java 6 e possuam a versao 5 também possam usar o Mirror.

[]'s

Z

Fala Adriano. Blz!

Uma das classes que deu esse erro foi net.vidageek.mirror.invoke.ConstructorHandlerByConstructor.java
Dá uma olhada nesse Sreenshot.

Compilando pela linha de comando usando Java 5 dá erro.
Já com Java6 compila.

[]'s


A

Oi Rafael, realmente, você tem razão.

Na versão 5 da JDK o @Override só serve para quando vc sobrescreve um método de uma superclasse (através de herança). Na versão 6 eles mudaram o conceito para além de através de herança, através de implementação de interface também, e daí o problema.

Já criei um ticket no nosso bugtracker.

Muito obrigado pelo feedback.

[]'s

O

jonasabreu:
@OCESN,

existe um erro na documentação.

Para refletir um método, o correto seria Mirror.on(clazz).reflect().method("methodName).withoutArgs();

Faltou a última chamada, pois você só consegue garantir a unicidade de um método se tiver o nome e os parâmetros.

Vou criar um issue pra corrigir isso.

Quanto ao nome dos parâmetros, eles não existem em tempo de execução. Você tem como recuperar os tipos dos parâmetros, mas não o nome (a não ser que você use o paranamer e compile em modo de debug, se não me engano).

E para pegar os valores que foram passados para o método, apenas reflection não resolveria. Você precisaria instrumentar seu método utilizando AOP (uo simplesmente colocar código no método para que ele exponha os parâmetros).


Beleza…vou estudar com essas informações.
E desde já agradeço a atenção.
Abraços a todos.

M

Bem, vamos ao meus comentários outra vez, aqui vão as alterações que eu acho pertinentes, vou colocando o código abaixo, sempre na ordem “original” e depois a minha idéia:

[code=java]//Criando clientes
Cliente cliente = Mirror.on( Cliente.class ).invoke().constructor().withArgs( new Date() );
Cliente cliente = Mirror.on( Cliente.class ).construct( new Date() ); //como eu gostaria que fosse

//chamando métodos

Mirror.on( cliente ).invoke().method( setDataDeNascimento ).withArgs( new Date() );

Mirror.on( cliente ).invoke(setDataDeNascimento).with( new Date() );
//alterando campos

Mirror.on( cliente ).get().field(dataDeNascimento);

Mirror.on( cliente ).get(dataDeNascimento);

//lendo campos
Mirror.on( cliente ).set().field(“dataDeNascimento”).withValue( new Date() );
Mirror.on( cliente ).set(“dataDeNascimento”, new Date());[/code]

Classe Cliente:

public class Cliente { private String nome; private Date dataDeNascimento; public Cliente(){} public Cliente( Date dataDeNascimento ) { this.dataDeNascimento = dataDeNascimento; } //gets e sets }

Bem, é isso aí, o arquivo com o patch pra o subversion vai anexado :slight_smile:

J

Olá Mauricio,

Vou levar estas sugestões para a lista de desenvolvimento.

Obrigado!

Criado 16 de novembro de 2008
Ultima resposta 21 de nov. de 2008
Respostas 49
Participantes 17