15 Aralık 2015 Salı

Reflection ile Nesne Yaratmak

Giriş
Java'da reflection ile nesne yaratmak için bir şekilde Class sınıfına erişip ya newInstance() metodu çağrılıyor ya da Class sınıfı aracılığıyla Constructor nesnesi bulunup nesne yaratılıyor.

Class Nasıl Bulunur ?
2 yöntem var. ClassLoader veya Class.forName() kullanılır.

1. ClassLoader - Tam İsim ile Class'ı Bulmak

Java'da Class ve ClassLoader ile sınıfları yükleyip yaratabilmek mümkün. ClassLoader'ı kullanmaya hiç ihtiyaç duymadım. Her class kendisini yükleyen ClassLoader'ı bilir.
ClassLoader cl =  t.getClass().getClassLoader();
ClassLoader arayüzünü gerçekleştiren sınıflardan birisi olan URLClassLoader aşağıdaki gibi yaratılabilir.
File file  = new File("vendorcatalogapi.jar");
URL url = file.toURI().toURL();  
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
Daha sonra ClassLoader loadClass() metodu ile Class nesnesini verir.
Class theClass = ClassLoader.loadClass("com.mycompany.SomeImpl");
2. Class.forName - Tam İsim ile Class'ı Bulmak

Class.forName() sadece class ve interface'ler için çalışır. bool gibi primitive tipler ile denersek ClassNotFounException alırız.
try {
   Class.forName( "bool" );
} 
catch( ClassNotFoundException e ) {
...
}
Tam sınıf ismi kullanan basit bir örnek
Class theClass = Class.forName("com.example.Foo");
Eğer sınıfı yüklemek istemiyor sadece var olup olmadığını öğrenmek istiyorsak şöyle yaparız.

Class.forName("com.example.Foo", 
              false, 
              ClassLoader.getSystemClassLoader());
İkinci parametrenin false olması sınıfın yüklenmesini engeller. Sınıfın static constructor metodu varsa çalışmadığını görürürüz.
public class Foo {
    static {
        System.out.println("foo loaded and initialized");
    }
}
Sınıf yoksa ClassNotFoundException alacağımız için, sınıfı yüklemeden varlığını tespit edebiliriz.
Class veya Constructor Bulunduktan Sonra
Elimizde iki seçenek var. Class sınıfının sunduğu newInstance metodunu kullanmak veya Constructor sınıfının sunduğu newInstance metodunu kullanmak.

1. Class.newInstance metodu
Class bir kere bulunduktan sonra şu kurallara uyuyorsa yeni bir nesne yaratmak çok kolay
Class.newInstance() will only succeed if the constructor is has zero arguments and is already accessible.
Yani
1. Sınıfın default constructor'a sahip olması gerekir.
2. Constructor'ın erişilebilir olması gerekir. Örneğin public olması gerekir.

Eğer hata olursa bu metod IllegalAccessException ve InstantiationException atar.

Basit bir örnek
SomeImpl impl = (SomeImpl)theClass.newInstance();
Generic Örnek
Exceptionlardan kurtulup generic bir metod kullanmak istersek aşağıdaki gibi yapabiliriz. Örnekte Parent sınıfından kalıtan sınıflar yaratılıyor. Ayrıca Java 7 ile gelen çoklu exception yakalama da gösteriliyor.

public static <T extends Parent> T load(Class<T> clazz) {
    try {
        T object = clazz.newInstance();
        return object;
    } catch (IllegalAccessException | InstantiationException e) {
        //handle the exception here...
    }
    return null;
}

2. Constructor.newInstance() metodu - Default Constructor Yoksa Kullanılabilir
Parametre Alan Constructor Örneği 1
Parametre alan constructor'a sahip bir nesne yaratmak için örnek
import java.lang.reflect.Constructor;

...

Class<?> loadedClass = classLoader.loadClass("tmp."+className);
try {
  Constructor<?> ctor=loadedClass.getConstructor(int.class);
  ctor.newInstance(42);
  ...
}
Parametre Alan Constructor Örneği 2
Bu sefer Constructor nesnesi getConstructor ile değil, getDeclaredConstructor ile bulunuyor. Elimizde şöyle bir sınıf olsun.
public Person()
{
}

public Person(int age)
{
    this.age = age;
}

