$29
Introduction
Dependency injection is commonly used in software development. Popular Java framework you use
frequently are equipped with dependency injection, for example, Spring. To be an excellent stuent in CSE
department of SUSTech, you should know not only how to use dependency injection frameworks but also
how they work.
Suppose you have a class A, which depends on class B, C, and D, and class C depends on class E and F. When
you need an instance of class A, in this case, you need to first create instances of class E and F, which will be
used to create an instance of class C. After that, you should create instances of class B and D. Finally, you
pass these instances to the constructor of A.
1
public class A {
2
public A(B serviceB, C serviceC, D serviceD) {
3
// Creating an instance of class A requires instances of class B, C, and D.
4
5
}
}
Creating instances of such classes is tedious and error-prone. The case would be much more complicated in
real world applications. It is desired that these steps can be done automatically.
Dependency injection can act as a "smart factory" to help us achieve this goal. In this assignment, you will
learn to build a tiny dependency injection framework by which you will have an impression of the internal
mechamism of dependency injection.
Requirement
To get full score in this assignment, you are required to implement an interface provided by us.
1
public interface Container {
2 <T> void register(Class<T> serviceType);
3 <T> void register(Class<T> serviceType, Class<? extends T> implementationType);
4
5
<T> T resolve(Class<T> serviceType);
}There are three methods in this interface. The first two are used for registering a service type, and,
optionally, its corresponding implementation type. The last method is for getting an instance of the
specified service type.
The following code snippet shows the example mentioned above, which demostrates the usage of the first
and the last method in the Container interface.
1
public class Example1 {
2
public static void main(String[] args) {
3 // Create an instance of container
4 Container container = new ContainerImpl();
5
6 // Register classes to the container
7 container.register(A.class);
8 container.register(B.class);
9 container.register(C.class);
10 container.register(D.class);
11 container.register(E.class);
12 container.register(F.class);
13
14
// Get an object from container
15
A aObject = container.resolve(A.class);
16
17
}
}
The second method provides the ability to associate a service type, which is usually an abstract class or an
interface, to a specific implementation type, which is usually a class that extends the abstract class or
implemented the interface mentioned before. Note that when multiple implementations are associate to a
service type, only the last one should take effect.
1
public class Example2 {
2
public static void main(String[] args) {
3 // Create an instance of container
4 Container container = new ContainerImpl();
5
6 // Associate A with AImpl1
7 container.register(A.class, AImpl1.class);
8
9
// Get an object from container
10 // Here aObject shoule be an instance of AImpl1
11 A aObject = container.resolve(A.class);
12
13 // Associate A with AImpl2
14 container.register(A.class, AImpl2.class);
15
16 // Get an object from container
17 // Here aObject shoule be an instance of AImpl2
18 A aObject = container.resolve(A.class);
19
20
}
}Dependencies can be specified by parameters in the constructor, or fields with @Inject annotation. Here is
an example.
1
public class A {
2
3
private B bDep;
4
5 @Inject
6 private C cDep;
7
8
public A(B bDep) {
9
this.bDep = bDep;
10
11
}
}
When dependencies can not be found, an ServiceNotFoundException should be thrown.
For simplicity, we guarantee that, in our test cases for grading:
No cyclic dependency would occur
To be rigorius, you are required to carefully check the arguments before further processing. An
IllegalArgumentException should be thrown if one of the following cases happen:
Null argumnet value(s) for each method
Register an interface or an abstract class for serviceType in the register method with one
parameter, or for implementationType in the register method with two parameters.
Materials Provided
Container.java: The interface to implement
ServiceNotFoundException.java: The exception to be thrown when a service can not be found
Inject.java: The annotation used to specify dependency
Submission
You should create a public class named ContainerImpl which implements the interface Container, and
upload the file ContainerImpl.java to Sakai
You will GET A ZERO if one of the following happens:
File name is not identical to the requirement (e.g., containerImpl.java, ContainerImpl.Java)
Compilation fail
Plagiarism