Table of Contents

Springboot - 02. Daftar Anotasi Umum

Springboot

@SpringBootApplication

@SpringBootApplication adalah salah satu anotasi inti di Spring Boot yang berfungsi untuk mengatur konfigurasi utama aplikasi. Ini adalah anotasi kombinasi yang menyatukan tiga anotasi penting lainnya:

  1. @Configuration: Menunjukkan bahwa kelas ini menyediakan definisi bean untuk konteks aplikasi Spring.
  2. @EnableAutoConfiguration: Mengaktifkan konfigurasi otomatis Spring Boot, yang secara otomatis mengonfigurasi aplikasi Anda berdasarkan dependensi yang ada di classpath.
  3. @ComponentScan: Memungkinkan Spring untuk memindai paket tempat kelas ini berada, sehingga Spring dapat menemukan dan mendaftarkan semua komponen, layanan, dan bean lain.
Contoh
				
					import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MySpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

				
			
Penjelasan
  • Kode di atas menunjukkan bahwa kelas MySpringBootApplication adalah titik masuk utama aplikasi Spring Boot.
  • Dengan anotasi @SpringBootApplication, Anda tidak perlu secara manual menambahkan ketiga anotasi yang disebutkan sebelumnya.
  • Metode SpringApplication.run() digunakan untuk memulai aplikasi.
@RestController

@RestController adalah anotasi yang digunakan di Spring untuk membuat kelas menjadi controller berbasis RESTful. Ini adalah kombinasi dari dua anotasi:

  1. @Controller: Menandai kelas sebagai komponen Spring yang bertindak sebagai controller.
  2. @ResponseBody: Menunjukkan bahwa metode di dalam kelas mengembalikan data langsung ke respons HTTP dalam bentuk JSON atau format lainnya, daripada merender view seperti template HTML.
Contoh
				
					import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyRestController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, World!";
    }
}

				
			
Penjelasan
  • Dalam contoh di atas, anotasi @RestController membuat kelas MyRestController sebagai REST controller.
  • Metode sayHello() akan menangani permintaan HTTP GET ke endpoint /hello dan mengembalikan teks “Hello, World!” sebagai respons dalam bentuk data.
  • Anda bisa menggunakan anotasi lain seperti @PostMapping, @PutMapping, atau @DeleteMapping untuk menangani jenis permintaan HTTP yang berbeda.

Dengan @RestController, Anda dapat dengan mudah membangun layanan web RESTful tanpa harus secara eksplisit menyebutkan @ResponseBody di setiap metode.

@RequestMapping

@RequestMapping adalah anotasi di Spring yang digunakan untuk memetakan permintaan HTTP ke metode atau kelas tertentu dalam aplikasi. Anotasi ini sangat fleksibel dan mendukung berbagai atribut untuk menangani URL, metode HTTP, header, parameter, dan lainnya. Anda dapat menggunakan @RequestMapping di tingkat kelas atau tingkat metode.

Contoh
				
					import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class MyController {

    // Memetakan permintaan GET ke /api/hello
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String sayHello() {
        return "Hello, World!";
    }

    // Memetakan permintaan POST ke /api/greet
    @RequestMapping(value = "/greet", method = RequestMethod.POST)
    public String greet() {
        return "Greetings!";
    }
}

				
			
Penjelasan

Tingkat Kelas:

  • Pada contoh di atas, @RequestMapping(“/api”) di tingkat kelas menentukan bahwa semua endpoint dalam kelas ini akan diawali dengan /api.
  • Misalnya, jika metode memiliki value = “/hello”, maka endpoint lengkapnya adalah /api/hello.

Tingkat Metode:

  • Untuk setiap metode, Anda bisa menentukan value, method (metode HTTP seperti GET, POST, dll.), atau atribut lainnya. Contohnya:
  • value: Mendefinisikan path spesifik endpoint.
  • method: Menentukan jenis permintaan HTTP (GET, POST, PUT, DELETE, dll.).

Fitur Tambahan:

  • Anda dapat memetakan lebih dari satu path dengan array: @RequestMapping(value = {“/path1”, “/path2”}).
  • Anda juga bisa menggunakan atribut seperti params, headers, atau produces untuk memfilter permintaan.
Catatan

Meskipun @RequestMapping sangat fleksibel, dalam praktik modern Spring (Spring 4.3 ke atas), Anda lebih sering melihat anotasi yang lebih spesifik seperti:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping

Anotasi @GetMapping, @PostMapping, @PutMapping, dan @DeleteMapping adalah bagian dari Spring Framework yang diperkenalkan pada Spring 4.3. Mereka digunakan untuk memetakan jenis permintaan HTTP (GET, POST, PUT, DELETE) ke metode tertentu dalam sebuah controller. Ini merupakan cara yang lebih ringkas dan intuitif dibandingkan dengan menggunakan @RequestMapping.

Penjelasan dan Contoh

@GetMapping Digunakan untuk menangani permintaan HTTP GET, biasanya untuk mendapatkan data.

				
					import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/users")
    public String getUsers() {
        return "List of users";
    }
}

				
			

@PostMapping Digunakan untuk menangani permintaan HTTP POST, biasanya untuk membuat data baru.

				
					import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@RestController
public class MyController {

    @PostMapping("/users")
    public String createUser(@RequestBody String user) {
        return "User created: " + user;
    }
}

				
			

@PutMapping Digunakan untuk menangani permintaan HTTP PUT, biasanya untuk memperbarui data yang sudah ada.

				
					import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

@RestController
public class MyController {

    @PutMapping("/users/{id}")
    public String updateUser(@RequestBody String user, @PathVariable String id) {
        return "User updated with ID " + id + ": " + user;
    }
}

				
			

@DeleteMapping Digunakan untuk menangani permintaan HTTP DELETE, biasanya untuk menghapus data.

				
					import org.springframework.web.bind.annotation.DeleteMapping;

@RestController
public class MyController {

    @DeleteMapping("/users/{id}")
    public String deleteUser(@PathVariable String id) {
        return "User with ID " + id + " deleted";
    }
}

				
			
Keuntungan Menggunakan Anotasi Ini:
  • Lebih Ringkas: Tidak perlu secara eksplisit menyebutkan jenis metode HTTP seperti pada @RequestMapping.
  • Lebih Mudah Dibaca: Menunjukkan tujuan metode dengan lebih jelas.
  • Modern & Standar: Mencerminkan praktik terbaik dalam pengembangan Spring.

Dengan menggunakan anotasi ini, kode Anda menjadi lebih bersih dan lebih mudah dipahami.

@Autowired

@Autowired adalah anotasi di Spring Framework yang digunakan untuk menyuntikkan (inject) dependency secara otomatis ke dalam sebuah bean. Dengan menggunakan anotasi ini, Spring akan secara otomatis mencari dan menyuntikkan bean yang sesuai ke dalam properti, konstruktor, atau metode setter, sehingga mempermudah proses Dependency Injection (DI).

Injection ke Properti (Field Injection):
				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    public void serve() {
        System.out.println("Service is running...");
    }
}

