Question

Le problème: Je voudrais être en mesure d'accéder génériquement en Java toute propriété / champ sur Java ojbect de façon similaire à la façon dont un langage dynamique (pensez Groovy, JavaScript) serait. Je sais pas au moment où je vous écris ce code de plomberie quel type d'objet il est ou ce que la propriété / nom de domaine sera. Mais je saurai le nom propriété / champ quand je vais l'utiliser.

Ma solution actuelle: Jusqu'à présent, j'ai écrit une simple classe d'emballage que les utilisations java.beans.Introspector pour saisir les propriétés d'un Bean / POJO et les exposer comme Map<String, Object>. Il est brut, mais fonctionne pour les cas simples.

Ma question est ce que les autres méthodes sont là pour aborder ce problème en plus de réflexion / conversion à une carte?

Avant d'aller trop loin dans cette voie, je voudrais savoir si quelqu'un sait comment je pourrais cannibaliser quelque chose de Rhino ou peut-être javax.script.* qui a une mise en œuvre bien pensé de ce concept. Ou peut-être que je une approche totalement différente n'a pas pris en considération.

Modifier oui je suis familier avec la réflexion (que je crois que Introspector utilise sous le capot de toute façon). J'étais curieux de savoir s'il y avait un autre bien pensé solutions.

Edit 2: Il semble que la plupart des réponses populaires impliquent 1) la réflexion soit directement, soit par l'intermédiaire des classes d'aide et / ou 2) la cartographie des interfaces qui mettent en œuvre les membres de la classe désirée. Je suis vraiment intrigué par le commentaire qui parle de tirer parti Groovy. Depuis Groovy a vrai canard frappe et il est un langage machine virtuelle Java, est-il un moyen de faire un aide simple Groovy et l'appeler de Java? Ce serait vraiment cool et probablement plus souple et plus performant.

Réponse: J'ai marqué la réponse de Mike comme le meilleur, car il est un concept complet qui est le plus proche. Je vais probablement pas aller dans cette voie pour ce cas particulier, mais il est certainement une approche utile. Tout le monde en regardant à travers cela devrait être sûr de lire les conversations ici car il y a beaucoup d'informations utiles là-dedans aussi.

Merci!

Était-ce utile?

La solution

Si vous connaissez l'ensemble des API que vous souhaitez exposer, dites que vous savez que vous souhaitez accéder à une méthode de longueur et une méthode iterator, vous pouvez définir une interface:

public interface TheInterfaceIWant {
  int length();
  void quack();
}

et vous voulez être en mesure d'utiliser cette interface pour l'accès des méthodes correspondantes sur les instances qui ne mettent pas en œuvre cette interface, vous pouvez utiliser des classes proxy: http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Proxy .html

Alors vous créez un proxy

final Object aDuck = ...;
TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance(
    TheInterfaceIWant.class.getClassLoader(),
    new Class[] { TheInterfaceIWant.class },
    new InvocationHandler() {
      public Object invoke(
          Object proxy, Method method, Object[] args)
          throws Throwable {
        return aDuck.getClass().getMethod(
            method.getName(), method.getParameterTypes()).invoke(aDuck, args);
      }
    });

Ensuite, vous pouvez utiliser l'emballage comme vous le feriez le canard dans un langage typé dynamiquement.

if (aDuckWrapper.length() > 0) {
  aDuckWrapper.quack();
}

Voici une longueur exemple runnable qui imprime « Quack » quatre fois à l'aide d'une enveloppe:

import java.lang.reflect.*;

public class Duck {

  // The interface we use to access the duck typed object.
  public interface TheInterfaceIWant {
    int length();
    void quack();
  }

  // The underlying instance that does not implement TheInterfaceIWant!
  static final class Foo {
    public int length() { return 4; }
    public void quack() { System.out.println("Quack"); }
  }

  public static void main(String[] args) throws Exception {
    // Create an instance but cast away all useful type info.
    final Object aDuck = new Foo();

    TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance(
        TheInterfaceIWant.class.getClassLoader(),
        new Class[] { TheInterfaceIWant.class },
        new InvocationHandler() {
          public Object invoke(
              Object proxy, Method method, Object[] args)
              throws Throwable {
            return aDuck.getClass().getMethod(
                method.getName(), method.getParameterTypes()).invoke(aDuck, args);
          }
        });

    for (int n = aDuckWrapper.length(); --n >= 0;) {
      // Calling aDuck.quack() here would be invalid since its an Object.
      aDuckWrapper.quack();
    }
  }
}

Autres conseils

Une autre méthode que je viens suis tombé sur qui met à profit (? Abus) l'effacement de type est assez intéressant:

http: // rickyclarkson. blogspot.com/2006/07/duck-typing-in-java-and-no-reflection.html

Je ne suis pas sûr que j'achète que ce soit très différent d'utiliser simplement les interfaces directement, mais peut-être il est utile à quelqu'un d'autre.

Jetez un oeil sur les méthodes de java.lang.Class et à l'API de réflexion. Java.lang.reflect *

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top