Friday, December 15, 2017

Spring Boot REST API - Convert English Number into Words

Spring is one of the most popular Java EE application framework. Today we will develop a very simple Spring Boot REST API which receives a number as a request and in response, we will get the corresponding English words.

Please note that, this is not a tutorial to learn about Spring Boot REST API. I assumed you already familiar with this technology.



Example request:
http://localhost:8080/convert/123456789

Response:
{“One Hundred Twenty Three Million Four Hundred Fifty-Six Thousand Seven Hundred Eighty-Nine”}

Development Environment:

a) Eclipse
b) JDK 1.8
c) Spring 5.
d) Maven
e) Postman (API client)  or you can use a web browser as well.


In this application, we do not need any database connectivity.

You can download the full code from my GitHub repository.


High-level project architecture:



POM file: Our application fairly simple. We use some basic dependencies only. No need any additional library.


<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.monirthought.ntw</groupId>
    <artifactId>english-number-to-words</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <finalName>ROOT</finalName>
    </build>
 <packaging>war</packaging>
</project>


Service layer: Only one method we require. (NumberToWordConversion.java)


package com.monirthought.ntw.service;

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

import com.monirthought.ntw.util.NumberToWordConverterUtil;

/**
 * Service class
 * 
 * @author Moniruzzaman Md
 *
 */
@Service
public class NumberToWordConversionImpl implements NumberToWordConversion {

 @Autowired
 NumberToWordConverterUtil convertUtil;

 /*
  * (non-Javadoc)
  * 
  * @see
  * com.monirthought.ntw.service.NumberToWordConversion#convertIntoWords(java.
  * lang.Long)
  */
 @Override
 public String convertIntoWords(Long number) {
  return convertUtil.convertToWords(number);
 }

}
Controller (IndexController.java):


package com.monirthought.ntw.controller;

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

import com.monirthought.ntw.service.NumberToWordConversion;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Index controller
 * 
 * @author Moniruzzaman Md
 *
 */
@RestController
public class IndexController {

 @Autowired
 NumberToWordConversion conversion;

 @RequestMapping("convert/{number}")
 public String index(@PathVariable(value = "number") Long number) {
  return conversion.convertIntoWords(number);
 }

}


Utility class: Here we implemented our core algorithm

package com.monirthought.ntw.util;

import java.util.ArrayList;
import java.util.HashMap;

import org.springframework.stereotype.Component;

/**
 * Utility class to Convert Number into Words
 * 
 * @author Moniruzzaman Md
 *
 */
@Component
public class NumberToWordConverterUtilImpl implements NumberToWordConverterUtil {

 private HashMap<Long, String> unitMapper = new HashMap<Long, String>();
 private ArrayList<Long> numberUnit = new ArrayList<Long>();

 /**
  * Constructor
  */
 public NumberToWordConverterUtilImpl() {
  super();
  assignUnitMapper();
 }

 /**
  * Keeping all number units into an ArrayList for further calculation
  */
 private void assignNumberUnit() {
  numberUnit.add(1L);
  numberUnit.add(2L);
  numberUnit.add(3L);
  numberUnit.add(4L);
  numberUnit.add(5L);
  numberUnit.add(6L);
  numberUnit.add(7L);
  numberUnit.add(8L);
  numberUnit.add(9L);
  numberUnit.add(10L);
  numberUnit.add(11L);
  numberUnit.add(12L);
  numberUnit.add(13L);
  numberUnit.add(14L);
  numberUnit.add(15L);
  numberUnit.add(16L);
  numberUnit.add(17L);
  numberUnit.add(18L);
  numberUnit.add(19L);

  numberUnit.add(20L);
  numberUnit.add(30L);
  numberUnit.add(40L);
  numberUnit.add(50L);
  numberUnit.add(60L);
  numberUnit.add(70L);
  numberUnit.add(80L);
  numberUnit.add(90L);

  numberUnit.add(100L);
  numberUnit.add(1000L);
  numberUnit.add(1000000L);
  numberUnit.add(1000000000L);

 }