@Component
public class MyController {
    @Autowired
    private MyService myService;

    public void process() {
        myService.serve();
    }
}

				
			
Injection ke Konstruktor (Constructor Injection): Direkomendasikan, karena lebih aman terhadap kemungkinan kesalahan null.
				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyController {
    private final MyService myService;

    @Autowired
    public MyController(MyService myService) {
        this.myService = myService;
    }

    public void process() {
        myService.serve();
    }
}

				
			
Injection ke Metode Setter (Setter Injection):
				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyController {
    private MyService myService;

    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    public void process() {
        myService.serve();
    }
}

				
			
Bagaimana Cara Kerjanya?
  • @Autowired menggunakan type-based injection. Artinya, Spring mencari bean dengan tipe yang cocok dalam konteks aplikasi.
  • Jika lebih dari satu bean dengan tipe yang sama ditemukan, Anda dapat menggunakan anotasi @Qualifier untuk mengidentifikasi bean tertentu.
Catatan Penting:
  • Pastikan semua kelas yang ingin di-@Autowired diberi anotasi seperti @Component, @Service, atau @Repository, sehingga Spring dapat mendaftarkannya sebagai bean.
  • Untuk menghindari masalah, gunakan Constructor Injection sebagai praktik terbaik karena membuat dependency bersifat immutable.
@Service

Anotasi @Service di Spring adalah bagian dari anotasi berbasis stereotype yang digunakan untuk menandai sebuah kelas sebagai komponen layanan (service layer). Dengan menambahkan anotasi ini, Spring secara otomatis mendaftarkan kelas tersebut sebagai bean dalam konteks aplikasi, sehingga dapat digunakan dengan fitur seperti Dependency Injection.

Fungsi :

  • Digunakan untuk menunjukkan bahwa kelas ini adalah bagian dari service layer dalam arsitektur aplikasi.
  • Menyediakan logika bisnis utama aplikasi.
  • Meningkatkan keterbacaan kode dengan menandai peran khusus kelas ini dalam aplikasi.
Contoh
				
					import org.springframework.stereotype.Service;

@Service
public class MyService {

    public String getServiceMessage() {
        return "This is a service message!";
    }
}

				
			
Penjelasan
  • Registrasi Otomatis: Dengan anotasi @Service, Spring akan mengenali kelas MyService sebagai bean.
  • Penggunaan dalam Komponen Lain: Anda dapat menyuntikkan bean ini ke dalam komponen lain seperti controller menggunakan @Autowired.

Contoh penggunaan dalam controller:

				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @Autowired
    private MyService myService;

    @GetMapping("/message")
    public String getMessage() {
        return myService.getServiceMessage();
    }
}

				
			

Perbedaan dengan @Component

@Service pada dasarnya adalah turunan dari @Component. Secara teknis, keduanya berfungsi sama dalam hal registrasi bean, tetapi @Service memberikan semantik tambahan bahwa kelas tersebut adalah bagian dari logika bisnis.

@Repository

Anotasi @Repository di Spring digunakan untuk menandai sebuah kelas sebagai komponen yang berperan sebagai repository, yaitu tempat logika akses data didefinisikan. Dengan menambahkan anotasi ini, Spring akan mengenali kelas tersebut sebagai bean dan memungkinkan penerapan fitur seperti translasi otomatis pengecualian basis data dengan Spring Data Access Exception.

Fungsi @Repository

  • Menunjukkan bahwa kelas tersebut bertanggung jawab untuk operasi CRUD (Create, Read, Update, Delete) dengan basis data.
  • Memudahkan Spring untuk menangani pengecualian basis data secara otomatis dengan menerjemahkannya menjadi pengecualian tipe Spring.
Contoh
				
					import org.springframework.stereotype.Repository;

@Repository
public class MyRepository {

    public String getDataFromDatabase() {
        // Logika untuk mengakses basis data
        return "Data dari database";
    }
}

				
			
Penggunaan dengan Spring Data JPA:

Ketika menggunakan Spring Data JPA, Anda sering tidak perlu mendefinisikan implementasi langsung karena Spring dapat secara otomatis menghasilkan metode CRUD. Contoh:

				
					import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // Tidak perlu implementasi manual untuk operasi CRUD standar
    User findByUsername(String username); // Contoh query khusus
}

				
			
Penjelasan
  • Pada contoh pertama, kelas MyRepository menggunakan logika manual untuk mengakses basis data.
  • Pada contoh kedua, UserRepository adalah interface yang memperluas JpaRepository. Spring secara otomatis menghasilkan implementasi untuk operasi CRUD standar seperti save(), findById(), dll.
  • Anda juga bisa menambahkan metode khusus seperti findByUsername().

Perbedaan dengan @Service dan @Component:

  • @Component: Generik, digunakan untuk semua jenis komponen.
  • @Service: Digunakan untuk logika bisnis.
  • @Repository: Secara spesifik digunakan untuk komponen yang berhubungan dengan akses data dan basis data.
@Component

Anotasi @Component di Spring Boot digunakan untuk mendeklarasikan sebuah kelas sebagai Spring Bean. Dengan menambahkan anotasi ini, Spring secara otomatis akan mendeteksi kelas tersebut selama proses component scanning dan mendaftarkannya dalam ApplicationContext. Ini memungkinkan kelas tersebut di-inject ke dalam komponen lain menggunakan mekanisme Dependency Injection (DI).

Contoh
				
					import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    public String getMessage() {
        return "Hello from MyComponent!";
    }
}

				
			

Dengan anotasi @Component, kelas MyComponent akan dikenali oleh Spring dan didaftarkan sebagai bean. Anda bisa menyuntikkan MyComponent ke dalam kelas lain menggunakan @Autowired:

				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    @Autowired
    private MyComponent myComponent;

    public void printMessage() {
        System.out.println(myComponent.getMessage());
    }
}

				
			
  • Spring melakukan component scanning secara otomatis berdasarkan paket tertentu yang didefinisikan dalam @SpringBootApplication atau menggunakan @ComponentScan.
  • Selama proses ini, semua kelas dengan anotasi seperti @Component, @Service, @Repository, dan @Controller didaftarkan sebagai bean.

Perbedaan dengan Anotasi Lain:

  • @Component: Umum digunakan untuk mendeklarasikan komponen generik.
  • @Service: Spesifik untuk logika bisnis.
  • @Repository: Spesifik untuk akses data dan translasi pengecualian basis data.
  • @Controller: Spesifik untuk komponen web MVC.

Anotasi @Component memberikan dasar untuk semua anotasi stereotype lainnya, menjadikannya fleksibel untuk digunakan dalam berbagai skenario.

@Configuration

Anotasi @Configuration dalam Spring Boot digunakan untuk menunjukkan bahwa sebuah kelas adalah kelas konfigurasi yang mendefinisikan satu atau lebih bean yang akan dikelola oleh Spring IoC (Inversion of Control) container. Ini adalah bagian penting dari konfigurasi berbasis Java di Spring.

