A módszeres osztály

Előző két részünkben áttekintettük a Java Reflection két osztályát, név szerint a Class, és a Constructor osztályokat. Ehavi cikkünkre maradt a reflection egyik legérdekesebb osztálya, vagyis az az osztály, amely magáról az osztály tagfüggvényeiről szolgáltat információkat.

Az osztály a Method nevet viseli, és ahhoz hogy tudjuk használni, szükséges importálnunk a java.lang.reflect csomagból legalább a Method osztályt, viszont ajánlom a teljes reflectet importra, mert akkor teljes egészében tudjuk használni, megszorítások nélkül az összes reflection képességet.

A Method osztály a java.lang.reflect.AccesibleObject –ből van származtatva, tehát először hadd vegyük ezt szemügyre. Mint tudjuk, egy Java osztály függvényeinek, illetve változóinak van egy hozzáférhetőségi szintje. Ezek lehetnek: publikus (public), privát (private) illetve védett (protected), hogy csak az alapokat soroljam fel. Ahogy szintén tudjuk, a publikus tagokat bárki elérheti, a protected tagokat csak a származtatott osztályok látják, a privát tagok pedig egyedül az osztály számára láthatóak.

Az AccessibleObject osztálynak van egy metódusa, mely bizonyos esetekben módosítani tudja ezeket a hozzáférési jogokat. A metódus a setAccessible névre hallgat, és két változatban is megtalálható. A metódus lényege viszont a következőkön alapul: a (az egyik) paraméter egy boolean típus, amely true esetén a privát illetve protected tagfüggvényeket publikus hozzáférésűvé változtatja, false esetén pedig használja (visszaállítja) az osztályban megadott hozzáférési jogokat.

Ez a metódus az első lépésben meghívja az esetlegesen létező Security Manager checkPermission metódusát, paraméterként átad egy java.lang.reflect.ReflectPermission (”suppressAccesChecks”) objektumot. A checkPermission SecurityException kivételt dob, ha bizonyos okok miatt nincs jogunk megváltoztatni a láthatósági jogokat (például egy privát konstruktor publikussá való tételének esetén, mint a Class osztály esetében).

Amennyiben sikerült a láthatóságát megváltoztatni az aktuális AccessibleObject –nek, a Reflection segítségével elméletileg bármilyen műveletet elvégezhetünk vele.

Egy függvény absztraktizálása

És most, hogy tudjuk, miként lehet meghívni egy privát függvényt minden körülmények közt, hát nézzünk szét picit a Method osztály háztáján. A Method osztály egy osztály egy darab osztálymetódusáról szolgál információkkal, és ennek a metódusnak az elérhetőségét is biztosítja.

Egy Method objektumot nem tudunk explicit módon létrehozni, hanem használnunk kell a Class osztály getDeclaredMethods metódusát, amely egy Method tömböt ad vissza. A függvény csak a publikus metódusokat téríti vissza, mégpedig az alaposztályoktól felfele, a legutolsó pozíciókon magának az osztálynak a metódusai szerepelnek.

A getDeclaredMethods függvény viszont már érdekesebb eredményt ad: az osztály összes metódusát visszatéríti, függetlenül a láthatósági megszorításokra. Viszont ez a függvény csak a megadott osztálynak a függvényeit sorolja fel, az alaposztályokat figyelmen kívül hagyja.

A Method osztálynak rengeteg érdekes függvénye van, viszont ezeknek a leírása mind megtalálható a JAVA API –ban, ezért most már csak az érdekesebbeket fogom bemutatni. Például a getParameterTypes visszad egy Class[] –t, és amint a neve is mondja, a tömbbe az osztály paramétertípusai kerülnek. A getReturnType() egy árva Class –t ad vissza, ami az osztály visszatérési típusát  jelenti. A getModifiers egy int értéket ad vissza, amit a Modifier osztály statikus isXXX metódusaival ki tudunk kódolni.

Ami igazán érdekes, az az, hogy miként lehet meghívni egy osztály privát függvényeit. Elsősorban szükségünk lesz egy objektumra az említett osztályból, ezt a múlt számban bemutatott technikával percek alatt létre tudjuk hozni.

Miután rendelkezünk egy objektummal, használjuk a Method osztály invoke függvényét, mely első paraméter gyanánt az objektumot várja el, a második paraméter pedig legyen egy Object tömb (Object[]), mely az átadandó paramétereket fogja képviselni. Következzen a példa:

import java.lang.reflect.*;

 

class Test {

private String a;

      public Test(String arg1, int arg2) {

            System.out.println("Test Class constructor:"+arg1+" "+arg2);

            a = arg1+":"+arg2;

      }

     

      private void testMethodPrivate(String par) {

            System.out.println("Inside private method:"+par+" a="+a);

      }

     

      public void testMethodPublic(String par) {

            System.out.println("Inside public method:"+par+" a="+a);

            testMethodPrivate(par);

      }

}

 

public class Default {

      public static void main(String[] args) {

            try {

                  Class test = Class.forName("Test");

                  Constructor cons[] = test.getDeclaredConstructors();

                  String a = "Hello";

                  Object[] paras = {a, new Integer(2)};

                  Test testClass = (Test)(cons[0].newInstance(paras));

                  Method[] methods = test.getDeclaredMethods();

                  for(int i=0;i<methods.length;i++) {

                        methods[i].setAccessible(true);

                        System.out.println(methods[i].getName());

                        methods[i].invoke(testClass,new Object[]{a});

                  }

            }

            catch(Exception ex) {

                  ex.printStackTrace();

            }

      }

}

Tehát mint látjuk, ez a múlt havi számunkból már ismerős program "továbbfejlesztése".  Figyeljünk a methods[i].setAcessible(true) –ra, ha oda azt rakjuk, hogy false, akkor szép IllegalAccessException –nal elszáll a programunk. Vigyázzunk ezzel a metódussal, nagyon "veszélyes" dolgokat tudunk művelni vele. A következő (és egyben befejező számban) a kimaradt részeket fogjuk megtárgyalni, mint az osztályváltozók, illetve kevés betekintést kapunk a java.security csomagba.

Deák Ferenc