HK2 injection in Standalone Java Application with Custom Binder

In my previous post, I gave an example of using the HK2 injection in a stand-alone application.

Please refer it in the below link.
Hk2 Injection with hk2 inhabitant file

In the above example, we have to create an HK2 inhabitant file which contains the binding information such as contract and service name and their mapping. The overhead in this approach is generating the HK2 default file. We can automate the file creation process in the maven build with hk2-inhabitant-generator plugin. But at some point, we may want to define the mapping explicitly such as using the service and contract from different libs. The hk2-inhabitant-generator may not add the contract/service mapping in the inhabitant file. Therefore, to resolve the above problem, we need to define a custom binder which contains all the bindings details.

Let’s see how can use the HK2 injection in a stand-alone application with a custom binder.

The below one is my POM file.
hk2-injection-pom

We have a standalone application which will be used for adding, deleting, updating the user details into HashMap or Google Guava Cache. We have two interfaces(UserService for service and UserDao for DAO) and three implementation classes(UserServiceImpl, UserGuavaCacheImpl and UserLocalCacheDaoImpl)

UserGuavaCacheImpl is used to do CRUD operation on Guava Chache and UserLocalCacheDaoImpl is used to do CRUD operation on HashMap.

We decide to use either Local cache or Google Guava cache based on a system property. This is a simple example to show how we can use the HK2 injection.
Refer the below image to know my project structure.

hk2-project-structure

All our interfaces should be annotated with @Contract and all the implementation classes should be annotated with @Service.

Refer below my Service implementation.
hk2-userservice

Refer my various DAO implementations below.

Refer my custom binder file which has the binding information below.

hk2-dependencybinder

In the above file, I have used “Named” annotation as we have two services for UserDao interface. If we don’t provide that then by default, the service locator injects the first available implementation.

Below is my main class which invokes the User Service to perform various CRUD operations with User Object.
hk2-Application
The below code is used to create a ServiceLocator instance and then we bind the created service locator with our custom binder.


ServiceLocator serviceLocator = ServiceLocatorFactory.getInstance().create("serviceLocator");
ServiceLocatorUtilities.bind(serviceLocator, new DependencyBinder());

We can use the ServiceLocator object for getting the Object instance like below


UserService userService = serviceLocator.getService(UserService.class, "empService");

We have two DAO implementation. We need to decide which one to use. The hk2 IterableProvider will give both the implementations classes. Therefore, I have used a system property to decide the appropriate cache implementation. Refer the below code from UserServiceImpl.


@Inject
    public UserServiceImpl(IterableProvider iterableProviders) {
        String cache = System.getProperty("CACHE");
        if (CacheDetails.GUAVA.name().equals(cache)) {
            this.userDao = iterableProviders.named("empGuavaCacheDao").get();
        }
        else if(CacheDetails.LOCAL.name().equals(cache)) {
            this.userDao = iterableProviders.named("empLocalCacheDao").get();
        }
    }

 
The output of my program is as given below,


Add user details
The user details after it has been added User: User{id='0701f22b-10b0-4d6f-8c8d-410da89646f9', firstName='First Name', lastName='Last Name}
Now fetch the user details with ID
User :User{id='0701f22b-10b0-4d6f-8c8d-410da89646f9', firstName='First Name', lastName='Last Name}
Now update the user details
User After Updation:User{id='0701f22b-10b0-4d6f-8c8d-410da89646f9', firstName='Bala', lastName='Samy}
Now delete the user details
User After Deletion:null


Testing HK2 injection
Fetching the various DAO implementation
UserDao userDao = serviceLocator.getService(UserDao.class, "empGuavaCacheDao")
userDao instanceof UserGuavaCacheImpl - > Its an instance of UserGuavaCacheImpl 
userDao = serviceLocator.getService(UserDao.class, "empLocalCacheDao")
userDao instanceof UserLocalCacheDaoImpl - > Its an instance of UserLocalCacheDaoImpl 


 

Refer the code @hk2-java-custombinder

 

 

Advertisements

How to use HK2 injection in a Standalone Java Application

In this post, we are going to see how we can use the HK2 injection framework in a standalone Java application.

We need to include the below hk2 dependencies in our pom file. Here is the pom file.


 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <name>Hk2 Java standlaone application</name>
    <version>1.0.0</version>
    <artifactId>hk2-java-sample</artifactId>
    <groupId>com</groupId>
    <properties>
        <commons-lang3-v>3.6</commons-lang3-v>
        <maven-compiler-plugin-v>3.7.0</maven-compiler-plugin-v>
        <hk2-v>2.5.0-b36</hk2-v>
        <junit-v>4.12</junit-v>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3-v}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit-v}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.hk2</groupId>
            <artifactId>hk2</artifactId>
            <version>${hk2-v}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.hk2</groupId>
            <artifactId>hk2-junitrunner</artifactId>
            <version>${hk2-v}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin-v}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.glassfish.hk2</groupId>
                <artifactId>hk2-inhabitant-generator</artifactId>
                <version>${hk2-v}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate-inhabitants</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Consider that, we have a standalone application which will be used for adding, deleting, updating the employee details and the back end is a HashMap.