 /**
  * Mapping all unit
  */
 private void assignUnitMapper() {

  unitMapper.put(1L, "One");
  unitMapper.put(2L, "Two");
  unitMapper.put(3L, "Three");
  unitMapper.put(4L, "Four");
  unitMapper.put(5L, "Five");
  unitMapper.put(6L, "Six");
  unitMapper.put(7L, "Seven");
  unitMapper.put(8L, "Eight");
  unitMapper.put(9L, "Nine");
  unitMapper.put(10L, "Ten");
  unitMapper.put(11L, "Eleven");
  unitMapper.put(12L, "Twelve");
  unitMapper.put(13L, "Thirteen");
  unitMapper.put(14L, "Fourteen");
  unitMapper.put(15L, "Fifteen");
  unitMapper.put(16L, "Sixteen");
  unitMapper.put(17L, "Seventeen");
  unitMapper.put(18L, "Eighteen");
  unitMapper.put(19L, "Nineteen");
  unitMapper.put(20L, "Twenty");
  unitMapper.put(30L, "Thirty");
  unitMapper.put(40L, "Fourty");
  unitMapper.put(50L, "Fifty");
  unitMapper.put(60L, "Sixty");
  unitMapper.put(70L, "Seventy");
  unitMapper.put(80L, "Eighty");
  unitMapper.put(90L, "Ninety");
  unitMapper.put(100L, "Hundred");
  unitMapper.put(1000L, "Thousand");
  unitMapper.put(1000000L, "Million");
  unitMapper.put(1000000000L, "Billion");

  assignNumberUnit();
 }

 /*
  * (non-Javadoc)
  * 
  * @see
  * com.monirthought.ntw.util.NumberToWordConverterUtil#convertToWords(java.lang.
  * Long)
  */
 public String convertToWords(Long number) {

  String inWords = "";

  /* No need to process further */
  if (0 == number) {
   return "Zero";
  }

  /* No need any logic for 1 to 19, simply return corresponding mapping string */
  if (number <= 19) {
   return unitMapper.get(number);
  }

  /* We only need unit higher than 19 to calculation */
  for (int i = numberUnit.size() - 1; i > 18; i--) {
   if ((number / numberUnit.get(i)) >= 1) {
    if (number > 99) {
     inWords += convertToWords(number / numberUnit.get(i)) + " " + unitMapper.get(numberUnit.get(i))
       + " ";
    } else {
     inWords += unitMapper.get(numberUnit.get(i)) + " ";
    }
    number = number % numberUnit.get(i);
    if (number == 0) {
     break;
    }
    inWords += convertToWords(number);
    break;
   }
  }
  return inWords;
 }
}

Algorithm in brief:

At very first, we have to find all units of English number and map all units with corresponding English words.

1 = One
2 = Two
.
.
.
10 = Ten
11 = Eleven
.
.
.
19 = Nineteen.
20 = Twenty
30 = Thirty
40 = Forty
50 = Fifty
60 = Sixty
70 = Seventy
80 = Eighty
90 = Ninety
100 = Hundred
1000 = Thousand
1000000 = Million
1000000000 = Billion

After this, we will recursively break down the number to get appropriate English words.

Let’s given number is 11561,

a) First Find the highest unit by which we can divide our given number. For 11561, height unit is thousand (1000)
b) Divide the number with the selected unit, so we will get 11. 11 is already mapped, so return ‘Eleven’
c) Calculate the remainder number. 11516 % 1000 = 516
d) Find the next highest unit for 516, we will get Hundred.
e) Divide 516 by Hundred (516/100 = 5), the result is 5. 5 is found on our map. So, return “Five”.
f) Again, calculate the remainder number. 516 % 100 = 16
g) 16 already mapped to ‘Sixteen’, so return “Sixteen”.

Finally, the function will return “Eleven Thousand Five Hundred Sixty One”

The following image illustrates the above algorithm:



Testing:
a.    Run the application with maven command: mvn spring-boot:run
b.    Open then postman or a web browser.
c.    Send a request as below:

http://localhost:8080/convert/123456789





This program was tested with the maximum range of a 64 bit singed long value (9223372036854775807).

No comments:

Post a Comment