Un moyen d’invoquer une méthode privée?

J’ai une classe qui utilise XML et la reflection pour renvoyer Object s à une autre classe.

Normalement, ces objects sont des sous-champs d’un object externe, mais parfois c’est quelque chose que je veux générer à la volée. J’ai essayé quelque chose comme ça mais en vain. Je crois que c’est parce que Java ne vous permettra pas d’accéder à private méthodes private de reflection.

 Element node = outerNode.item(0); Ssortingng methodName = node.getAtsortingbute("method"); Ssortingng objectName = node.getAtsortingbute("object"); if ("SomeObject".equals(objectName)) object = someObject; else object = this; method = object.getClass().getMethod(methodName, (Class[]) null); 

Si la méthode fournie est private , elle échoue avec une NoSuchMethodException . Je pourrais le résoudre en rendant la méthode public ou en créant une autre classe à partir de laquelle

Bref, je me demandais s’il y avait un moyen d’accéder à une méthode private par reflection.

Vous pouvez invoquer une méthode privée avec reflection. Modifier le dernier bit du code posté:

 Method method = object.getClass().getDeclaredMethod(methodName); method.setAccessible(true); Object r = method.invoke(object); 

Il y a quelques mises en garde. Tout d’abord, getDeclaredMethod trouvera uniquement la méthode déclarée dans la Class , non héritée des supertypes. Donc, parcourez la hiérarchie de classes concrète si nécessaire. Deuxièmement, un SecurityManager peut empêcher l’utilisation de la méthode setAccessible . Ainsi, il peut être nécessaire de l’exécuter en tant que PrivilegedAction (en utilisant AccessController ou Subject ).

Utilisez getDeclaredMethod() pour obtenir un object Method privé, puis utilisez method.setAccessible() pour permettre de l’appeler réellement.

Si la méthode accepte un type de données non primitif, la méthode suivante peut être utilisée pour appeler une méthode privée de n’importe quelle classe:

 public static Object genericInvokeMethod(Object obj, Ssortingng methodName, Object... params) { int paramCount = params.length; Method method; Object requiredObj = null; Class[] classArray = new Class[paramCount]; for (int i = 0; i < paramCount; i++) { classArray[i] = params[i].getClass(); } try { method = obj.getClass().getDeclaredMethod(methodName, classArray); method.setAccessible(true); requiredObj = method.invoke(obj, params); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return requiredObj; } 

Les parameters acceptés sont obj, methodName et les parameters. Par exemple

 public class Test { private Ssortingng concatSsortingng(Ssortingng a, Ssortingng b) { return (a+b); } } 

La méthode concatSsortingng peut être appelée en tant que

 Test t = new Test(); Ssortingng str = (Ssortingng) genericInvokeMethod(t, "concatSsortingng", "Hello", "Mr.x"); 

Permettez-moi de fournir un code complet pour les méthodes protégées par exécution par reflection. Il prend en charge tous les types de parameters, y compris les génériques, les parameters automatiques et les valeurs nulles

 @SuppressWarnings("unchecked") public static  T executeSuperMethod(Object instance, Ssortingng methodName, Object... params) throws Exception { return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params); } public static  T executeMethod(Object instance, Ssortingng methodName, Object... params) throws Exception { return executeMethod(instance.getClass(), instance, methodName, params); } @SuppressWarnings("unchecked") public static  T executeMethod(Class clazz, Object instance, Ssortingng methodName, Object... params) throws Exception { Method[] allMethods = clazz.getDeclaredMethods(); if (allMethods != null && allMethods.length > 0) { Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new); for (Method method : allMethods) { Ssortingng currentMethodName = method.getName(); if (!currentMethodName.equals(methodName)) { continue; } Type[] pTypes = method.getParameterTypes(); if (pTypes.length == paramClasses.length) { boolean goodMethod = true; int i = 0; for (Type pType : pTypes) { if (!ClassUtils.isAssignable(paramClasses[i++], (Class) pType)) { goodMethod = false; break; } } if (goodMethod) { method.setAccessible(true); return (T) method.invoke(instance, params); } } } throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " + Arrays.toSsortingng(paramClasses)); } throw new MethodNotFoundException("There are no methods found with name " + methodName); } 

Method utilise apache ClassUtils pour vérifier la compatibilité des parameters autoboxés

vous pouvez le faire en utilisant ReflectionTestUtils of Spring ( org.springframework.test.util.ReflectionTestUtils )

 ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument); 

Exemple: si vous avez une classe avec une méthode privée square(int x)

 Calculator calculator = new Calculator(); ReflectionTestUtils.invokeMethod(calculator,"square",10); 

Une autre variante utilise la bibliothèque JOOR très puissante https://github.com/jOOQ/jOOR

 MyObject myObject = new MyObject() on(myObject).get("privateField"); 

Il permet de modifier les champs comme les constantes statiques finales et d’appeler les méthodes protégées sans spécifier de classe concrète dans l’inheritance hierarhy

   org.jooq joor-java-8 0.9.7