Pergunta

Atualmente estou trabalhando com um, interpretado linguagem de programação, especializada implementado em Java. Como uma parte muito pequena da língua, eu gostaria de adicionar a capacidade de fazer chamadas em Java. Antes de mergulhar em todo o âmago da questão de reflexão, eu queria saber se alguém sabia de uma biblioteca geral para fazer a parte de "back-end" de invocar código Java reflexivamente.

Isto é, eu analisar uma string (I definir a gramática) em alguma estrutura de dados que representa uma chamada de método Java (ou construtor, ou o acesso de campo) e, em seguida, passar essa estrutura de dados para esta biblioteca que invoca a chamada e retorna o resultado. Em particular, eu gostaria que ele já lidar com todos os casos, a ponta que eu não quero descobrir:

  • Automagically escolher o método correto com base nos tipos de argumentos (como um Class.getDeclaredMethod inteligente ())
  • Handle distinção entre matrizes e referências normais objeto
  • etc

Eu passei um pouco de tempo olhando para as implementações de linguagens dinâmicas na JVM, mas estes são geralmente muito mais complicado do que eu estou procurando, ou altamente otimizado para o idioma específico.

Outra opção é converter a minha gramática em uma string em alguma linguagem dinâmica e invocá-lo com o Rhino ou algo assim, mas isso é um pouco mais em cima do que eu estou procurando.

Obrigado!

Foi útil?

Solução

Apenas um comentário para sua própria resposta; realmente BeanUtils tem suporte para obter "uma estreita correspondência" dado um conjunto de parâmetros. Veja getMatchingAccessibleMethod ()

BeanUtils é realmente poderoso e tem muitos métodos utilitários para inspecionar classes. O mesmo apoio é naturalmente disponível para os construtores.

Outras dicas

Tente o href="https://github.com/alexruiz/fest-reflect" rel="nofollow noreferrer"> módulo Reflexão

 String name = method("get").withReturnType(String.class)
                         .withParameterTypes(int.class)
                         .in(names)
                         .invoke(8);

Se você está à procura de simplicidade, eu criei uma biblioteca simples chamado Joor em para facilitar o acesso à API reflexão em Java. Ele suporta a maioria das ações essenciais sem a criação de uma enorme API. Aqui está um exemplo do que parece código Joor como:

String world = 
on("java.lang.String") // Like Class.forName()
.create("Hello World") // Call the most specific matching constructor
.call("substring", 6)  // Call the most specific matching substring() method
.call("toString")      // Call toString()
.get()                 // Get the wrapped object, in this case a String

Dê uma olhada suporte a scripts de Java ; Eu acredito que ele irá ajudá-lo a resolver o seu problema.

Tenha um olhar em Apache Commons BeanUtils

Eu fortemente considerar também ter um olhar para molas ReflectionUtils classe. manipulação de reflexão muito poderoso.

Para levantar este dos mortos:

invoke(Object object, String methodName, Object[] args) 

Apache Commons lang tem exatamente esse método. MethodUtils # invoke

Eu comecei a criar um com.lexicalscope.fluent-reflexão biblioteca: fluente-reflexão que se integra com hamcrest e lambdaj

Você pode escrever código como este; que chama todos os métodos anotados do pós construto em uma classe:

forEach(
   object(subject).methods(annotatedWith(PostConstruct.class)),
   ReflectedMethod.class).call();

Blog post aqui: http://www.lexicalscope.com / blog / categoria / software-projectos / fluente-reflexão /

Documentação aqui: http://fluent-reflection.lexicalscope.com/

Você pode obtê-lo de maven central aqui: http://repo1.maven.org/maven2/com/ lexicalscope / fluente-reflexão / fluente-reflexão /

Ele tem algumas características básicas faltando no momento, como o acesso aos campos, mas funciona para métodos. Ainda vai levar um tempo para chegar a um realmente apresentam ponto estável (como um ou dois anos), como eu só estou trabalhando nisso de vez em quando. Mas é desenvolvido para um bom padrão de alta qualidade (espero) e é opensource então você pode basicamente usá-lo como está agora se ele tem todas as características que você precisa (você só pode ter que ajustar o seu código um pouco se você quiser usar versões mais recentes que são liberados). Eu estou usando-o em algum código de produção para elas momento.

Ele é projetado para ser bastante extensível, de modo que você pode plug-in em estratégias para encontrar os métodos que você quer em um estilo de baixo acoplamento (composição). Então, se ele não tem a exata estratégia de pesquisa método que quiser, espero que seja fácil de adicioná-lo.

Eu acabei indo com a sugestão de Alex. BeanUtils ajuda muito para o feijão, mas eu não quero trabalhar somente com Beans. FEST parece muito legal e eu marcada-lo para um estudo mais aprofundado, mas como BeanUtils, ele não aparece para resolver o que eu considero ser o difícil problema aqui. Ou seja, dado um nome do método e lista de argumentos, escolher o método que melhor se "encaixa" os argumentos. Se um método leva uma bóia e eu tenho uma dupla, deve ser inteligente o suficiente para não rejeitar esse método porque a assinatura não corresponder exatamente.

Obviamente, linguagens de script construídas na JVM resolver este problema, mas de uma forma muito mais complicado do que eu preciso devido a otimizações específicas do idioma. Então, uma vez que este for menor e recurso experimental, eu escolhi uma solução rápida usando o suporte ao mecanismo de scripts (JavaScript, em particular) em Java 1.6. Aqui está a idéia básica:

private ScriptEngine engine = ... initialize with JavaScript engine ...

private Object invoke(Object object, String methodName, Object[] args) 
   throws RhsFunctionException
{
   // build up "o.method(arg0, arg1, arg2, ...)"
   StringBuilder exp = new StringBuilder("o." + methodName);
   engine.put("o", object);
   buildArgs(arguments, exp);

   try {
      return engine.eval(exp.toString());
   }
   catch (ScriptException e) {
      throw new RhsFunctionException(e.getMessage(), e);
   }
}

private void buildArgs(Object[] args, StringBuilder exp)
{
   // Use bindings to avoid having to escape arguments
   exp.append('(');
   int i = 0;
   for(Symbol arg : args) {
         String argName = "arg" + i;
         engine.put(argName, arg);
         if(i != 0) {
            exp.append(',');
         }
         exp.append(argName);
         ++i;
   }
   exp.append(')');
}

Há, obviamente, um pouco mais do que isso, mas essa é a idéia básica. Eu realmente não gosto de construir uma corda e avaliá-lo, mas usando as ligações sugeridas por Alex, I evitar a maioria das armadilhas em torno de escapar. Além disso, eu tenho uma interface limpa e simples que eu posso trocar com uma implementação "real" se for necessário.

Qualquer comentário ou soluções alternativas são mais do que bem-vindos.

eu escrevi e open-source este código depois de ler esta discussão, talvez você possa encontrá-lo útil.

https: //github.com/yclian/Reflects.java/blob/master/src/test/java/my/jug/reflects/ReflectsTest.java

É inspirado goiaba, assim você pode usar Predicate para filtrar os métodos que você gosta.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top