JAX RS – 02 – RESTEasy & Apache Tomcat Implementation

Merhaba Arkadaslar
Onceki bolumde JAX-RS ve RESTful kavramina giris yapmistik. Bu bolumde ornek uygulama gelistirmeye baslayacagiz.

RestEasy , JAX-RS spectlerini uygulayan/implement eden JBoss tarafindan gelistirilen bir urundur.

JAX-RS 2.0 (JSR-339) and JAX-RS 2.1 (JSR-370), are JCP specifications that provide 
a Java API for RESTful Web Services over the HTTP protocol.
RESTEasy is a portable implementation of these specifications which can run in 
any Servlet container. 

Oncelikle kurulumlari halledelim. Projemizi ayaga kaldirmak icin kullanabilecegimiz bir kac yontem vardir.

Burada inceleyecegimiz yaklasimlar ve yontemler ;

  • HttpServletDispatcher
  • HttpServletDispatcher & resteasy.servlet.mapping.prefix
  • FilterDispatcher

Setup

Bu bolumde inceleyecegimiz kurulum ;

RESTEasy JAX-RS Implementation
Apache Tomcat 9

RESTEasy icin jar’lari download etmeyelim , bunun icin Maven tabanli proje kullanacagiz.
Eclipse’te yeni bir Dynamic Web Project olusturalim ve sonrasinda Maven projesine cevirelim.

Right Click Project -> Configure -> Convert to Maven Project

convert to maven project

Add RESTEasy dependency

Sonrasinda projemize resteasy icin gerekli olan ilgili dependency tanimini ekleyelim.

pom.xml

...  
  <properties>
  	<resteasy.version>3.6.2.Final</resteasy.version>
  </properties>
  
  <dependencies>
  	<dependency>
		<groupId>org.jboss.resteasy</groupId>
		<artifactId>resteasy-jaxrs</artifactId>
		<version>${resteasy.version}</version>
	</dependency>
  </dependencies>
...

Root Resource Classes

Root Resouce Class’lar , POJO (Plain Old Java Object) yapisindaki @Path annotation’ini kullandigimiz class’lardir.

@Path("/messages")
public class RestMessageController {
...
}

Resource Root Class’lar icin varsayilan olarak her istek sonrasinda yeni bir instance/obje olusur. Constructor calisir varsa dependency’ler inject edilir sonrasinda ilgili/uygun metot calisir istek tamamlandiktan sonra obje garbage collector tarafindan temizlenmeye uygun hale gelir.

Root Resource Class’larin objesi, JAX-RS tarafindan calisma zamaninda/runtime olusturulur. Root Resource Class’lar icin mutlaka public constructor tanimli olmalidir.
Hatirlayacagimiz gibi Java’da her class icin otomatik olarak no-arg default constructor tanimlanir. Eger biz kendimiz bir constructor tanimlarsak Java bizim icin otomatik Constructor tanimlamaz.

Resource Methods

Resource method’lar , Resource Root Class’larda tanimladigimiz istekleri karsilayan (handle request) metotlardir.
HTTP methodlarina karsilik olarak ilgili annotation’lari alabilir.

  • @GET
  • @POST
  • @PUT
  • @DELETE
  • @HEAD
  • @OPTIONS
  1. Resource Method’lar public olmalidir.
  2. Resource Method’lar checked ya da unchecked exception firlatabilir (throws)
  3. Resource Method’larin donus tipi void , Response , GenericEntity ya da diger Java tipleri olabilir.

RESTful Controller

Projemize dependency tanimini ekledikten sonra yeni bir package olusturup , RESTful Controller sinifimizi yazalim.
Ornegimiz son derece basit ve kisa olacak.

@javax.ws.rs.Path annotation’ini Spring MVC’deki @RequestMapping gibi dusunebiliriz.
/messages ilgili sinif , /messages/message ilgili metod ile eslecektir.

@javax.ws.rs.Path annotation ile bu sinifin JAX-RS service’i oldugunu belirtiyoruz.

HTTP GET istegi kullanacagimiz icin @GET annotation’ini kullaniyoruz.
Metodumuz geriye java.lang.String tipinde basit bir message donmektedir.

RestMessageController.java

package controller;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/messages")
public class RestMessageController {

	@GET
	@Path("/message")
	public String getMessage() {

		String message = "Welcome to injavawetrust.com RESTEasy Tutorial !";
		return message;

	}
}

Register Application

RESTEasy uygulamamiz icin yapmamiz gereken bir baska konfigurasyon vardir. Yeni bir sinif tanimlayip javax.ws.rs.core.Application sinifini extends edelim.

Kodu inceleyecek olursak Set<Object> tipinde bir instance variable tanimliyoruz ve constructor/yapilandiricida yeni bir RestMessageController tipinde obje olusturup bu Set’e ekliyoruz. Burada sadece bir tane RESTful controller sinifimiz RestMessageController , baska bir sinif daha olsaydi onu da eklememiz gerekliydi.

getSingletons metodunu override edelim ve geriye bu Set<Object> ‘i donelim. Boylece RESTful Controller siniflarimizi register/kaydettik.

JAX-RS service’leri (RestMessageController) , singleton ya da per-request object olabilir.
Yani butun HTTP isteklerine karsilik sadece bir tane ilgili service sinifi objesi olusur ya da her request sonrasi yeni bir service sinifi objesi olusur.