Fungsi Utama @Configuration

  • Menunjukkan bahwa kelas tersebut berisi definisi bean dan konfigurasi aplikasi.
  • Berfungsi sebagai pengganti konfigurasi berbasis XML tradisional.
  • Menyediakan konteks aplikasi yang dapat dikelola Spring.
Contoh
				
					import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public MyRepository myRepository() {
        return new MyRepository();
    }
}

class MyService {
    public String serve() {
        return "Service is serving!";
    }
}

class MyRepository {
    public String getData() {
        return "Repository data retrieved!";
    }
}

				
			
Penjelasan
  1. Kelas AppConfig:
    • Diberi anotasi @Configuration, sehingga Spring mengetahui bahwa ini adalah kelas konfigurasi.
    • Spring akan memindai metode dalam kelas ini untuk mencari anotasi @Bean.
  2. Metode @Bean:
    • Setiap metode dengan anotasi @Bean digunakan untuk menghasilkan objek (bean) yang dikelola oleh Spring.
    • Bean dapat disuntikkan ke komponen lain di dalam aplikasi.
  3. Dependency Injection:
    • Objek yang didefinisikan sebagai bean dapat diinject secara otomatis ke dalam kelas yang membutuhkan.
Catatan
  • Singleton: Secara default, bean yang didefinisikan dengan @Bean adalah singleton, yang berarti hanya satu instance dari bean tersebut yang dibuat dalam konteks aplikasi.
  • Scope: Jika Anda membutuhkan instance baru setiap kali, Anda dapat mengatur scope bean menggunakan anotasi seperti @Scope.
  • Dalam aplikasi Spring Boot, anotasi @SpringBootApplication sudah mencakup anotasi @Configuration. Namun, Anda tetap dapat mendefinisikan kelas konfigurasi tambahan jika diperlukan untuk membuat bean khusus.
@Bean

Anotasi @Bean di Spring Framework digunakan untuk mendefinisikan bean secara manual dalam konteks aplikasi. Bean ini akan dikelola oleh Spring IoC (Inversion of Control) container. Dengan @Bean, Anda dapat mendeklarasikan dan mengonfigurasi bean di dalam kelas konfigurasi yang biasanya ditandai dengan @Configuration.

Fungsi Utama @Bean

  • Mendaftarkan bean secara manual: Ideal untuk bean yang memerlukan logika inisialisasi khusus atau tidak dapat dideteksi secara otomatis melalui component scanning.
  • Mengontrol pembuatan bean: Memberikan kontrol penuh untuk membuat, mengonfigurasi, dan menginisialisasi bean.
  • Menyediakan integrasi dengan library eksternal: Membuat bean dari kelas yang berasal dari library pihak ketiga.
Contoh
				
					import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

class MyService {
    public void serve() {
        System.out.println("Service is running...");
    }
}

				
			
Penjelasan
  1. Deklarasi Kelas Konfigurasi:
    • Kelas AppConfig diberi anotasi @Configuration untuk menunjukkan bahwa kelas ini berisi definisi bean.
  2. Membuat Bean dengan @Bean:
    • Metode myService() mengembalikan instance dari MyService.
    • Spring akan mengelola siklus hidup dan dependensi dari bean ini.
  3. Penggunaan Bean:
    • Bean yang dideklarasikan dengan @Bean dapat di-inject ke dalam kelas lain:
				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    private final MyService myService;

    @Autowired
    public MyComponent(MyService myService) {
        this.myService = myService;
    }

    public void execute() {
        myService.serve();
    }
}

				
			
Manfaat
  • Flexibilitas: Menggunakan @Bean memungkinkan Anda untuk menentukan logika pembuatan bean yang kompleks.
  • Kompabilitas: Cocok untuk bean yang berasal dari library eksternal yang tidak memiliki anotasi seperti @Component.
Perbedaan dengan Anotasi Lain
  • @Component, @Service, @Repository: Mengandalkan component scanning otomatis.
  • @Bean: Digunakan untuk mendeklarasikan bean secara eksplisit dengan kontrol penuh.
@EnableAutoConfiguration

Anotasi @EnableAutoConfiguration di Spring Boot adalah salah satu fitur inti yang memungkinkan Spring Boot untuk secara otomatis mengkonfigurasi aplikasi berdasarkan dependensi yang ada di classpath. Dengan anotasi ini, Spring Boot mencoba mengatur konfigurasi yang paling sesuai untuk aplikasi Anda, tanpa perlu membuat konfigurasi manual untuk setiap komponen.

Fungsi Utama

  • Mengaktifkan konfigurasi otomatis untuk komponen Spring yang sesuai, seperti pengaturan koneksi database, servlet, JPA, keamanan, dan lainnya.
  • Membebaskan pengembang dari konfigurasi manual yang kompleks, sehingga mempercepat pengembangan aplikasi.
Contoh

Secara umum, Anda tidak perlu menambahkan @EnableAutoConfiguration secara eksplisit, karena sudah termasuk dalam anotasi @SpringBootApplication:

				
					import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

				
			

Namun, jika Anda ingin menggunakan @EnableAutoConfiguration secara terpisah:

				
					import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
public class MyConfig {
    // Konfigurasi tambahan jika diperlukan
}

				
			
Cara Kerja
  1. Mekanisme Auto-Configuration:
    • Saat aplikasi dijalankan, Spring Boot memindai file META-INF/spring.factories untuk menentukan konfigurasi otomatis mana yang akan diterapkan.
    • File ini berisi daftar kelas konfigurasi otomatis yang relevan dengan dependensi Anda.
  2. Ekstensi dan Kustomisasi:
    • Anda dapat menonaktifkan auto-configuration tertentu dengan menambahkan properti di application.properties:
    • Anda juga bisa menggunakan anotasi @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) untuk menonaktifkan konfigurasi tertentu langsung di kelas.
  3. Integrasi dengan @SpringBootApplication:
    • @SpringBootApplication adalah kombinasi dari @EnableAutoConfiguration, @Configuration, dan @ComponentScan.
Manfaat
  • Memudahkan pengaturan aplikasi Spring Boot.
  • Mengurangi kebutuhan untuk konfigurasi manual.
  • Mendukung pengembangan cepat dengan pendekatan “konvensi di atas konfigurasi”.
@Qualifier

Anotasi @Qualifier di Spring Boot digunakan untuk menyelesaikan konflik bean autowiring ketika ada lebih dari satu bean dengan tipe yang sama dalam konteks aplikasi. Dengan @Qualifier, Anda dapat menentukan secara eksplisit bean mana yang harus di-inject ke dalam dependensi, sehingga menghindari ambiguitas.

Mengapa Menggunakan @Qualifier?

  • Memilih Bean Spesifik: Ketika ada banyak bean dengan tipe yang sama, Spring tidak dapat memutuskan secara otomatis bean mana yang harus digunakan.
  • Menghindari Konflik Autowiring: @Qualifier memberikan kontrol kepada pengembang untuk menentukan bean mana yang digunakan.