We have two interfaces(EmployeeService and EmployeeDao) and its implemetation classes(EmployeeServiceImpl and EmployeeDaoImpl) in this application.

To make use of HK2 injection, All our interfaces should be annotated with @Contract and all the implementation classes should be annotated with @Service.

Refer the below code to know how to do that.


package com.service;

import com.model.Employee;
import org.jvnet.hk2.annotations.Contract;

@Contract
public interface EmployeeService {
    public Employee fetch(String id);
    public Employee add(Employee employee);
    public void delete(String id);
    public Employee update(Employee employee);
}



package com.service.impl;

import com.dao.EmployeeDao;
import com.model.Employee;
import com.service.EmployeeService;
import org.jvnet.hk2.annotations.Service;

import javax.inject.Inject;
import java.util.UUID;

@Service
public class EmployeeServiceImpl implements EmployeeService {

    private EmployeeDao employeeDao;

    @Inject
    public EmployeeServiceImpl(EmployeeDao employeeDao){
        this.employeeDao = employeeDao;
    }

    @Override
    public Employee fetch(String id) {
        return employeeDao.fetch(id);
    }

    @Override
    public Employee add(Employee employee) {
        employee.setId(UUID.randomUUID().toString());
        return employeeDao.add(employee);

    }

    @Override
    public void delete(String id) {
        employeeDao.delete(id);
    }

    @Override
    public Employee update(Employee employee) {
        return employeeDao.update(employee);
    }
}



package com.dao;

import com.model.Employee;
import org.jvnet.hk2.annotations.Contract;

@Contract
public interface EmployeeDao {

    public Employee fetch(String id);
    public Employee add(Employee employee);
    public void delete(String id);
    public Employee update(Employee employee);
}


package com.dao.impl;

import com.dao.EmployeeDao;
import com.model.Employee;
import org.jvnet.hk2.annotations.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class EmployeeDaoImpl implements EmployeeDao {

    private static Map empLocalCache = new HashMap();

    public Employee fetch(String id) {
        return empLocalCache.get(id);
    }

    public Employee add(Employee employee) {
        empLocalCache.put(employee.getId(), employee);
        return empLocalCache.get(employee.getId());
    }

    public void delete(String id) {
        empLocalCache.remove(id);
    }

    public Employee update(Employee employee) {
        empLocalCache.put(employee.getId(), employee);
        return empLocalCache.get(employee.getId());
    }
}


Below is my main class which will use the Employee service class to perform add, update and delete operations with Employee Object.


package com;

import com.model.Employee;
import com.service.EmployeeService;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;

public class Application {

    public static void main(String[] args) {

        ServiceLocator serviceLocator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
        EmployeeService employeeService = serviceLocator.getService(EmployeeService.class);
        Employee employee = new Employee();
        employee.setFirstName("First Name");
        employee.setLastName("Last Name");

        System.out.println("Add employee details");
        Employee employeeAddResponse = employeeService.add(employee);
        System.out.println("The employee details after it has been added Employee: "+employeeAddResponse);

        System.out.println("Now fetch the employee details with ID");
        Employee employeeFetchResponse = employeeService.fetch(employee.getId());
        System.out.println("Employee :"+employeeFetchResponse);

        System.out.println("Now update the employee details");
        employee.setFirstName("Bala");
        employee.setLastName("Samy");
        Employee employeeUpdateResponse = employeeService.update(employee);
        System.out.println("Employee After Updation:"+employeeUpdateResponse);

        System.out.println("Now delete the employee details");
        employeeService.delete(employee.getId());
        System.out.println("Employee After Deletion:"+ employeeService.fetch(employee.getId()));

    }
}


To initialize all the HK2 dependencies, we have to call the ServiceLocatorUtilities.createAndPopulateServiceLocator() which will perform the initialization and return the ServiceLocator object.

We can make use of ServiceLocator object for getting the Object instance like below

EmployeeService employeeService = serviceLocator.getService(EmployeeService.class);

Before executing this, we need to do an important step which is to create the hk2 default file under our target/classes/META-INF folder. The hk2-inhabitant-generator plugin will help us to generate that file. Hence we need to include this plugin in our file. So we have to do maven install/package before we start executing our junit test cases.

The sample default file content will be like this,

#
# Generated on Thu Nov 09 17:04:57 EST 2017 by hk2-inhabitant-generator
#

[com.dao.impl.EmployeeDaoImpl]S
contract={com.dao.EmployeeDao}

[com.service.impl.EmployeeServiceImpl]S
contract={com.service.EmployeeService}

The output of my program is given below,



Add employee details
The employee details after it has been added Employee: Employee{id='f25b119a-820e-4162-af99-5c3580fe06f1', firstName='First Name', lastName='Last Name}
Now fetch the employee details with ID
Employee :Employee{id='f25b119a-820e-4162-af99-5c3580fe06f1', firstName='First Name', lastName='Last Name}
Now update the employee details
Employee After Updation:Employee{id='f25b119a-820e-4162-af99-5c3580fe06f1', firstName='Bala', lastName='Samy}
Now delete the employee details
Employee After Deletion:null


 

Refer the code @hk2-java-sample