There’s been a lot of buzz around Guice for a while, everyone seems to be interested in the technology for dependency injection, but I still haven’t seen any simple tutorials for using Guice with Maven. In this series, I’m just going to provide the basics, how to start a Maven project to support a simple command-line Guice application, how to organize projects containing different implementations of common interfaces, etc. This first installment really just provides a simple example project and walks you through the component parts of the application.
You can try to follow along, step-by-step, but you’ll probably have an easier time if you checkout this example from GitHub here: https://github.com/tobrien/guice-series-1
There are a thousand ways to create a simple Maven project: you can use a Maven Archetype, or, if you are using m2eclipse as I recommended earlier, all you need to do is create a new project and select Maven -> New Maven Project. For the purposes of this entry, just create a simple Maven project using the following parameters: groupId: com.discursive.example, artifactId: guice-series-1, version: 1.0-SNAPSHOT. Again, it doesn’t really matter if you change the identifiers here, feel free to use your own groupId.
You would think that there would be a few Guice-specific Maven archetypes by now? Unfortunately there are none, so you have to start hacking away at a new Guice project by copying and example. Lucky for you, it is easy to start a new Maven project that uses Guice for dependency injection. Create a new Maven project, and add the following dependency to your project’s pom.xml file for Guice. For this example, your pom.xml will look like this (that’s it);
Since Guice is in Maven Central, you don’t need to go bumbling around the internet to find someone’s custom Maven repo or installing some fancy new build tool with an anti-Maven agenda. Because it is in Maven Central, it just works. It is even easier to add Guice as a dependency if you use a modern IDE like Eclipse with solid Maven integration (m2eclipse) – if you don’t already use it, check out m2eclipse, the latest release works like a charm.
In this post, I’m going to be developing a simple example based on student data. This example is a simple command-line application that starts up, asks for a student ID number, queries a database of students, and verifies that the student is enrolled as a full time student. This application has a few core interfaces and objects:
- This is a simple Java bean with the properties: id, name, credits, major, whether or not the student is registered, and the year of the student.
- This is an interface which defines methods involved in verifying the student’s full-time status. Implementations of this interface apply different rules to classify a student.
- Think of this as a DAO for Student data objects. The program can load a Student by id or save a Student object. This interface hides all of the details from the program.
Create a class in the com.discursive.example.student package named Student with the following code. Note that I’ve omitted the getters and setters for all of the properties. If you are following along, create the getters and setters (again, if you use an IDE like Eclipse, this is very easy to do).
Next create a StudentStore interface in the com.discursive.example.student package with the following code:
This is a very straightforward interface. The exists method takes an identifier, returning true of a student record with that id exists and false otherwise. The load method loads a Student record with the specified id, and the save method either creates a new record if the student record doesn’t exist or updates an existing record.
Next, create the Registrar interface in the com.discursive.example.student package with the following code:
Another simple interface, two methods: checkStudentStatus just checks to see if the student is a registered, full-time student, registerStudent registers a student.
Once you’ve defined the Registrar and StudentStore interfaces, you can provide simple implementations. In this example, we’re only going to create two simple implementations. In the next post, I’ll introduce alternative implementations and make some suggestions about Maven project structure.
Create the DummayStudentStore class in com.discursive.example.student.store package. This class is true to its name, it doesn’t persist Student records between executions and it really just stores and serves Student objects from an in-memory HashMap. The point of this class isn’t to provide real functionality, it is to provide a simple demonstration of how interfaces and implemented in Guice. Here’s the class listing:
Note the @Singleton annotation. This is a hint to Guice that there should only be one instance of the DummyStudentStore. It is a singleton object. Also notice that there is no other hint that this object is going to be managed by Guice.
Next, create a class called LenientRegistrar in the com.discursive.example.student.register package. This is an implementation of Registrar which applies a simple rule for students. A student is considered full-time if they are enrolled in 10 or more credits.
Just like the DummyStudentStore this class is also marked as a @Singleton. Again, this means that there will only be a single instance of LenientRegistrar in a system.
In addition to the @Singleton annotation, notice that this class contains a constructor annotated with the @Inject annotation. When Guice creates this object, it will note the arguments to this constructor and attempt to supply components which have the same type. Next, we’ll see how this binding is configured.
Next, we need to provide some hints to Guice to tell it what class to instantiate when it is asked for a particular interface. Create a class named SimpleModule and put this class in the com.discursive.example package. This class follows:
So, what’s going on here. Here we’ve configured the simplest of modules, all this class is doing is giving hints to Guice. When we ask for a StudentStore, create a DummyStudentStore, and when we ask for a Registrar gives us a LenientRegistrar.
Lastly, create a command-line application which uses Guice to gain access to these Singleton objects and which only references the interfaces defined at the beginning of this post. Create a class Main in the com.discursive.example package with the following code:
What’s going on here? First we’re asking the user to supply a student ID. Then we’re configuring Guice and retrieving both of the Singleton objects. All the magic happens in the following three lines:
In the first line, we’re creating an “injector” which is the object we’re going to retrieve our components from. Guice takes care of retrieving the appropriate classes because of the bindings configured in the SimpleModule class.
If you are using m2eclipse in the Eclipse IDE, simply right-click on the Main class and choose Run… As m2eclipse adds the appropriate dependencies to the classpath automatically, you should see the program run and product the following output. The program will pause and wait for you to enter in a “person ID”, in the example below I supplied the number 23.
So, that’s the simplest Guice example that goes a bit farther than the stock example from Guice itself because I’ve given you a real project to checkout from GitHub. In future posts, I’m going to develop this a bit and try to provide some guidance for larger projects.