30 Mart 2015 Pazartesi

Reflection

Reflection ve Encapsulation
Reflection encapsulation'ın bir noktaya kadar bozulmasına sebep olabilir. Ancak birim testi gibi yerlerde bu tür kabiliyetler çok faydalı oluyor.
 
Java Reflection Notları

Java reflection ile ilgili olarak Hibernate,JPA ve Default Constructor başlıklı yazıya göz atabilirsiniz.

Java'da reflection için iki önemli paket var. Bunlar java.lang.reflect ve java.beans paketleri.

java.lang.reflect sınıfları
Java'daki reflection işlerini yapan en önemli sınıflar Class, Method.

java.beans paketindeki sınıflar
Introspector, PropertyDescriptor, BeanInfo

Class Sınıfı ile kullanılabilen metodlar
Oracle örneği burada.

Bu sınıftaki metodların isimleri yerine getirdikleri işlevi yansıtıyor. getDeclared...() şeklindeki metodlar, public olan veya olmayan bilgiye erişebilir. get...() ile başlayan metodlar ismi veya imzası verilen public bilgiye erişebilir. get...s() şeklindeki çoğul metodlar ise public olan veya olmayan bilgiye bir array şeklinde erişebilir.

isArray
Sınıfın array olup olmadığını döndürür. Örnek'te Object o array ise, dizi üzerinde yürüme işlemi gerçekleştiriliyor.

if (o != null && o.getClass().isArray()) {
  Object[] temp (Object[] o)
  for (Object each : temp) {  
    System.out.println(each);
  }
}
isAssignableFrom
Bu metod Parametre olarak verilen nesnenin/sınıfın diğer sınıfın altsınıfı veya kendisi olup olmadığını döner. Type erasure'dan dolayı reflection içinde bazen kullanmak gerekir. Örnek:
myClass.isAssignableFrom(obj.getClass())

forName
Bu metod "fully qualied" yani tam ismiyle verilen sınıfı yaratabilmemizi sağlar. Eğer yaratılmak istenen sınıfın ismi eksik verilirse, ClassNotFoundException atar.

getConstructor - verilen imzaya sahip public constructor'a erişir

Bu metod ile sınıfın belli bir imzaya sahip veya default constructor metodunu bulup o sınıfı yaratmak mümkün.

MyPanel extends Panel{
    public MyPanel (String id){
        super (id);
    }
}

Class<? extends Panel> c = MyPanel.class;
//Panel constructor'ını bul
Constructor<? extends Panel> ctor = c.getConstructor(String.class);
//Paneli yarat
Panel panel = ctor.newInstance(panelId);
getConstructors
Örnek:
Constructor<?>[] array = c.getConstructors();
for (Constructor ctr : mbrs) {
 out.format("  %s%n", ctr.toGenericString());
}

getDeclaredConstructor - verilen imzaya sahip public olan veya olmayan constructor'a erişir

Bu metod ile bir sınıfın public olan veya olmayan tüm constructorlarına erişilebilir. Örneği buradan aldım.

getDeclaredClasses
Sınıfın içinde nested olarak tanımlanmış diğer sınıflara erişmek için kullanılır.
Örnekte Foo sınıfı içindeki A, B ve C sınıflarına erişiliyor.
public class Demo {
public static void main(String[] args) {
    Class foo = Foo.class;
    Class[] declaredClasses = foo.getDeclaredClasses();
    for (Class class1 : declaredClasses) {
        System.out.println(Modifier.isStatic(class1.getModifiers()));
    }
}
}

class Foo {
    static class A {}
    class B {}
    static class C {}
}


getDeclaredField - Verilen isme sahip public olan veya olmayan Field'a erişir
Konuyu Reflection ile Fieldlara erişmek başlıklı yazıya taşıdım.

getField - Verilen isme sahip public Field'a erişir
Konuyu Reflection ile Fieldlara erişmek başlıklı yazıya taşıdım.

getFields - Tüm field'lara erişir
Konuyu Reflection ile Fieldlara erişmek başlıklı yazıya taşıdım.

getDeclaredMethod - Verilen isme sahip public olan veya olmayan  Method'a erişir
Konuyu Reflection ile Metod çağırmak başlıklı yazıya taşıdım.

getMethod -  Verilen isme sahip public Method'a erişir
Konuyu Reflection ile Metod çağırmak başlıklı yazıya taşıdım.

getPackage - Sınıfın paketine erişilir
Örnek:
Class<?> c = Class.forName("fully qualified name");
Package p = c.getPackage();
out.format("Package:%n  %s%n%n",(p != null ? p.getName() : "-- No Package --"));
Yan not olarak Java'da "Package Visible" denilen bir kavram var. Eğer bir sınıfın başına modifier konulmazsa, sadece paket içinden kullanılabilir.