public Person(int age, String name)
{
    this.age = age;
    this.name = name;
}
Şöyle yaparız.
Class<Person> pClass = Person.class;
pClass.getDeclaredConstructor().newInstance(); // default constructor
pClass.getDeclaredConstructor(int.class).newInstance(50);
pClass.getDeclaredConstructor(int.class, String.class).newInstance(50, "test");






8 Aralık 2015 Salı

ScriptEngineManager Sınıfı

Giriş
Şu satırı dahil ederiz. Bir ScriptEngine nesnesi yaratır.
import javax.script.ScriptEngineManager;
constructor
Şöyle yaparız.
ScriptEngineManager mgr = new ScriptEngineManager();
getEngineByName metodu
ScriptEngine nesnesi oluşturur. Şöyle yaparız.
ScriptEngine engine = mgr.getEngineByName("js");
Şöyle yaparız.
ScriptEngine engine = mgr.getEngineByName("JavaScript");





6 Aralık 2015 Pazar

HttpServlet Sınıfı

Giriş
Şu satırı dahil ederiz.
import javax.servlet.http.HttpServlet;
Kendi sınıfımızı yazmak istersek şöyle yaparız. Burada Serializable'dan kalıtmak isteğe bağlı.
public class MyServlet extends HttpServlet implements Serializable {
...
}
Sınıfın 3 tane önemli metodu var. Bu 3 metodun hepsi protected ve hepsi service metodu tarafından tetikleniyor.

public service metodu
Container public service metodunu çağırır. Metodun imzası şöyle
public void service(ServletRequest req,ServletResponse res)
  throws ServletException,java.io.IOException
Bu metod protected service metodunu tetikler.

protected service metodu
Görüldüğü gibi yukarıdaki ServletRequest nesnesi  HttpServletRequest nesnesine,  ServletResponse ise HttpServletResponse nesnesine dönüştürülüyor. Metodun imzası şöyle
protected void service(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException,java.io.IOException
Kendi servlet'imizi yazarsak bu metodu override ederiz. Şöyle yaparız.
@Override
protected  void service (HttpServletRequest req, HttpServletResponse resp) 
  throws ServletException, IOException {
  System.out.println(req.toString());        
}
Ancak bence bu metodu override etmek için hiçbir sebep yok. Her zaman doGet(), doPost() metodları kullanılmalı.

doGet metodu
Bu metod sadece veriyi sunucundan çekmek için kullanılmalı. Get metodu ile silme (delete) işlemi yapmak yanlıştırÖrneğin aşağıdaki html get ile delete işlemi yapıyor!
<a href="delete.php?deleteWhat=everything&deleteMode=unrecoverable">index me!</a>

Container'lar tarafından sağlanan default metodlar şöyle. Yani hata döndürüyorlar.
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
  String protocol = req.getProtocol();
  String msg = lStrings.getString("http.method_get_not_supported");
  if (protocol.endsWith("1.1")) {
    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
  } else {
    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
  }
}
Dolayısıyla doGet() metodu içinde super.doGet() yapılmamalı! Aşağıdaki kod yanlış
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException{
  super.doGet(request, response);
  ...
}
doPut metodu
Bu metod verilen resource'u saklamak için vardır. Dolayısıyla doGet() metodundaki gibi parametre geçilemiyor. Yani HttpServletRequest nesnesinden parametre alınamıyor. Aşağıdaki örnekte params'ın boyu 0 gelir.
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws {
   Map<String,String[]> params = req.getParameterMap();
   System.out.println(params.size());
}
Bir başka örnekte aynı şeyi görebiliriz.
public void doPut(HttpServletRequest request, HttpServletResponse response) {
    String name = request.getParameter("name");
    // name is null
}
Verilen resource ancak request.getInputStream() ile okunabilir.
BufferedReader br=new BufferedReader(new InputStreamReader(req.getInputStream());
String data = br.readLine();
Örnekte verilen PUT ile gönderilen json nesnesi önce stream'den okunuyor daha sonra nesneye çevriliyor.
ServletInputStream inputStream = request.getInputStream();
String string = convertStreamToString(inputStream); 
JSONObject jsonArray= new JSONObject(string);
doPost metodu
Eğer istenirse post ile get birleştirilebilir.
public void doGet(HttpServletRequest request,HttpServletResponse response)
 throws ServletException, IOException {
 // Servlet code
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
 doGet(request, response);
}
getServletContext  metodu
Bu metod ile ServletContext arayüzüne erişilebilir.
protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
  ServletContext appContext = getServletContext();
  ...
}