Domanda

Attualmente sto lavorando con un servizio specializzato, interpretato, linguaggio di programmazione implementato in Java.Come una parte molto piccola della lingua, vorrei aggiungere la possibilità di effettuare chiamate in Java.Prima di tuffarsi in tutto il nocciolo della riflessione, mi chiedevo se qualcuno sapesse di un generale libreria per fare il "back-end" parte di invocare il codice Java aggiornati.

Che è, mi analizzare una stringa (definire la grammatica) in una qualche struttura dati che rappresenta un metodo Java chiamata (o costruttore, o di accesso al campo) e quindi passare la struttura di dati per questa libreria che richiama la chiamata e restituisce il risultato.In particolare, mi piacerebbe che già di gestire tutti i casi limite che non voglio capire:

  • Automagicamente scegliere il giusto metodo, in base al tipo di argomenti (come un intelligente e di Classe.getDeclaredMethod())
  • Maniglia distinzione tra matrici e normale riferimenti a oggetti
  • ecc

Ho trascorso un po ' di tempo a guardare le implementazioni di linguaggi dinamici su JVM, ma questi sono generalmente molto più complicata di quanto sto cercando, o altamente ottimizzato per la lingua in particolare.

Un'altra opzione è quella di convertire la mia grammatica in una stringa in linguaggio dinamico e richiamarlo con Rhino o qualcosa del genere, ma un po ' più di overhead che sto cercando.

Grazie!

È stato utile?

Soluzione

Solo un commento alla propria risposta; in realtà beanutils ha il supporto per ottenere "una stretta corrispondenza" dato un insieme di parametri. Vedere getMatchingAccessibleMethod ()

BeanUtils è davvero potente e ha un sacco di metodi di utilità per l'ispezione classi. Lo stesso supporto è naturalmente disponibile per i costruttori.

Altri suggerimenti

Prova il href="https://github.com/alexruiz/fest-reflect" rel="nofollow noreferrer"> modulo Riflessione FEST

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

Se siete alla ricerca di semplicità, ho creato un semplice libreria chiamata Joor per agevolare l'accesso alle API riflessione in Java. Supporta le azioni più essenziali, senza la costruzione di un enorme API. Ecco un esempio di ciò che il codice Joor appare come:

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

Date un'occhiata a supporto di scripting Java ; Credo che sarà aiuterà ad affrontare il problema.

Dai un'occhiata alla Apache Commons BeanUtils

Vorrei prendere in seria considerazione anche avere uno sguardo a classe di sorgenti ReflectionUtils. Molto potente movimentazione di riflessione.

Per sollevare questo dai morti:

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

Apache Commons Lang ha esattamente questo metodo. MethodUtils # invoke

ho cominciato a creare una libreria com.lexicalscope.fluent-riflessione: fluente-riflesso  che si integra con hamcrest e lambdaj

È possibile scrivere codice come questo; che chiama tutti i metodi annotati dopo costrutto in una classe:

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

Blog post qui: http://www.lexicalscope.com / blog / categoria / software-progetti / fluente riflessione /

Documentazione qui: http://fluent-reflection.lexicalscope.com/

Si può ottenere da Maven centrale qui: http://repo1.maven.org/maven2/com/ lexicalscope / fluente riflessione / fluente riflessione /

Ha alcune caratteristiche di base mancanti al momento, come l'accesso ai campi, ma funziona per i metodi. Ci vorrà probabilmente un po 'per arrivare a una davvero caratteristica punto stabile (come un anno o due), come sto solo lavorando su di esso di tanto in tanto. Ma si è sviluppato per un abbastanza standard di alta qualità (spero) ed è opensource in modo da poter praticamente usarlo come è ora, se ha tutte le caratteristiche necessarie (appena potreste modificare il tuo codice di un po 'se si vuole di utilizzare le versioni più recenti che vengono rilasciati). Io lo utilizzo in un certo codice di produzione al loro momento.

E 'progettato per essere abbastanza estensibile, in modo da poter plug-in strategie per trovare i metodi che si desidera in uno stile loosely coupled (compositiva). Quindi, se non ha l'esatta strategia di metodo di ricerca che si desidera, si spera è facile per aggiungerlo.

Ho finito per andare con Alex suggerimento.BeanUtils aiuta molto per i fagioli, ma non ho voglia di lavorare esclusivamente con i Fagioli.FEST sembra davvero cool e ho segnalibro per un ulteriore studio, ma come BeanUtils, non sembra risolvere quello che io considero il difficile problema qui.Cioè, dato il nome di un metodo e di un elenco di argomenti, scegliere il metodo che meglio si "adatta" gli argomenti.Se un metodo richiede un galleggiante e ho una doppia, dovrebbe essere abbastanza intelligente da non rifiutare il metodo, perché la firma non corrisponde esattamente.

Ovviamente, i linguaggi di scripting costruito su JVM risolvere questo problema, ma in un modo molto più complesso di quello di cui ho bisogno a causa di un linguaggio di ottimizzazioni specifiche.Così, dal momento che questo è un minore e funzione sperimentale, ho scelto una soluzione rapida utilizzando il motore di script di supporto (JavaScript, in particolare) in Java 1.6.Ecco l'idea di base:

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

C'è ovviamente un po ' di più, ma questa è l'idea di base.Non mi piace molto costruire una stringa e di valutare, ma utilizzando le associazioni suggerito da Alex, che cerco di evitare la maggior parte delle insidie intorno a fuggire.Inoltre, ho un pulito, semplice interfaccia che posso scambiare con un "vero" attuazione, se dovesse essere necessario.

Tutte le risposte o soluzioni alternative sono più che benvenuti.

ho scritto e open-source il codice dopo aver letto questa discussione, forse si può trovare utile.

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

E 'ispirato a Guava, in modo da poter utilizzare Predicate per filtrare i metodi che ti piace.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top