newInstance
Konuyu Reflection ile Nesne Yaratmak başlıklı yazıya taşıdım.

Method sınıfı 
getName
Metodun ismini döner

getDeclaringClass
Metodun hangi sınıfta tanımlandığını belirtir.

getGenericParameterTypes
Metodun generic parametresi vars dizi şeklinde döner. Örnek:

invoke - parametre almayan bir metodu çağırma örneği
 
Örnek: Örnekte metodun parametre almadığını belirtmek için variable argument olarak hiç bir şey geçilmiyor.

setAccessable - parametre almayan ve public olmayan bir metodu çağırma örneği


Örneği buradan aldım.Örnekte metodun parametre almadığını belirtmek için boş bir array kullanılıyor. setAccessable ile private metodların güvenliğinin tehlikeye atıl atılmadığı ise burada konuşulmuş.
//no paramater
Class noparams[] = {};

//load the class at runtime
Class targetClass = Class.forName("com.reflection.Test");
Object obj = targetClass.newInstance();
      
Method method = targetClass.getDeclaredMethod("testMethod",noparams);

//Set accessible provide a way to access private methods too
method.setAccessible(true);

//call the  method
method.invoke(obj, null);

Introspector sınıfı ile kullanılabilen metodlar
 
java.beans.Introspector.getBeanInfo
Bu metod ile verilen bean ve üst sınıfları ile reflection kullanmak çok daha kolay. Örnek:

AnnotatedElement arayüzü ile kullanılabilen metodlar
java.lang.reflectAnnotatedElement.isAnnotationPresent metodu bir Field ve Method ile anotasyon varmı diye kontrol etmeye yarar. Örnek:
public class SamplePojo {
    @Column(name="User_Id")
    int id;
}
Class outputClass = SamplePojo.class;
Field[] fields = outputClass.getDeclaredFields();
for (Field field : fields) {
    if (field.isAnnotationPresent(Column.class)) {
        //Do something...
    }
}
Apache Commons Reflection Notları
Apache Commons bir çok kullanması kolay sını sunuyor.
BeanComparator Sınıfı
Bu sınıfı kullanarak, reflection ile nesneleri sıralamak mümkün. Örnek:
new BeanComparator("name");//artan sıralama
new BeanCompartor("name", Collections.reverseOrder());//azalan sıralama

BeanUtils Sınıfı
BeanUtils yazısına taşıdım.

MethodUtils Sınıfı
invokeMethod
Reflection ile bir nesnenin metodunu çağırmak mümkün. 
Örnek:
Parametre almayan bir metodu çağırmak için.

PropertyUtils
Verilen property alanına getter/setter metodları ile erişir.
copyProperties
Bu metod ile bir bean'in property'leri diğerine kopyalanır.

getProperty
Bu metod dot notation şeklinde kullanıma izin veriyor sanıyorum.

setProperty
PropertyUtils.setProperty(beanObject, property, value.trim());
şeklinde kullanılabilir.

Apache Commons Byte Code Engineering Library (BCEL)
ClassParser sınıfı
Örnek:

ClassParser parser=new ClassParser(getClass().getResourceAsStream("/my/package/MyClass.class"), "MyClass.class");
JavaClass javaClass=parser.parse();
javaClass.getMethods(); // Get whatever info you need

C# Reflection Notları
Activator Sınıfı
Bu sınıf ile verilen tipte nesne yaratmak mümkün.
CreateInstance metodu
Konuyu Reflection ile Nesne Yaratmak başlıklı yazıya taşıdım.

Assembly
Bu sınıf ta Activator gibi nesne yaratabiliyor.

CreateInstance metodu
Konuyu Reflection ile Nesne Yaratmak başlıklı yazıya taşıdım.

Dynamic Method
Dinamik olarak bir metod yaratabilme yeteneğini sağlar. Örnek:

FieldInfo
Konuyu Reflection ile Fieldlara erişmek başlıklı yazıya taşıdım.

MethodInfo Sınıfı
Konuyu Reflection ile Metod çağırmak başlıklı yazıya taşıdım.
 
Type Sınıfı
Type sınıfı Java'daki Object.getClass() ile elde edilen sınıfa denk geliyor.
 
typeof()
Type sınıfı typeof() veya Type.GetType() metodları ile elde ediliyor.

GetGenericArguments
Aşağıdaki kodda generic parametrenin adı öğrenilebiliyor.
List myObj = new List<Data>();
myObj.GetType().GetGenericArguments()[0].Name;
 

 
GetProperty - İsim ile bir PropertyInfo sınıfı bulmaya yarar
Bu metod ile ismi bilinen bir property bulunabilir.