Contoh
				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class MyController {

    @Autowired
    @Qualifier("myServiceA")
    private MyService myService;

    public void process() {
        myService.serve();
    }
}

@Component("myServiceA")
class MyServiceA implements MyService {
    @Override
    public void serve() {
        System.out.println("Service A is running...");
    }
}

@Component("myServiceB")
class MyServiceB implements MyService {
    @Override
    public void serve() {
        System.out.println("Service B is running...");
    }
}

interface MyService {
    void serve();
}

				
			
Penjelasan
  1. Bean dengan Identitas Kustom:
    • @Component(“myServiceA”) dan @Component(“myServiceB”) memberikan nama unik pada dua implementasi dari MyService.
  2. Penggunaan @Qualifier:
    • Dalam kelas MyController, anotasi @Qualifier(“myServiceA”) memastikan bahwa bean myServiceA digunakan untuk injection.
    • Jika tidak ada @Qualifier, Spring akan memunculkan kesalahan NoUniqueBeanDefinitionException karena tidak dapat menentukan bean mana yang harus di-inject.
  3. Keuntungan:
    • Anda dapat mengelola berbagai implementasi dari tipe yang sama tanpa harus mengubah logika program.
Catatan
  • Kombinasi dengan @Primary: Anda juga dapat menggunakan @Primary untuk menandai bean default ketika tidak ada @Qualifier yang ditentukan.
  • Penggunaan di Konstruktor: Anda juga bisa menggunakan @Qualifier dalam injection berbasis konstruktor:
				
					@Autowired
public MyController(@Qualifier("myServiceA") MyService myService) {
    this.myService = myService;
}

				
			
Kesimpulan

@Qualifier memberikan fleksibilitas untuk memilih bean tertentu dalam konteks aplikasi Spring, sehingga mempermudah pengelolaan aplikasi yang memiliki implementasi atau jenis bean yang sama.

@Value

Anotasi @Value di Spring Boot digunakan untuk menyuntikkan nilai ke dalam variabel atau properti dari sumber konfigurasi, seperti file application.properties, application.yml, atau bahkan variabel lingkungan. Dengan @Value, Anda dapat menyuntikkan nilai literal atau mengikat pengaturan aplikasi ke dalam bean Anda.

Fungsi Utama @Value

  • Menyuntikkan nilai properti dari file konfigurasi (application.properties atau application.yml).
  • Menyuntikkan ekspresi SpEL (Spring Expression Language).
  • Menyuntikkan nilai default jika properti tidak tersedia.
Contoh

Contoh Pertama : Menyuntikkan Nilai Properti dari application.properties: Misalkan Anda memiliki properti berikut di file application.properties:

				
					app.name=My Spring Boot Application
app.version=1.0.0
				
			

Anda dapat menggunakan @Value untuk menyuntikkan nilai:

				
					import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppInfo {

    @Value("${app.name}")
    private String appName;

    @Value("${app.version}")
    private String appVersion;

    public void printInfo() {
        System.out.println("Application Name: " + appName);
        System.out.println("Application Version: " + appVersion);
    }
}

				
			

Contoh Ke-Dua : Menyuntikkan Nilai Default: Jika properti tidak ada di file konfigurasi, Anda bisa menetapkan nilai default menggunakan sintaks :defaultValue:

				
					@Value("${app.description:Default description}")
private String appDescription;
				
			

Jika properti app.description tidak didefinisikan, maka variabel appDescription akan berisi “Default description”.

Contoh Ke-Tiga : Menyuntikkan Nilai dari Variabel Lingkungan: Anda bisa menyuntikkan variabel lingkungan seperti berikut:

				
					@Value("${JAVA_HOME}")
private String javaHome;
				
			

Contoh Ke-Empat : Menggunakan Ekspresi SpEL: Anda juga dapat menyuntikkan nilai dengan ekspresi Spring:

				
					@Value("#{5 + 10}")
private int result;

@Value("#{'Hello ' + 'World'}")
private String greeting;

				
			
Penjelasan Tambahan
  • Format Placeholder: Properti diakses menggunakan sintaks ${propertyName}.
  • Sumber Konfigurasi: Spring Boot membaca properti dari berbagai sumber, termasuk file application.properties, file YAML, variabel lingkungan, atau argumen baris perintah.
  • Pentingnya Typing: Nilai otomatis dikonversi ke tipe variabel, seperti int, boolean, atau double, berdasarkan deklarasi variabel.
Kapan Menggunakan @Value?
  • Saat Anda ingin menyuntikkan nilai langsung dari konfigurasi aplikasi.
  • Untuk menyederhanakan pembacaan konfigurasi sederhana ke dalam bean.
@Transactional

Anotasi @Transactional di Spring digunakan untuk mengelola transaksi secara otomatis pada metode atau kelas. Dengan menggunakan anotasi ini, Anda dapat menentukan bahwa sebuah operasi (seperti operasi database) harus dieksekusi dalam kerangka transaksi, sehingga menjamin konsistensi data dan menangani skenario kegagalan dengan benar (melalui rollback).

Fungsi Utama @Transactional

  • Membungkus metode/kode dalam kerangka transaksi.
  • Melakukan commit secara otomatis jika operasi berhasil.
  • Melakukan rollback secara otomatis jika terjadi pengecualian (exception).
  • Mengelola transaksi secara deklaratif tanpa perlu kode tambahan untuk pengelolaan transaksi manual.
Contoh Penggunaan

Anotasi pada Metode:

				
					import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Transactional
    public void performTransactionalOperation() {
        // Operasi yang melibatkan banyak query ke database
        saveData();
        updateData();
        // Jika terjadi exception di sini, semua perubahan sebelumnya akan di-rollback
    }

    private void saveData() {
        // Logika penyimpanan data
    }

    private void updateData() {
        // Logika pembaruan data
    }
}

				
			

Anotasi pada Kelas:

  • Dengan menambahkan @Transactional pada kelas, semua metode dalam kelas tersebut akan diperlakukan sebagai transaksi.
				
					import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;

@Service
@Transactional
public class MyService {
    public void saveData() {
        // Logika penyimpanan data
    }

    public void updateData() {
        // Logika pembaruan data
    }
}

				
			
Penjelasan
  • Jika terjadi runtime exception, transaksi akan otomatis di-rollback.
  • Secara default, pengecualian yang diperiksa (checked exception) tidak memicu rollback. Anda dapat menyesuaikannya dengan properti rollbackFor:
				
					@Transactional(rollbackFor = Exception.class)
public void performOperation() {
    // Logika operasi
}

				
			

Properti yang Dapat Dikonfigurasi:

  • propagation: Menentukan bagaimana transaksi baru harus diperlakukan (contoh: apakah harus membuat transaksi baru, menggunakan transaksi yang ada, dll.).
    @Transactional(propagation = Propagation.REQUIRES_NEW)
  • isolation: Menentukan tingkat isolasi transaksi untuk menangani konflik antar transaksi yang bersamaan.
    @Transactional(isolation = Isolation.READ_COMMITTED)
  • timeout: Menentukan batas waktu maksimum transaksi (dalam detik).
    @Transactional(timeout = 10)
  • readOnly: Menandai transaksi hanya-baca untuk meningkatkan performa.
    @Transactional(readOnly = true)

