![تزریق خودکار](https://quera.org/qbox/view/TUr0D912sk/dependency-injection.jpg)
*ابوالفضل* مدت زیادی است که با فریمورک *Spring Boot* کار میکند. اخیراً او به این فکر فرو رفته که قابلیتهای مختلف این فریمورک چگونه کار میکنند. برای درک عمیقتر این موضوع، او میخواهد بداند قابلیت *autowiring* که تزریق وابستگی (*dependency injection*) خودکار با استفاده از آن انجام میشود چگونه کار میکند. از شما میخواهیم نسخهی سادهای از این بخش فریمورک *Spring Boot* را برای او بنویسید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/157778/) دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
```
dependency-injection
├── annotations
│ ├── Autowired.java
│ ├── Component.java
│ └── Qualifier.java
├── exceptions
│ ├── CircularDependencyFoundException.java
│ ├── NoPublicConstructorFoundException.java
│ ├── NoUniqueComponentFoundException.java
│ └── NoUniqueConstructorFoundException.java
├── test
│ ├── A1.java
│ ├── B1.java
│ ├── IA.java
│ └── IB.java
├── Injector.java
└── Main.java
```
## انوتیشن `@Component`
از این انوتیشن در کلاسهایی استفاده میشود که بخواهیم امکان استفاده از آنها در تزریق وابستگی خودکار فراهم باشد. این انوتیشن شامل پارامتر `value` از نوع `String` است.
## انوتیشن `@Autowired`
از این انوتیشن زمانی استفاده میشود که بخواهیم کانستراکتور موردنظر را جهت فراخوانی هنگام تزریق وابستگی خودکار مشخص کنیم. اگر کلاس موردنظر تنها شامل یک کانستراکتور باشد، نیازی به استفاده از این انوتیشن نیست. در غیر اینصورت، فقط یکی از کانستراکتورهای کلاس باید دارای این انوتیشن باشد.
## انوتیشن `@Qualifier`
از این انوتیشن زمانی استفاده میشود که بخواهیم از بین چند پیادهسازی برای یک اینترفیس یا کلاس، یکی را برای *autowiring* انتخاب کنیم. این انوتیشن شامل پارامتر `value` از نوع `String` است.
## کلاس `Injector`
این کلاس، وظیفهی اصلی قابلیت *autowiring* را برعهده دارد. این کلاس شامل متدی با نام `get` و با امضای زیر است:
```java
public static <T> T get(Class<T> typeClass)
```
این متد را بهگونهای پیادهسازی کنید که با دادن یک کلاس به آن، یک نمونه از آن کلاس ساخته شود. همچنین، کلاس دادهشده میتواند شامل یک یا چند کانستراکتور باشد.
نکات زیر هنگام پیادهسازی متد `get` باید رعایت شوند:
+ اگر کلاس موردنظر شامل کانستراکتور `public` نبود، یک استثنا از نوع `NoPublicConstructorFoundException` پرتاب کنید.
+ اگر کلاس موردنظر دارای بیش از یک کانستراکتور بود و بیش از یکی از این کانستراکتورها دارای انوتیشن `@Autowired` بودند، یک استثنا از نوع `NoUniqueConstructorFoundException` پرتاب کنید.
+ اگر بیش از یک پیادهسازی برای یک اینترفیس یا کلاس جهت ساخت آبجکت وجود داشت که هیچکدام از آنها دارای انوتیشن `@Qualifier` نبودند، یک استثنا از نوع `NoUniqueComponentFoundException` پرتاب کنید (برای مثال، اگر اینترفیسی با نام `IA` داشته باشیم و دو پیادهسازی `A1` و `A2` از آن داشته باشیم که مقدار موجود در `@Component` آنها یکسان باشد).
+ اگر یک `@Component` با `value` یکسان برای بیش از یک پیادهسازی برای یک اینترفیس یا کلاس وجود داشت، یک استثنا از نوع `NoUniqueComponentFoundException` پرتاب کنید.
+ اگر هنگام ساخت آبجکتها با وابستگی چرخشی مواجه شدید (مثلاً اگر کلاس `A` در کانستراکتور خود یک آبجکت از نوع `B` لازم داشته باشد و کلاس `B` در کانستراکتور خود یک آبجکت از نوع `A` لازم داشته باشد)، یک استثنا از نوع `CircularDependencyFoundException` پرتاب کنید.
# نکات
+ بررسی خطاها و پرتاب استثناها باید هنگام فراخوانی متد `get` کلاس `Injector` و هنگام بررسی آبجکتهای موردنظر جهت ساخت صورت گیرد.
+ در صورت نیاز، میتوانید متدهای دیگری نیز در کلاس `Injector` تعریف کنید.
+ **تضمین میشود** که از نوع دادههای *generic* بهعنوان آرگومان متد `get` کلاس `Injector` استفاده نمیشود.
# آنچه باید آپلود کنید
پس از پیادهسازی متد `get`، فایل `Injector.java` را آپلود کنید.