Une classe peut-elle s'ajouter une méthode à l'exécution (comme à partir d'un bloc static
), de sorte que si quelqu'un effectue une réflexion sur cette classe, il verra la nouvelle méthode, même si elle n'a pas été définie à compiler le temps?
Contexte:
Un framework que j'utilise attend que les classes Action
soient définies qui ont une méthode doAction(...)
, par convention. Le framework inspecte ces classes au moment de l'exécution pour voir quels types de paramètres sont disponibles dans leur méthode doAction()
. Par exemple: doAction (String a, Integer b)
J'aimerais que chaque classe puisse générer par programmation sa méthode doAction()
avec divers paramètres, juste à temps lorsqu'elle est inspectée. Le corps de la méthode peut être vide.
Ce n'est pas simple. Une fois qu'une classe est chargée par un chargeur de classe, il n'y a aucun moyen de changer les méthodes des classes chargées. Lorsqu'une classe est demandée, un chargeur de classe la charge et link it. Et il n'y a aucun moyen (avec Java) de changer le code lié ou d'ajouter/supprimer des méthodes.
La seule astuce qui me vient à l'esprit est de jouer avec les chargeurs de classe. Si nous supprimons un chargeur de classe personnalisé, les classes chargées par ce chargeur de classe doivent également être supprimées ou inaccessibles. L'idée qui me vient à l'esprit est de
Je laisse cela comme matière à réflexion, ne peut pas prouver, si cela conduit à une solution ou si nous avons des pièges.
Comme réponse simple à la question: Non, nous ne pouvons pas changer une classe chargée comme nous pouvons changer le contenu des champs avec réflexion. (nous ne pouvons pas ajouter ou supprimer des champs également).
Andres_D a raison, nous pouvons très bien le faire en utilisant le chargement de classe personnalisé, voici un guide détaillé sur la façon de le faire: http://www.javaworld.com/javaworld/jw-06-2006/jw- 0612-dynamic.html? Page = 1
L'article explique comment écrire du code dynamique Java. Il explique la compilation du code source au moment de l'exécution, le rechargement de classe et l'utilisation du modèle de conception Proxy pour apporter des modifications à une classe dynamique transparente pour son appelant.
En fait, un chercheur en Autriche a écrit une machine virtuelle Java qui permet même de recharger des classes avec différentes hiérarchies de types. Ils ont atteint cet objectif en utilisant des points de sauvegarde de threads existants pour générer un `` univers latéral '' complet d'un objet et de toutes ses références associées et de son contenu référencé, puis une fois entièrement réorganisé avec toutes les modifications requises, il suffit de permuter dans toutes les classes modifiées. [1] Voici un lien vers leur projet http://ssw.jku.at/dcevm/ le parrainage d'Oracle fait certainement des spéculations intéressantes sur les plans futurs.
Des modifications moins intrusives des corps de méthode et des champs sont déjà possibles dans la norme Java VM utilisant les capacités de remplacement à chaud du JPDA comme présenté dans Java 1.4:
docs.Oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap
Je ne sais pas s'il s'agissait du premier mais le document de 2001 de cet employé de Sun semble être l'une des premières propositions mentionnant les capacités du HotSpot to Hot Swap. [2]
[~ # ~] référence [~ # ~]
[1] T. Würthinger, C. Wimmer et L. Stadler, "Dynamic Code Evolution for Java", présenté à la 8e Conférence internationale sur les principes et la pratique de la programmation à Java, Vienne, 2010.
[2] M. Dmitriev, "Towards flexible and safe technology for runtime evolution of Java language applications", in OOPSLA Workshop on Engineering Complex Object-Oriented Systems for Evolution, 2001.
Non, ce n'est pas (facilement) possible en Java.
Il semble que vous essayez d'utiliser Java comme s'il s'agissait d'un langage de programmation dynamique. Par exemple, Ruby a des classes ouvertes: vous pouvez ajouter et supprimer des méthodes from Ruby classes à l'exécution. Dans Ruby, vous pouvez également avoir une méthode "méthode manquante" dans votre classe, qui sera appelée lorsque vous essayez d'appeler une méthode qui n'existe pas dans le Une telle chose n'existe pas non plus en Java.
Il existe une version de Ruby qui s'exécute sur la JVM, JRuby, et il doit faire des tours très difficiles pour faire fonctionner les classes ouvertes sur la JVM.
Vous pouvez avoir une méthode doAction
qui fait tout ce que vous voudriez que la méthode générée fasse. Y a-t-il une raison pour laquelle il doit être généré ou peut-il être dynamique?
Le proxy peut aider. Mais vous devez instancier un proxy chaque fois que vous souhaitez ajouter ou supprimer une méthode.
Ce que je suggère devrait fonctionner pour votre situation: 1. Vous avez une classe MyClass existante avec n méthodes 2. Vous voulez inclure la méthode (n + 1) qui n'est pas dans la classe lors de la compilation dans un autre fichier source .Java
Ma façon de le résoudre est l'héritage. Créez un nouveau fichier source .Java pour une classe MyClassPlusOne étendant la première classe MyClass. Compilez cette classe et utilisez l'objet. Comment puis-je compiler et déployer une Java lors de l'exécution?
class MyClassPlusOne extends MyClass
{
void doAction(String a, Integer b)
{
int myNPlus1 = a+b;
//add whatever you want before compiling this code
}
}
Je crois que vous avez besoin d'un outil/cadre de modification de code octet, comme asm, cglib ou javassist. Vous pouvez y parvenir via des aspects/tissages comme c'est le cas au printemps, mais je crois que vous devez encore définir la méthode en premier.
Il semble qu'il n'y ait aucun moyen d'ajouter dynamiquement une méthode. Mais vous pouvez préparer une classe avec une liste de méthodes ou un hachage comme:
import Java.lang.reflect.InvocationTargetException;
import Java.lang.reflect.Method;
import Java.lang.reflect.Modifier;
import Java.util.HashMap;
public class GenericClass {
private HashMap<String, Method> methodMap = new HashMap<String, Method>();
public Object call(String methodName,Object ...args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method method = methodMap.get(methodName);
return method.invoke(null, args);
}
public void add(String name,Method method){
if(Modifier.isStatic(method.getModifiers()))
methodMap.put(name, method);
}
public static void main(String[] args) {
try {
GenericClass task = new GenericClass();
task.add("Name",Object.class.getMethod("Name", new Class<?>[0]));
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
}
Ensuite, à l'aide de réflexions, vous pouvez définir ou désactiver l'attribut.
Je ne suis pas sûr que ce soit possible. Cependant, vous pouvez utiliser AspectJ, ASM, etc. et intégrer ces méthodes dans les classes appropriées.
L'autre alternative consiste à utiliser la composition pour encapsuler la classe cible et fournir la méthode doAction. Vous finiriez par déléguer à la classe cible dans ce cas.