per-request object yaklasimi kullanilacaksa getClasses() metodu override edilmelidir.

package service;


import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;

import controller.RestMessageController;

public class RegisterApplication extends Application{

     private Set<Object> singletons = new HashSet<Object>();
     
     public RegisterApplication() {
        singletons.add(new RestMessageController());
     }
     
     @Override
     public Set<Object> getSingletons() {
        return singletons;
     }
}

Deployment Descriptor

Deployment Descriptor (web.xml) dosyamizda bir servlet tanimi yapacagiz.
<servlet-class> olarak org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher sinifini veriyoruz.

Isminden de belli oldugu uzere bu sinif Front Controller ozelligi gosterir.
Benzer bir konfigurasyon ve yaklasim Spring MVC , JSF gibi MVC yapisindaki frameworkler icin de mevcuttur.

  • org.springframework.web.servlet.DispatcherServlet
  • javax.faces.webapp.FacesServlet

Daha sonrasinda yeni bir <init-param> tanimliyoruz.
Bu parametre ismi javax.ws.rs.core.Application ya da javax.ws.rs.Application olabilir.
<param-value> olarak da RegisterApplication sinifimizi veriyoruz.

Sonrasinda url-pattern olarak /* bilgisini veriyoruz.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
 id="WebApp_ID" version="3.1">
 
  <display-name>injavawetrust.resteasy</display-name>

    <servlet>
        <servlet-name>HttpServletDispatcher</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.core.Application</param-name>
            <param-value>service.RegisterApplication</param-value>
        </init-param>
      
        <!-- This is valid too. -->  
        <!-- 
      
         <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>service.RegisterApplication</param-value>
        </init-param>
         -->
    </servlet>
        
    <servlet-mapping>
        <servlet-name>HttpServletDispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
</web-app>

Run Application

Ornegimizi calistiralim ;

http://localhost:8080/injavawetrust.resteasy/messages/message

run resteasy

resteasy.servlet.mapping.prefix

Bir baska nokta olarak eger /* adresinden farkli olarak bir url-pattern bilgisi verirsek /resteasy/*
Bu burumda <context-param> tanimlamamiz gereklidir.

RESTEasy documentation ;
resteasy.servlet.mapping.prefix

If the url-pattern for the Resteasy servlet-mapping is not /*

NOT :  Onceki konfigurasyon ile karismasin , kod karisikligi olmasin diye projede bu XML konfigurasyonunu farkli bir dosyaya ekledim.
Bu senaryoyu test etmek icin dosya ismi web.xml olmalidir. 

web.xml / web-mapping-prefix.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">

    <display-name>injavawetrust.resteasy</display-name>

    <!-- Note: change file name web-mapping-prefix.xml to web.xml for testing-->
    
    <servlet>
        <servlet-name>HttpServletDispatcher</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.core.Application</param-name>
            <param-value>service.RegisterApplication</param-value>
        </init-param>
    </servlet>
    
    
    <servlet-mapping>
        <servlet-name>HttpServletDispatcher</servlet-name>
        <url-pattern>/resteasy/*</url-pattern>  
    </servlet-mapping>
        
        
    <!-- 

    resteasy.servlet.mapping.prefix
    If the url-pattern for the Resteasy servlet-mapping is not /*
    
    http://localhost:8080/injavawetrust.resteasy/resteasy/messages/message
     -->
    
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/resteasy</param-value>
    </context-param>
</web-app>

Ornegimizi calistiralim bu sefer Context Path olarak /resteasy ekliyoruz.

http://localhost:8080/injavawetrust.resteasy/resteasy/messages/message

run resteasy 2

FilterDispatcher

Bir baska yaklasim olarak Filter kullanabiliriz.
Yukarida belirtigim gibi benzer sekilde dosya ismi web.xml olmalidir.
Yorum satirlari seklinde ayarlamak yerine ayri dosyalara koymayi tercih ettim , boylece daha temiz bir konfigurasyon olacaktir. Test etmek icin dosya ismini web.xml yapabilirsiniz.

web.xml / web-filter-dispatcher.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
 id="WebApp_ID" version="3.1">
 
  <display-name>injavawetrust.resteasy</display-name>
    <!-- Note: change file name web-filter-dispatcher.xml to web.xml for testing-->
   <filter>
        <filter-name>FilterDispatcher</filter-name>
        <filter-class>
            org.jboss.resteasy.plugins.server.servlet.FilterDispatcher
        </filter-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>service.RegisterApplication</param-value>
        </init-param>
    </filter>

   <filter-mapping>
        <filter-name>FilterDispatcher</filter-name>
        <url-pattern>/restfilter/*</url-pattern>
    </filter-mapping>
    
        <!-- 
    
    resteasy.servlet.mapping.prefix
    If the url-pattern for the Resteasy servlet-mapping is not /*
    
    http://localhost:8080/injavawetrust.resteasy/restfilter/messages/message
     -->
    
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/restfilter</param-value>
    </context-param>
    
</web-app>

Ornegimizi calistiralim ;

http://localhost:8080/injavawetrust.resteasy/restfilter/messages/message

run resteasy 3

Kaynak/Source folder : 
injavawetrust.resteasy

Yazimi burada sonlandiriyorum.
Herkese bol Javali gunler dilerim.
Be an oracle man , import java.*;
L.Erguder

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *