7
votes

Méthode de type de type réflexion en Java

est un moyen pratique de faire référence à une méthode sur une classe de manière sûre? Un exemple de base est si je voulais créer quelque chose comme la fonction utilitaire suivante: xxx pré>

Pour l'appeler, je devrais faire: P>

validateField(data, Person.phoneNumber.getter, options);


4 commentaires

C'est une plainte commune concernant la réflexion - et une bonne raison pour l'éviter dans la mesure du possible. Être quelqu'un qui doit faire beaucoup de réflexion avec l'un des projets que je travaille, je ressens votre douleur.


Je pense que le terme "type-coffre" est légèrement faux. Utilisation de la réflexion @ Java est sécurisée (en ce qui concerne l'exécution). Les erreurs de type ne se présentent tout simplement pas plus tôt pendant la compilation.


Utilisez le @jailbreak de Manifold pour la compilée-Time Type-Safe Accès aux champs privés, aux méthodes, etc. En savoir plus: Type-Safe-Reflet


Pourquoi ne pas passer une fonction comme Lambda à elle?


9 Réponses :


4
votes

Il n'y a rien dans la langue mais - mais une partie de la proposition de fermetures pour Java 7 comprend des littéraux méthodes, je crois.

Je n'ai aucune suggestion au-delà de cela, j'ai peur.


0 commentaires

1
votes

est un moyen pratique de faire référence à une méthode sur une classe de manière sûre? p>

Tout d'abord, la réflexion est em> type-coffre-fort. C'est juste qu'il est dactylographié de manière dynamique, non typée statiquement. P>

Ainsi, en supposant que vous voulez un typé de manière statique em> équivalente de réflexion, la réponse théorique est que c'est impossible. Considérez ceci: P>

Method m;
if (arbitraryFunction(obj)) {
    obj.getClass().getDeclaredMethod("foo", ...);
} else {
    obj.getClass().getDeclaredMethod("bar", ...);
}


2 commentaires

Merci pour la correction de la terminologie. Je ne sais pas comment le reste de votre réponse est lié à ma question. Si vous faites une réflexion de manière dynamique au moment de l'exécution (c'est-à-dire que le résultat de la réflexion pourrait varier en fonction de l'entrée ou d'un autre état d'exécution), alors oui, vous ne pourrez probablement pas vous assurer que le code ne jette pas une exception ou que cela arrête.


J'avais plus de questions sur la réflexion dans laquelle le résultat est toujours le même. C'EST À DIRE. PERSON.CLASS.GETMETHOD ("GETPHONENULLET", NULL) retournerait toujours la même méthode et il est tout à fait possible de le résoudre au moment de la compilation. Tout comme comment vous pouvez faire la personne.class pour obtenir un objet de classe, il serait utile de pouvoir faire quelque chose comme Person.getPhonenGumber.Method pour obtenir un objet de méthode.



6
votes

Comme d'autres mentionnent, il n'y a pas de moyen réel de faire cela ... et je n'ai pas vu de précompiler qui le soutient. La syntaxe serait intéressante, de dire le moins. Même dans votre exemple, il ne pouvait que couvrir un petit sous-ensemble des possibilités de réflexion potentielles pouvant vouloir faire car elle ne gérera pas les accesseurs ou les méthodes non standard qui prennent des arguments, etc.

même s'il est impossible Pour vérifier au moment de la compilation, si vous voulez que le code incorrecte échoue dès que possible, une approche consiste à résoudre les objets de méthode référencés lors de l'heure d'initialisation de la classe.

Imaginez que vous avez une méthode utilitaire pour rechercher des objets de méthode qui Peut-être inclure une exception d'erreur ou d'exécution: xxx

puis dans vos classes, avez des constantes de préserrer les méthodes que vous utiliserez: xxx P> Au moins, il échouera dès que MyClass est chargé la première fois.

J'utilise beaucoup de réflexion, notamment la réflexion de la propriété de haricot et je viens de vous habituer à des exceptions tardives au moment de l'exécution. Mais ce style de code de haricot a tendance à faire une erreur en retard pour toutes sortes d'autres raisons, être très dynamique et toutes. Pour quelque chose entre les deux, ce qui précède aiderait.


4 commentaires

Cela semble être une idée décente. C'est mieux que d'essayer de définir des constantes de string avec les noms de champs comme ce que j'ai vu dans le code que j'ai maintenu.


Oui, c'est une sorte de "en tirer le meilleur parti". Je ne sais pas qui / pourquoi j'ai eu un vote en baisse de quelqu'un. :) Toujours amusant de me faire voter sans commentaire.


L'autre bonne chose à propos de cette approche est quand / si la langue obtient la méthode littérales, il est éventuellement un simple changement à convertir.


8 ans plus tard ... Il y a une "vraie façon de faire ça". Utilisez le @jailbreak de Manifold pour la compilée-Time Type-Safe Accès aux champs privés, aux méthodes, etc. En savoir plus: Type-Safe-Reflet



0
votes

inspiré des cadres moqueurs, nous pourrions rêver de la syntaxe suivante: xxx

L'astuce est la déclaration générique: xxx p> maintenant Le type de retour de la méthode est identique à celui de votre objet de données et que vous pouvez utiliser l'achèvement du code (et la vérification statique) pour accéder à toutes les méthodes, y compris les méthodes de getter.

comme un inconvénient, le code ISN 'T assez intuitif de lire, puisque l'appel à la getter n'obtient rien, mais instruise au contraire le validateur de valider le champ.

Une autre option possible serait d'annoter les champs de votre classe de données : xxx

puis appelez simplement: xxx

pour valider tous les champs en fonction des options annotées.


0 commentaires

2
votes

Java manque le sucre de la syntaxe pour faire quelque chose de aussi agréable que personne.Phonenumber.geter code>. Mais si la personne est une interface, vous pouvez enregistrer la méthode Getter à l'aide d'un proxy dynamique. Vous pouvez enregistrer des méthodes sur des classes non finales à l'aide de CGLib, de la même manière Makiito le fait.

MethodSelector<Person> selector = new MethodSelector<Person>(Person.class);
selector.select().getPhoneNumber();
validateField(data, selector.getMethod(), options);


0 commentaires

0
votes

Le framework piclock vous permet de procéder aux éléments suivants:

 assertThat(Data.class, providesFeaturesOf(OpenData.class));


0 commentaires

3
votes

Check out https://jodd.org/ref/methref.html . Il utilise la bibliothèque de proxy Jodd (Proxetta) pour proxy votre type. Pas sûr de ses caractéristiques de performance, mais il fournit une sécurité de type.

Un exemple: Supposons que str.class code> a la méthode .BOO () code> et vous souhaitez obtenir son nom comme la chaîne "boo" code " >: P>

Methref<Str> m = Methref.on(Str.class);

// `.to()` returns a proxied instance of `Str` upon which you
// can call `.boo()` Methods on this proxy are empty except when
// you call them, the proxy stores the method's name. So doing this
// gets the proxy to store the name `"boo"`.

m.to().boo();

// You can get the name of the method you called by using `.ref()`:

m.ref();   // returns "boo"                                 


0 commentaires

0
votes

Utilisez le @jailbreak de Manifold CODE> pour la compilation-Time Type-Safe-Safe Strong> Accès aux champs privés, aux méthodes, etc.

public class Foo {
  private final int _privateField;

  public Foo(int value) {
    _privateField = value;
  }

  private String privateMethod() {
    return "hi";
  }

  private String privateMethod(String param) {
    return param;
  }
}


0 commentaires

0
votes

J'ai trouvé un moyen d'obtenir la méthode méthode code> à l'aide de Lambdas. Cela ne fonctionne que sur les méthodes d'interface cependant actuellement.

Ça fonctionne en utilisant Net.Jodah: TypeTools code> une bibliothèque très légère. https://github.com/jhalterman/typetools p> xxx pré >

Utilisation: p>

Method method = MethodResolver.toMethod2(SomeIFace::foobar);
System.out.println(method); // public abstract example.Result example.SomeIFace.foobar(java.lang.String,boolean)

Method get = MethodResolver.<Supplier, Object>toMethod0(Supplier::get);
System.out.println(get); // public abstract java.lang.Object java.util.function.Supplier.get()

Method accept = MethodResolver.<IntFunction, Integer, Object>toMethod1(IntFunction::apply);
System.out.println(accept); // public abstract java.lang.Object java.util.function.IntFunction.apply(int)

Method apply = MethodResolver.<BiFunction, Object, Object, Object>toMethod2(BiFunction::apply);
System.out.println(apply); // public abstract java.lang.Object java.util.function.BiFunction.apply(java.lang.Object,java.lang.Object)


0 commentaires