Manfaat @Transactional:

  • Mengelola transaksi lebih mudah dengan cara deklaratif.
  • Menghindari ketidakonsistenan data dalam operasi database.
  • Menjamin rollback otomatis jika terjadi error.
@ExceptionHandler

Anotasi @ExceptionHandler di Spring digunakan untuk menangani pengecualian (exceptions) secara khusus dalam sebuah controller atau REST controller. Dengan menggunakan anotasi ini, Anda dapat menentukan metode yang akan dipanggil secara otomatis saat pengecualian tertentu terjadi selama pemrosesan permintaan.

Fungsi @ExceptionHandler

  • Menangani pengecualian tertentu yang dilempar dalam scope sebuah controller.
  • Memastikan bahwa respons yang diberikan kepada klien terformat dengan baik, bahkan ketika terjadi error.
  • Menghindari duplikasi logika penanganan error dengan mengkonsolidasikannya dalam satu tempat.
Contoh

Menggunakan di dalam Controller:

				
					import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/example")
    public String example() {
        // Mungkin terjadi exception
        if (true) {
            throw new IllegalArgumentException("Invalid argument provided!");
        }
        return "Success";
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgument(IllegalArgumentException e) {
        // Respons jika exception terjadi
        return "Error: " + e.getMessage();
    }
}

				
			

Penjelasan:

  • Ketika endpoint /example memunculkan IllegalArgumentException, metode handleIllegalArgument akan dipanggil untuk menangani error tersebut.
  • Dalam hal ini, respons berupa pesan error akan diberikan kepada klien alih-alih error stack trace bawaan.

Menggunakan di Kelas Global Controller Advice: Untuk menangani pengecualian secara global (berlaku untuk seluruh controller), Anda bisa menggunakan anotasi @ControllerAdvice:

				
					import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgument(IllegalArgumentException e) {
        return "Global Error: " + e.getMessage();
    }

    @ExceptionHandler(Exception.class)
    public String handleGenericException(Exception e) {
        return "An unexpected error occurred: " + e.getMessage();
    }
}

				
			

Penjelasan:

  • Semua pengecualian IllegalArgumentException di seluruh aplikasi akan ditangani oleh handleIllegalArgument.
  • Pengecualian generik lainnya akan ditangani oleh metode handleGenericException.
Catatan Penting

Urutan Prioritas:

  • Jika Anda memiliki metode @ExceptionHandler di controller spesifik dan global (@ControllerAdvice), maka metode di controller spesifik akan diprioritaskan.

Penerapan pada REST API:

  • Untuk REST API, Anda dapat mengembalikan respons berupa ResponseEntity untuk menyertakan status HTTP:
				
					@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgument(IllegalArgumentException e) {
    return new ResponseEntity<>("Error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
}

				
			

Penanganan Berlapis:

  • Anda dapat menetapkan beberapa pengecualian ke dalam satu metode:
				
					@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
public String handleMultipleExceptions(Exception e) {
    return "Error: " + e.getMessage();
}

				
			
Manfaat @ExceptionHandler:
  • Memberikan kontrol penuh atas bagaimana pengecualian ditangani.
  • Memastikan pengalaman pengguna tetap baik meskipun terjadi error.
  • Mendukung struktur kode yang bersih dan modular.

JPA(Java Persistence API)

@Entity

Menentukan bahwa kelas adalah suatu entitas. Anotasi ini dapat diterapkan pada Kelas, Interface dari Enums.

				
					import javax.persistence.Entity;

@Entity
public class Employee implements Serializable {
}
				
			
@Table

Menentukan tabel dalam database yang digunakan untuk memetakan suatu entitas. Pada contoh di bawah, data akan disimpan di tabel employee. Atribut nama anotasi @Table digunakan untuk menentukan nama tabel.

				
					import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "employee")
public class Employee implements Serializable {
}
				
			
@Column

Anotasi ini menentukan nama kolom pada table.

				
					import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "employee")
public class Employee implements Serializable {
  @Column(name = "fullname")
  private String employeeName;
}
				
			
@Id

Anotasi ini menentukan primary key dari sebuah entitas.

				
					import javax.persistence.*;

@Entity
@Table(name = "employee")
public class Employee implements Serializable { 
  @Id
  @Column(name = "id")
  private Long id;
}
				
			
@GeneratedValue

Anotasi @GeneratedValue digunakan untuk menentukan strategi pengisian nilai otomatis untuk kolom primary key (atau atribut ID) dalam entitas. Ini membantu memastikan bahwa setiap entitas memiliki nilai unik untuk primary key tanpa perlu memberikan nilai tersebut secara manual.

Ketika Anda menggunakan anotasi @GeneratedValue, Anda bisa menentukan strategi bagaimana nilai ID akan dihasilkan. Ada beberapa strategi yang didukung, yaitu:

  • GenerationType.AUTO (Default): JPA secara otomatis memilih strategi yang dianggap paling sesuai berdasarkan database yang digunakan.
  • GenerationType.IDENTITY: Database bertanggung jawab untuk menghasilkan nilai ID, misalnya menggunakan kolom dengan sifat auto-increment.
  • GenerationType.SEQUENCE: Menggunakan sequence yang dikelola oleh database untuk menghasilkan nilai ID.
  • GenerationType.TABLE: Menggunakan tabel khusus di database untuk menghasilkan nilai ID (jarang digunakan karena performa lebih lambat dibanding strategi lain).
				
					@Entity
@Table(name = "employee")
public class Employee implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Strategi IDENTITY
    private Long id;
    private String fullname;

    // Getter dan Setter
}

				
			
@Version

Anotasi @Version digunakan untuk mendukung optimistic locking dalam aplikasi yang berinteraksi dengan database. Optimistic locking adalah mekanisme untuk mencegah konflik data selama operasi pembaruan atau penghapusan, terutama dalam lingkungan dengan banyak pengguna atau transaksi.

  • Cara Kerja @Version:
    Anotasi ini digunakan pada atribut entitas yang bertindak sebagai versi dari entitas tersebut. Atribut ini biasanya berupa tipe seperti int, long, atau java.util.Date.
  • Setiap kali entitas diperbarui, nilai atribut yang diberi anotasi @Version akan bertambah.
  • Ketika JPA melakukan update, ia memeriksa nilai versi saat ini di database. Jika nilai versi sudah berubah (misalnya karena ada update lain), maka JPA akan membatalkan operasi dan melemparkan OptimisticLockException.
				
					@Entity
@Table(name = "employee")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String fullname;
    private double height;

    @Version
    private int version; // Menyimpan versi entitas

    // Getter dan Setter
}

				
			

Dalam contoh di atas:

  • Atribut version akan otomatis bertambah setiap kali entitas diperbarui.
  • Ini membantu memastikan bahwa pembaruan data dilakukan dengan aman tanpa menimpa perubahan yang dibuat oleh transaksi lain.