GetProperties
Bu metod ile tüm property'ler sizi şeklinde alınabilir. Örnek:
IsAssignableFrom
Bir sınıfın başka sınıftan türeyip türemediğini belirtir. Örnek'te baseType sınıfından türeyen sınıfların isimleri bulunuyor.
var names = assembly.GetTypes().Where(t => baseType.IsAssignableFrom(t)).Select(t => t.Name);

Örnek
Console.WriteLine(typeof(IEnumerable).IsAssignableFrom(typeof(List<int>)));//True
Console.WriteLine(typeof(List<int>).IsAssignableFrom(typeof(IEnumerable)));//False
isAssignableTo
Örnek
if(something.GetType().IsAssignableTo<IEnumerable>())
    throw;
 
IsGenericType
Sorgulanan sınıfın generic olup olmadığını belirtir.

IsValueType
Sorgulanan sınıfın struct gibi value tipi mi yoksa class gibi referans tipi mi olduğunu belirtir.

Namespace
Verilen tipin hangi namespace içinde olduğunu string olarak döndürür. Örnek:
if (type.Namespace == "My.Fun.Namespace"){...}
PropertyInfo Sınıfı
Bu sınıf Java'daki PropertyDescriptor sınıfına benziyor. 

GetValue
Örnek:


 
Win32 Reflection Notları
Konuyu POSIX ve Shared Object API'si başlıklı yazıya taşıdım.

Linux Reflection Notları
Konuyu POSIX ve Shared Object API'si başlıklı yazıya taşıdım.

C++ Reflection Notları
C++ ile tabiki reflection gelmiyor. Ancak işimizi kolaylaştıracak ve reflection'ı andıran bir güzel kullanımı not etmek istedim. Her sınıfa eşi olmayan bir numara vererek bu sınıfı bir hasmap'te saklayabiliriz. Örnek:
Önce bir arayüz atanımlanır. Daha sonra bu arayüzü gerçekleştiren ve statik bir alan ekleyen bir macro kendi sınıfımızın header dosyasına eklenir. Yine sınıfımızın cpp dosyasına sayaca değer atacak bir başka macro eklenir.

class MyInterface{
virtual int getID() = 0;
};

class MyClass : public MyInterface{
COMPONENT(); //Arayüzü gerçekleştiren macro

SET_ID(MyClass); //cpp dosyasındaki sayaçtan yeni değeri alan macro

#define  COMPONENT()\
static int ID;\//Statik değişken tanımla
int getID(){return ID};//Arayüzü gerçekleştir

#define SET_ID(Component)\
int Component::ID = GetNextID();//GetNextID sayaçtan gelen yeni sayı

SCRIPTING
Java
Java'da scripting JSR-223 ile yapılıyor.
ScriptEngineManager
Bu sınıf classpath içindeki tüm script engine sınıflarını yönetir.

getEngineByName
İsmi verilen ScriptEngine sınıfını döndürür. Örnek:
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine e = sem.getEngineByName("ECMAScript");

getEngineFactories
ScriptEngineFactory sınıflarının listesini döner.

ScriptEngine sınıfı
Bu sınıfı verilen script'i çalıştırır.
eval
C#

Reflection ile tam alakası olmasa da bu yazıya eklemek mantıklı geldi. Buradaki sorudan yola çıkarak aşağıdaki örnekte kod çalıştırma gösteriliyor.

25 Mart 2015 Çarşamba

GoF - Memento Örüntüsü - Belki Snapshot Denilebilir

Giriş
Memento kelime anlamı olarak "hatıra/yadigar" manasına geliyor. İngilizce anlamı şöyle
an object that you keep to remember a person, place, or event
Yazılım dünyasında Memento örüntüsü, bir nesnenin iç verisini bilmeden, nesnenin belli bir andaki halini saklayabilmemiz sağlar. Böylece istenilen bir anda, geriye dönebiliriz. Bu tasarım örüntüsü undo veya rollback işlemlerinde kullanılır.

Undo Framework
QT Undo Framework için Memento yerine Command örüntüsünü kullanmış. Memento sınıfı yerine QUndoCommand, Caretaker sınıfı yerine QUndoStack nesnesi kullanılmış.

Örüntüdeki nesneler ve görevleri
- Originator undo veya restore edilmesi gereken domain nesnedir. Memento parametresi alan save() ve restore() metodları sunar.
- Memento ise Originator'ın verisini saklar.
- Caretaker nesnesi Memento'ların listesini saklar.

Şeklen şöyle


Bazı notlar şöyle
- We can make Memento Design Pattern implementation more generic by using Serialization; that will eliminate the requirement of every class having its own Memento class.
- The Memento Design Pattern can also be used with the Command Design Pattern for achieving undo of the commands.
Java
Örnek
Originator şöyle tanımlanır
public class Employee {
  ...    
  public EmployeeMemento createMemento() {
    return new EmployeeMemento(empId, name, designation, salary, department, project);
  }
  public void restore(EmployeeMemento memento) {
    this.empId = memento.empId;
    ...
  }
}
Memento nesnesi sadece veriyi saklar
public class EmployeeMemento {
  ...
  public EmployeeMemento(int empId, String name, String designation, long salary,...) {
    ...
  }
}
Caretake sadece Memento listelerini saklarr
public class EmployeeCaretaker {
  protected Map<Integer, Map<String, EmployeeMemento>> mementoHistory = ...;
  public void addMemento(int empId, String mementoMessage, EmployeeMemento memento) {
    ...
  }
  public EmployeeMemento getMemento(int empId, String mementoMessage) {
    ...
  }
}
Kullanmak için şöyle yaparız
public static void main(String[] args) {
  EmployeeCaretaker caretaker = ...
  Employee rachel = ...
  Employee michael = ...

  //Save
  EmployeeMemento rachelMemento = rachel.createMemento();
  EmployeeMemento michaelMemento = michael.createMemento();
  caretaker.addMemento(racheal.getEmpId(), "...", rachelMemento);
  caretaker.addMementomichael.getEmpId(), "...", michaelMemento);
  
  //Update domain objects
  rachel .setDesignation("Manager").setSalary(120000);
  michael.setProject("Android App");

  //Get saved snapshots
  rachelMemento = caretaker.getMemento(rachel.getEmpId(),"...");
  michaelMemento = caretaker.getMemento(micheal.getEmpId(), "...");

  //Restore
  rachel.restore(rachelMemento);
  michael.restore(michaelMemento);
}
Örnek
Bir projede her Originator için farklı bir Memento sınıfı yazmak yerine şöyle yaptım. Böylece her Originator'a createMemento(), restoreMemento() gibi bir şey yazmaya da gerek kalmadı. Her takeSpanshot() işleminde Memento nesnesi bir isim listede saklandı.
Memento memento = new Memento();
try(ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
    GZIPOutputStream zos = new GZIPOutputStream(baos);
    ObjectOutputStream os = new ObjectOutputStream (zos);
  ) {
    foo.serialize(os);
    bar.seriazlie(os);

    os.close();

    memento.setData(baos.toByteArray();
}  

try(ByteArrayInputStream bais = new ByteArrayInputStream (memento.getData());
    GZIPInputStream zis = new GZIPInputStream(bais);
    ObjectInputStream is = new ObjectInputStream (zis);
  ) {
    Foo foo = (Foo)is.readObject();
    Bar bar = (Bar)is.readObject();

}
Örnek
Originator ve Memento bazen içiçe (nested) sınıflar şeklinde tanımlanırlar.Originator sınıfının save ve restore metodları bulunur. Memento sınıfı Java gibi dillerde verinin deep copy'si ile çalışmalıdır. Bu yüzdenveri clone'lanır. Örnekte Clone kütüphanesi kullanılıyor.
public class Originator {
  private String state;
  private Integer code;
  private Map<String, String> parameters;

  public Memento save() {
    return new Memento(this);
  }

  public void restore(Memento memento) {
    this.state = memento.getState();
    this.code = memento.getCode();
    this.parameters = memento.getParameters();
  }

  /**
   * We use Memento class for making a snapshot of Originator state.
   */
  public class Memento {
    private String state;
    private Integer code;
    private Map<String, String> parameters;

    public Memento(Originator o) {
      Cloner cloner = new Cloner();
      this.state = cloner.deepClone(o.state);
      this.code = cloner.deepClone(o.code);
      this.parameters = cloner.deepClone(o.parameters);
    }
  }
}
Caretaker basit bir liste sınıfıdır.
public class Caretaker {

  List<Originator.Memento> snapshots;

  public Caretaker() {
    this.snapshots = new ArrayList<Originator.Memento>();
  }

  public void addSnapshot(Originator.Memento memento) {
    snapshots.add(memento);
  }
    
  public Originator.Memento find(Criteria criteria, Object key) {
    //...
  }
}
Tüm örüntünün kullanılması
Originator originator = new Originator();

//Save with Memento the state of Originator
Caretaker caretaker = new Caretaker();
caretaker.addSnapshot(originator.save());

//Search with Caretaker
Originator.Memento m = caretaker.find(Criteria.ByCode, 500);

//Restore originator
originator.restore(m);