Keuntungan @Version:

  • Keamanan Data: Mencegah konflik saat beberapa pengguna mengakses dan memperbarui data yang sama.
  • Efisiensi: Tidak membutuhkan penguncian fisik di level database, sehingga performa aplikasi tetap optimal.
@OrderBy

Anotasi ini digunakan untuk menentukan urutan data berdaskan suatu kolom. Pada contoh di bawah ini, ini akan mengurutkan semua employee_addresses berdasarkan id mereka dalam urutan menaik

				
					@OrderBy("id asc")
private Set employee_addresses;
				
			
@Transient

Anotasi yang digunakan untuk menunjukkan bahwa suatu kolom atau bidang tidak perlu disimpan dalam database. Dengan kata lain, kolom atau bidang ini akan diabaikan saat operasi penyimpanan dan pengambilan entitas dari database

				
					@Transient
Private int employeePhone;
				
			
@Lob

Anotasi @Lob digunakan untuk menunjukkan bahwa atribut entitas yang dianotasi mewakili tipe objek besar (Large Object). LOB (Large Object) adalah tipe data variabel panjang yang digunakan untuk menyimpan objek besar seperti teks atau data biner. Ada dua jenis utama LOB:

  1. CLOB (Character Large Object): Digunakan untuk menyimpan data teks besar.
  2. BLOB (Binary Large Object): Digunakan untuk menyimpan data biner seperti gambar, audio, atau video2.
				
					@Entity
public class FileEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Lob
    private byte[] data; // Menyimpan data biner sebagai BLOB

    // Getter dan Setter
}

				
			
@OneToOne

Anotasi @OneToOne digunakan untuk mendefinisikan hubungan satu-ke-satu (one-to-one) antara dua entitas. Artinya, setiap instance dari satu entitas hanya dapat berhubungan dengan satu instance dari entitas lain, dan sebaliknya.

Anotasi ini membantu Anda memetakan relasi yang erat antara dua tabel di database menjadi model objek dalam aplikasi. Hal ini umum digunakan dalam kasus seperti:

  • Setiap User memiliki satu Profile.
				
					@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "profile_id", referencedColumnName = "id")
    private Profile profile;
    
    //Jika ingin menggunakan id yang sama
    //@OneToOne(cascade = CascadeType.MERGE)
    //@PrimaryKeyJoinColumn
    //private Profile profile;

    // Getter dan Setter
}

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String bio;

    private String avatar;

    // Getter dan Setter
}

				
			

Penjelasan pada Contoh:

  1. @OneToOne: Menunjukkan bahwa hubungan antara entitas User dan Profile adalah hubungan satu-ke-satu.
  2. @JoinColumn: Menentukan kolom di tabel database yang digunakan untuk menyimpan relasi (contoh: kolom profile_id dalam tabel User).
  3. cascade = CascadeType.ALL: Memastikan bahwa perubahan pada entitas User (seperti menyimpan atau menghapus) juga akan memengaruhi entitas Profile.

Keuntungan Menggunakan Relation:

  1. Meningkatkan keterbacaan dan modularitas kode dengan memodelkan relasi database dalam bentuk objek.
  2. Mendukung operasi CRUD relasional secara otomatis tanpa memerlukan banyak kueri SQL manual.
@OneToMany

Penggunaan @OneToMany dalam JPA membantu membangun hubungan “satu ke banyak” antara dua entitas dalam aplikasi Anda. Anotasi ini sangat berguna untuk memodelkan hubungan database yang kompleks dalam kode Java.

Entitas One
				
					@Entity
public class Kelas {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String nama;

    @OneToMany(mappedBy = "kelas", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Siswa> siswaList = new ArrayList<>();

    // Getter, Setter, Constructor, dll.
}

				
			
Entitas Many
				
					@Entity
public class Siswa {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String nama;

    @ManyToOne
    @JoinColumn(name = "kelas_id")
    private Kelas kelas;

    // Getter, Setter, Constructor, dll.
}

				
			
Penjelasan
  • mappedBy: Properti ini digunakan pada @OneToMany untuk menentukan bahwa hubungan ini dikendalikan oleh entitas Siswa (mengacu pada properti kelas).
  • cascade: Digunakan untuk menentukan tindakan seperti persist, merge, dan remove yang akan diterapkan pada entitas terkait.
  • orphanRemoval: Menghapus entitas Siswa dari database jika dihapus dari daftar siswaList pada Kelas.
Penggunaan
  • Menyimpan Data: Saat menyimpan Kelas beserta daftar Siswa, Anda hanya perlu menyimpan entitas Kelas, dan semua entitas Siswa yang ada di dalam daftar akan tersimpan otomatis (jika CascadeType.PERSIST aktif).
  • Menghapus Data: Jika Anda menghapus suatu Siswa dari siswaList pada Kelas, maka JPA akan otomatis menghapus entitas Siswa dari database (jika orphanRemoval diatur ke true).
Query dengan JPA

Anda juga dapat menggunakan JPQL atau Criteria API untuk melakukan query terhadap hubungan ini. Contoh sederhana:

				
					List<Siswa> siswaList = entityManager
    .createQuery("SELECT s FROM Siswa s WHERE s.kelas.id = :kelasId", Siswa.class)
    .setParameter("kelasId", 1L)
    .getResultList();

				
			
@ManyToMany

Anotasi @ManyToMany dalam JPA digunakan untuk mendefinisikan hubungan “banyak ke banyak” antara dua entitas. Hubungan ini terjadi ketika banyak entitas pada satu sisi terhubung dengan banyak entitas pada sisi lainnya. Contoh kasusnya adalah hubungan antara Mahasiswa dan MataKuliah, di mana seorang mahasiswa bisa mengambil banyak mata kuliah, dan satu mata kuliah bisa diikuti oleh banyak mahasiswa.

Contoh :
  1. Entitas “Mahasiswa”: Entitas yang memiliki relasi ke banyak MataKuliah.
  2. Entitas “MataKuliah”: Entitas yang memiliki relasi ke banyak Mahasiswa.
Entitas "Mahasiswa"
				
					@Entity
public class Mahasiswa {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String nama;

    @ManyToMany
    @JoinTable(
        name = "mahasiswa_matakuliah",
        joinColumns = @JoinColumn(name = "mahasiswa_id"),
        inverseJoinColumns = @JoinColumn(name = "matakuliah_id")
    )
    private List<MataKuliah> mataKuliahList = new ArrayList<>();

    // Getter, Setter, Constructor, dll.
}

				
			
Entitas "MataKuliah"
				
					@Entity
public class MataKuliah {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String nama;

    @ManyToMany(mappedBy = "mataKuliahList")
    private List<Mahasiswa> mahasiswaList = new ArrayList<>();

    // Getter, Setter, Constructor, dll.
}

				
			
Penjelasan
  • @ManyToMany: Menunjukkan bahwa entitas memiliki relasi banyak ke banyak.
  • @JoinTable: Digunakan untuk mendefinisikan tabel penghubung (join table) antara entitas. Properti joinColumns digunakan untuk menghubungkan entitas “Mahasiswa”, sedangkan inverseJoinColumns untuk menghubungkan entitas “MataKuliah”.
  • mappedBy: Digunakan pada sisi terbalik untuk menunjukkan bahwa hubungan ini sudah dikelola oleh entitas lain.
Penggunaan
  • Menyimpan Data: Anda bisa menyimpan data kedua entitas dan menambahkan relasi di tabel penghubung.
  • Menghapus Data: Saat relasi dihapus dari list, maka tabel penghubung akan diperbarui.
Manfaat
  • Memodelkan hubungan kompleks secara relasional.
  • Otomatisasi pengelolaan relasi tanpa kode SQL manual.

Lombok

@Getter

Digunakan untuk secara otomatis menghasilkan metode getter untuk semua atau beberapa bidang (fields) dalam sebuah kelas

Tingkat Kelas(Semua Kolom)
				
					import lombok.Getter;

@Getter
public class Person {
    private String name;
    private int age;

    // Lombok akan otomatis membuat metode:
    // public String getName() { return this.name; }
    // public int getAge() { return this.age; }
}

				
			
Tingkat Field(Hanya Kolom Tertentu)
				
					import lombok.Getter;

public class Car {
    @Getter
    private String brand;

    private int year; // Tidak memiliki getter karena tidak ada anotasi @Getter di bidang ini
}

				
			
@Setter

Digunakan untuk secara otomatis menghasilkan metode setter untuk bidang (fields) dalam sebuah kelas. Untuk penggunaan sama seperti @Getter untuk menggernerate fungsi setField().

@ToString

Digunakan untuk secara otomatis menghasilkan metode toString() untuk sebuah kelas. Metode ini memberikan representasi string dari objek, yang sangat berguna untuk debugging atau logging, tanpa harus menulis metode toString() secara manual.

				
					import lombok.ToString;

@ToString
//@ToString(exclude = "age") => "Person(name=John)"
public class Person {
    private String name;
    private int age;

    // Lombok akan menghasilkan metode:
    // @Override
    // public String toString() {
    //     return "Person(name=John, age=30)";
    // }
}

				
			
@EqualsAndHashCode

Digunakan untuk secara otomatis menghasilkan metode equals() dan hashCode() untuk sebuah kelas. Metode ini penting untuk membandingkan objek berdasarkan nilai atribut mereka, dan juga berguna saat menggunakan koleksi seperti HashSet atau HashMap.

				
					import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class Person {
    private String name;
    private int age;

    // Lombok akan menghasilkan metode:
    // - equals(): membandingkan atribut 'name' dan 'age'
    // - hashCode(): menghitung nilai hash berdasarkan 'name' dan 'age'
}

				
			
@AllArgsConstructor

Digunakan untuk secara otomatis menghasilkan konstruktor yang mencakup semua bidang (fields) dalam sebuah kelas. Anotasi ini sangat berguna untuk menghindari penulisan kode boilerplate konstruktur secara manual, terutama pada kelas dengan banyak atribut.

				
					import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Person {
    private String name;
    private int age;

    // Lombok akan menghasilkan:
    // public Person(String name, int age) {
    //     this.name = name;
    //     this.age = age;
    // }
}

				
			
@NoArgsConstructor

Digunakan untuk secara otomatis menghasilkan konstruktor tanpa parameter (no-args constructor) dalam sebuah kelas. Anotasi ini sangat membantu terutama untuk kelas dengan banyak bidang (fields), sehingga Anda tidak perlu menulis konstruktur tanpa parameter secara manual.

				
					import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Person {
    private String name;
    private int age;

    // Lombok akan menghasilkan:
    // public Person() {}
}

				
			
@RequiredArgsConstructor

Digunakan untuk secara otomatis menghasilkan konstruktor dengan parameter untuk semua bidang yang bersifat final atau diberi anotasi @NonNull. Hal ini membantu memastikan bahwa atribut penting diinisialisasi selama pembuatan objek.

Ketika Anda menerapkan @RequiredArgsConstructor pada sebuah kelas, Lombok akan membuat konstruktor untuk semua bidang:

  • final (tidak dapat diubah setelah diinisialisasi).
  • Beranotasi dengan @NonNull (meskipun tidak final).
				
					import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class User {
    private final String username;
    @NonNull
    private Integer age;
    private String address; // Tidak termasuk dalam konstruktor

    // Lombok akan menghasilkan:
    // public User(String username, Integer age) {
    //     this.username = username;
    //     if (age == null) {
    //         throw new NullPointerException("age is marked non-null but is null");
    //     }
    //     this.age = age;
    // }
}

				
			
@NonNull

Digunakan untuk memastikan bahwa nilai untuk suatu atribut atau parameter tidak boleh null. Jika ada upaya untuk menetapkan nilai null pada atribut atau parameter yang dianotasi dengan @NonNull, maka kode akan memunculkan NullPointerException secara otomatis. Anotasi ini sering digunakan untuk mencegah bug akibat nilai null

				
					import lombok.NonNull;

public class Person {
    @NonNull
    private String name;

    public Person(@NonNull String name) {
        this.name = name; // Akan melempar NullPointerException jika name = null
    }
}

				
			
@Data

Anotasi @Data dalam Lombok adalah solusi serbaguna yang menggabungkan beberapa anotasi Lombok lainnya untuk menghasilkan berbagai metode penting secara otomatis dalam sebuah kelas. Anotasi ini sangat ideal untuk membuat kelas sederhana seperti POJO (Plain Old Java Object), DTO (Data Transfer Object), atau model data.

Ketika Anda menggunakan @Data, Lombok akan menghasilkan:

  1. Getter: Untuk semua atribut dalam kelas.
  2. Setter: Untuk semua atribut non-final.
  3. toString(): Representasi string dari objek.
  4. equals() dan hashCode(): Untuk membandingkan objek berdasarkan nilainya.
  5. RequiredArgsConstructor: Konstruktor dengan parameter untuk semua atribut final atau beranotasi @NonNull.
				
					import lombok.Data;

@Data
public class Person {
    private String name;
    private int age;

    // Lombok akan otomatis menghasilkan metode:
    // - public String getName()
    // - public void setName(String name)
    // - public int getAge()
    // - public void setAge(int age)
    // - public String toString()
    // - public boolean equals(Object o)
    // - public int hashCode()
    // - public Person(String name, int age) [jika ada atribut final atau @NonNull]
}

				
			
Kondisi Tertentu

Bidang final dan beranotasi @NonNull akan dipaksa untuk diinisialisasi melalui konstruktor:

				
					import lombok.Data;
import lombok.NonNull;

@Data
public class Employee {
    @NonNull
    private String id;
    private String name;
    private final int age;

    // Konstruktor akan dihasilkan untuk 'id' dan 'age', karena 'id' memiliki @NonNull dan 'age' bersifat final.
}

				
			
Kombinasi dengan Anotasi Lain

Lombok mendukung kombinasi @Data dengan anotasi lain seperti:

  • @Builder: Untuk pola builder.
  • @NoArgsConstructor atau @AllArgsConstructor: Untuk menyesuaikan jenis konstruktor yang dibutuhkan.
@Value

Digunakan untuk menciptakan kelas immutable (tidak dapat diubah) yang berfungsi sebagai objek nilai (value object). Semua atribut dalam kelas yang menggunakan @Value secara otomatis menjadi final, dan kelas itu sendiri bersifat final. Anotasi ini sangat ideal untuk membuat data model yang tetap dan konsisten.

Saat Anda menggunakan @Value, Lombok akan melakukan hal berikut:

  • Menjadikan semua bidang dalam kelas bersifat final.
  • Membuat getter untuk semua bidang.
  • Menghasilkan konstruktor dengan semua argumen untuk menginisialisasi semua atribut.
  • Membuat metode toString(), equals(), dan hashCode().
  • Menjadikan kelas bersifat final, sehingga tidak dapat diwarisi (extended).
				
					import lombok.Value;

@Value
public class Person {
    String name;
    int age;

    // Lombok akan menghasilkan:
    // - Getter untuk 'name' dan 'age'
    // - Konstruktor untuk menginisialisasi 'name' dan 'age'
    // - toString(), equals(), dan hashCode()
    // - Kelas bersifat final, dan semua bidang bersifat final
}

				
			
Kombinasi dengan Builder

Anda dapat mengkombinasikan @Value dengan @Builder untuk menciptakan pola builder yang fleksibel sambil mempertahankan sifat immutable:

				
					import lombok.Value;
import lombok.Builder;

@Value
@Builder
public class Employee {
    String id;
    String name;
    int salary;
}

				
			

Dengan kombinasi ini, Anda dapat membuat objek menggunakan pendekatan builder:

				
					Employee employee = Employee.builder()
                            .id("001")
                            .name("Alice")
                            .salary(5000)
                            .build();

				
			
Manfaat
  • Immutable: Objek tidak dapat diubah setelah dibuat, menjaga integritas data.
  • Mengurangi Boilerplate: Tidak perlu menulis metode getter, konstruktor, dan lainnya secara manual.
  • Sederhana: Sangat cocok untuk DTO (Data Transfer Object) atau model data.
Catatan
  • Kelas dengan @Value otomatis tidak memiliki setter karena semua atribut bersifat final.
  • Karena kelas bersifat final, Anda tidak dapat membuat subclass.
@Builder

Digunakan untuk mengimplementasikan pola builder pada kelas atau metode. Pola ini memungkinkan Anda membuat objek secara fleksibel, dengan menyusun parameter satu per satu. Ini sangat berguna saat Anda memiliki kelas dengan banyak atribut atau parameter opsional.

Tingkat Kelas

Ketika diterapkan pada kelas, Lombok akan membuatkan kelas builder secara otomatis untuk semua atribut dalam kelas tersebut. Berikut contoh sederhana:

				
					import lombok.Builder;

@Builder
public class Person {
    private String name;
    private int age;

    // Dengan @Builder, Anda dapat membuat objek seperti ini:
    // Person person = Person.builder()
    //                        .name("John")
    //                        .age(30)
    //                        .build();
}

				
			
Dengan Konstruktor Khusus

Anda dapat mengkombinasikan @Builder dengan anotasi seperti @AllArgsConstructor atau @RequiredArgsConstructor untuk menyesuaikan bagaimana pola builder digunakan berdasarkan konstruktor Anda:

				
					import lombok.Builder;
import lombok.AllArgsConstructor;

@Builder
@AllArgsConstructor
public class Employee {
    private final String id;
    private final String name;
    private int salary;

    // Employee emp = Employee.builder()
    //                         .id("001")
    //                         .name("Alice")
    //                         .salary(5000)
    //                         .build();
}

				
			
Di Tingkat Metode

Anda juga dapat menggunakan @Builder di tingkat metode untuk membuat builder hanya untuk metode tertentu:

				
					import lombok.Builder;

public class Calculation {

    @Builder
    public static String performOperation(String operand1, String operand2, String operator) {
        return operand1 + " " + operator + " " + operand2;
    }

    // Pemanggilan:
    // String result = Calculation.builder()
    //                             .operand1("5")
    //                             .operand2("3")
    //                             .operator("+")
    //                             .build();
}

				
			
Manfaat
  • Keterbacaan Kode yang Lebih Baik: Membuat kode lebih intuitif dengan menyebutkan nama parameter.
  • Fleksibilitas: Anda dapat membuat objek tanpa harus mengatur semua atribut sekaligus.
  • Menghindari Konstruktor Kompleks: Pola builder jauh lebih mudah dimengerti dibandingkan konstruktor dengan banyak parameter.
Kombinasi dengan Anotasi Lain
  • @Value: Untuk membuat objek builder yang bersifat immutable.
  • @Getter dan @Setter: Mengelola akses ke atribut sambil menggunakan pola builder.
  • @ToString: Untuk menambahkan representasi string pada objek yang dibangun.
@Singular

Digunakan untuk mempermudah pengelolaan koleksi (collections) dalam pola builder. Dengan @Singular, Anda dapat menambahkan elemen ke dalam koleksi satu per satu atau menetapkan seluruh koleksi secara langsung saat membangun objek menggunakan builder.

Fungsi Utama @Singular
  1. Menambahkan Elemen Satu per Satu: Anda bisa menambahkan elemen ke koleksi (seperti List, Set, atau Map) satu per satu menggunakan metode yang dihasilkan oleh Lombok.
  2. Mengatur Koleksi Secara Langsung: Selain itu, Lombok memungkinkan Anda menetapkan semua elemen koleksi sekaligus.
  3. Fleksibilitas: Cocok untuk menangani koleksi dengan pendekatan yang lebih modular dan terstruktur.
Penggunaan pada List
				
					import lombok.Builder;
import lombok.Singular;

@Builder
public class Team {
    private String teamName;

    @Singular
    private List<String> members;
}

// Membuat objek:
Team team = Team.builder()
                .teamName("Development Team")
                .member("Alice")
                .member("Bob")
                .member("Charlie")
                .build();

// Hasilnya, koleksi `members` berisi ["Alice", "Bob", "Charlie"].

				
			
Penggunaan pada Set
				
					import lombok.Builder;
import lombok.Singular;

@Builder
public class Organization {
    private String orgName;

    @Singular
    private Set<String> departments;
}

// Membuat objek:
Organization org = Organization.builder()
                                .orgName("TechCorp")
                                .department("Engineering")
                                .department("Marketing")
                                .build();

				
			
Penggunaan pada Map
				
					import lombok.Builder;
import lombok.Singular;

@Builder
public class Configuration {
    @Singular
    private Map<String, String> properties;
}

// Membuat objek:
Configuration config = Configuration.builder()
                                     .property("key1", "value1")
                                     .property("key2", "value2")
                                     .build();