Welcome to my blog. Here I write about technology, software development practice/processes and other stuff.
Notice
Wednesday, January 19, 2022
Using the headless mode in Spring Boot
Saturday, January 8, 2022
Customise Spring Boot Banner
When we run a Spring Boot application we see a Spring Boot banner. I wonder if we could able to change this or not and find out that Spring gives us the opportunity to change it. Why anyone should do that? Answer will be just for fun and learning.
spring.application.name=My Custom Banner
spring.banner.location=classpath:myBanner.txt
Now let's run the Spring Boot application and see the result.
Now we will see how to use an image (*.png/*.jpg/*.gif) as a banner.
To implement image we need to get an image of *.png/*.jpg/*.gif type and put it into the class path and set the path in the Spring Boot property spring.banner.image.location=classpath:myBanner.png here my image file name is myBanner.png.
- spring.main.banner-mode where we mention the banner mode console | log | off and the default value is console. console will print the banner in console and log in log file and off will turn of the banner.
- spring.banner.image.location where we put the banner image file location and the default value is classpath:banner.gif.
- spring.banner.image.height where we put an integer to specify the height of the image and the default value will be based on the image height.
- spring.banner.image.width where we put an integer to specify the width of the image in chars and the default value is 76.
- spring.banner.image.margin where we put an integer to specify the margin from the left hand image margin in chars and the default value is 2.
- spring.banner.image.bitdepth is used for ANSI colour and where we use two allowed values 4 (16 colour) or 8 (256 colour).
- spring.banner.image.invert is set to true then the dark terminal themes will be used for and the default value is false.
- spring.banner.image.pixelmode is to determine the pixel used to render the image, where we can use TEXT | BLOCK and the default value is TEXT. TEXT will use ' ', '.', '*', ':', 'o', '&', '8', '#', '@' to render image and BLOCK will use ' ', '░', '▒', '▓', '█' to render image.
spring.application.name=My Custom Banner
spring.main.banner-mode=console
spring.banner.location=classpath:myBanner.txt
spring.banner.image.pixelmode=text
spring.banner.image.location=classpath:myBanner.png
spring.banner.image.height=10
spring.banner.image.width=30
spring.banner.image.margin=2
spring.banner.image.bitdepth=8
spring.banner.image.invert=false
I will be using this 32 bit colour myBanner.png
myBanner.png |
Banner as a TEXT |
Inverted image render |
Banner as a BLOCK |
Banner in log file |
Sunday, July 18, 2021
Introduction to Spring Boot
History of Spring Boot
Before Spring Boot enterprise-level development creating an application with the Spring framework was so difficult. As a developer, you have to create and maintain the dependence injection, web configuration, deployment and etc. This also increase the learning curve for the developers.
Mike Youngstrom opened Spring JIRA # SPR-9888 feature JIRA on 17th Oct 2012. The idea was to reduce the learning curve of any new developer who will be coming in to create application using Spring's Web Application.
What is the Spring Boot?
Spring framework provides a pre-setup of Spring and some third party library using which developer could develop an application without any/much of configurations result in faster development. Non-functional features are readily available such as an embedded server, health check, security, metrics, and externalised configuration. If we want to differ from Spring-provided default configurations we could simply do so.
Spring Boot application could be bundled into a jar or a traditional war, as a result, it is easy to deploy. It also provides a command-line interface (CLI) to run the Spring script.
Why anyone uses Spring Boot?
- Do prototyping.
- Creating a minimum viable product for the actual market.
- Create Microservice
How to use/implement Spring Boot?
Spring Boot requirements
- Java 8 onwards supported
- Maven 3.3+ version build tool supported
- Gradle 6.3+ version build tool supported (5.6.x is also supported but is deprecated form)
- Tomcat 9.0 embedded servlet container (Servlet 4.0) supported
- Jetty 9.4 embedded servlet container (Servlet 3.1) supported
- Undertow 2.0 embedded servlet container (Servlet 4.0) supported
You can also deploy Spring Boot applications to any Servlet 3.1+ compatible container.
Spring Boot is available in Groovy or Kotlin or Java language for application development.
To minimise the developer’s effort Spring provide Spring Initializr (https://start.spring.io/) to generate the basic structure of your project with all the dependency in it. The Spring Boot Command Line Interface (CLI) is a command-line tool that you can use to quickly prototype an application. As it uses Groovy script for it, which means there is no boilerplate code that still has flour of Java.
Creating a simple application
Open Spring Initializr (https://start.spring.io/) to generate the basic structure of your project with all the dependency in it.
This will create the basic project structure.
pom.xml which is generated from Spring Initializr (https://start.spring.io/).
Note all the official starters follow the naming pattern spring-boot-starter-*
It has a spring-boot-starter-parent parent. We included only Spring Web and Spring Initializr add the test for unit testing. We will see how to test Spring Boot in another blog.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>2.5.2</version> | |
<relativePath/> <!-- lookup parent from repository --> | |
</parent> | |
<groupId>com.andy</groupId> | |
<artifactId>demo</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<name>demo</name> | |
<description>Demo project for Spring Boot</description> | |
<properties> | |
<java.version>1.8</java.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-web</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-maven-plugin</artifactId> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
The main class generated by Spring Initializr
package com.andy.demo; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
@SpringBootApplication | |
public class DemoApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(DemoApplication.class, args); | |
} | |
} |
Created a controller to make REST call
RestContoller annotation let the Spring know this is a controller class
RequestMapping maps HTTP requests to handler methods of MVC and REST controllers
package com.andy.demo.controller; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
@RestController("demoBean") | |
@RequestMapping("v1/demo") | |
public class DemoController { | |
@GetMapping("/message") | |
public String sayHello() { | |
return "Hello World! "; | |
} | |
} |
Sunday, August 9, 2020
New way to create immutable object in Java ['record'] JEP 384: Records
Some of the features of these 'record' class.
- implicitly they are final so it cannot be extended or abstracted but can implement an interface.
- java.lang.Record is the superclass of record
- A record cannot define the native method.
- A record field(s) is/are implicitly final
package dto; | |
import java.time.LocalDate; | |
public record Person(Name name, LocalDate dob, Address address) { | |
} |
package dto; | |
public record Address(String line1, String line2,String country,String zipcode) { | |
public Address(String line1, String line2, String zipcode) { | |
this(line1, line2, "India", zipcode); | |
} | |
// Instance Method | |
public String fullAddress() { | |
return line1 + " " + line2 + " " + country + " " + zipcode; | |
} | |
} |
package dto; | |
public record Name(Title title, String fname, String lname) { | |
public enum Title { Mr, Mrs, Miss, Master, Dr, Prof} | |
public Name { | |
if(fname == null || lname == null) { | |
throw new IllegalArgumentException("First name and / or Last name cannot be null"); | |
} | |
} | |
// static method | |
public static String fullNameToUpper(Name name) { | |
return (name.title() + " " + name.fname() + " " + name.lname()).toUpperCase(); | |
} | |
// Custom equals method. Not considering title here | |
// Do remember that hashCode method also need to be changed | |
// As this is just an example. Not overriding hashCode method | |
@Override | |
public boolean equals(Object obj) { | |
if(obj == this) { | |
return true; | |
} | |
return obj instanceof Name name && name.fname().equals(fname()) && name.lname().equals(lname()); | |
} | |
} |
import dto.*; | |
import java.time.*; | |
public class TestRecord { | |
public static void main(String[] args) { | |
String fname = "Andy"; | |
String lname = "Banerjee"; | |
Name name = new Name(Name.Title.Mr, fname, lname); | |
LocalDate dob = LocalDate.of(1990,Month.JANUARY,01); | |
Address addressInIndia = new Address("Networking Street", "Hacker Avenue", "PINcode"); | |
Person person = new Person(name, dob, addressInIndia); | |
System.out.println("Person Name: " + person.name()); | |
System.out.println("Date of Birth: " + person.dob()); | |
System.out.println("Address: " + person.address()); | |
System.out.println("hashCode() = " + person.hashCode()); | |
System.out.println("toString() = " + person.toString()); | |
Person clonePerson = new Person(name, dob, addressInIndia); | |
Address addressOutsideIndia = new Address("Networking Street", "Hacker Avenue", "USA", "ZIPcode"); | |
Person anotherPerson = new Person(name, dob, addressOutsideIndia); | |
System.out.println("====================================="); | |
System.out.println("\n Person object A : " + person); | |
System.out.println("\n Person Object B : " + clonePerson); | |
System.out.println("\n Person Object C : " + anotherPerson); | |
System.out.println("====================================="); | |
System.out.println("Person A & B. Both are equals? => " + person.equals(clonePerson)); | |
System.out.println("Person A & C. Both are equals ? => " + person.equals(anotherPerson)); | |
Name nameWithDrTitle = new Name(Name.Title.Dr, fname, lname); | |
System.out.println("How custom equals working ? Ignoring the title here => " + name.equals(nameWithDrTitle)); | |
System.out.println("Invoking the static method => " + Name.fullNameToUpper(nameWithDrTitle)); | |
System.out.println("Invoking the instance method => " + addressOutsideIndia.fullAddress()); | |
try { | |
Name recordWithValidationCheck = new Name(Name.Title.Mr, null, null); | |
} catch (IllegalArgumentException e) { | |
System.out.println("Added validation. \t::::::: \t" + e.getMessage()); | |
} | |
} | |
} |
javac --enable-preview --release 15 TestRecord.java
java --enable-preview TestRecord
Sunday, July 26, 2020
Now Java Developer can write their 'Will' [JDK15 JEP 360: Sealed Class (Preview)]
As a developer if you want to control who can extend your class or interface.
public sealed class Shape permits Circle { | |
public void name() { | |
System.out.println("This is Shape."); | |
} | |
public static void main(String args[]) { | |
Shape shape = new Shape(); | |
shape.name(); | |
Shape newShape = new Circle(); | |
newShape.name(); | |
} | |
} | |
non-sealed class Circle extends Shape { | |
@Override | |
public void name() { | |
System.out.println("This is Circle."); | |
} | |
} | |
To Compile
To Run
A permitted subclass must define whether it could be extended to a specific class (sealed) or open to any unknown class(non-sealed) or not open for any extension (final).
When a not permitted class extend a sealed class.
Happy Coding and keep learning!
Saturday, July 18, 2020
JDK 15 [Pattern Matching of instanceof operator ]
// Anindya Bandopadhyay (anindyabandopadhyay@gmail.com) | |
public class PatternMatchingOfInstance { | |
public static void main(final String args[]) { | |
PatternMatchingOfInstance instance = new PatternMatchingOfInstance(); | |
Object obj = instance.getValue((instance.new IntValue(1))); | |
if(obj instanceof Integer) { | |
final Integer intValue = (Integer) obj; | |
System.out.println(String.format("Int value = %d", intValue)); | |
} | |
//JEP 375: Pattern Matching for instanceof (Second Preview) | |
if(obj instanceof Integer objInt) { | |
System.out.println(String.format("Using Pattern Matching for instanceof: Int value = %d", objInt)); | |
} | |
} | |
private Object getValue(final Value value) { | |
return value.getValue(); | |
} | |
interface Value { | |
Object getValue(); | |
} | |
class IntValue implements Value { | |
private final int value; | |
public IntValue(final int value) { | |
this.value = value; | |
} | |
@Override | |
public Integer getValue() { | |
return value; | |
} | |
} | |
class BoolValue implements Value { | |
private final boolean value; | |
public BoolValue(final boolean value) { | |
this.value = value; | |
} | |
@Override | |
public Boolean getValue() { | |
return value; | |
} | |
} | |
class StrValue implements Value { | |
private final String value; | |
public StrValue(final String value) { | |
this.value = value; | |
} | |
@Override | |
public String getValue() { | |
return value; | |
} | |
} | |
class DoubleValue implements Value { | |
private final double value; | |
public DoubleValue(final double value) { | |
this.value = value; | |
} | |
@Override | |
public Double getValue() { | |
return value; | |
} | |
} | |
class FloatValue implements Value { | |
private final float value; | |
public FloatValue(final float value) { | |
this.value = value; | |
} | |
@Override | |
public Float getValue() { | |
return value; | |
} | |
} | |
} |
Output
Happy Coding!
Wednesday, May 20, 2020
Abstract Data Type
What is the data type?
A data type is an attribute in a programming language which define the domain of values and operations on that domain.- Define a certain domain of value.
- Define operations allowed on those values.
Example
- Take only integer values
- Operations supported: addition, subtraction, multiplication, bitwise operation etc.
- Take only floating values
- Operations supported: addition, subtraction, multiplication, etc. (it does not support operations like bitwise and modulus).
Now, what is the user-defined data type?
In below example, we define the user-defined data type using class. Here Person class is the type which is consist of bunch of String, LocalDate and Address fields. Person class have a user define a data type of Address.
Example
public class Person {private String firstName;
private String lastName;
private LocalDate dateOfBirth;
private Address address;
.....
}
public class Address {
private String firstLine;
private String lastLine,
private State state;
....
}
Abstract Data Types (ADT)
Abstract Data Types (ADT) are like user define types which define values and operations on that user define type without specifying how the operation will happen.Example
User Define Data Type
- MyString is a wrapper object of string.
User Define Operations
- The addition will concatenation two MyString. Example: "Hello" + " world" will result in "Hello world".
- The subtraction will substring the difference of length. If the difference of length is zero or negative then it will have an empty string. Example:
- "Hello" - "world" will result in an empty string
- "Hello" - "hi" will result in "Hel"
- "hi" - "Hello" will also result in an empty string.
- The division will remove common character(s) from MyString. Example: "Hello" / "world" will result in "He".
- The multiplication will concatenate characters alternatively. Example: "Hello" * "world" will result in "Hweolrllod".
Actual Implementation
package com.andy.adt; | |
import java.util.Objects; | |
public class MyString { | |
private final String myString; | |
public MyString(String myString) { | |
this.myString = myString; | |
} | |
public MyString add(MyString str2) { | |
return new MyString(myString + str2.toString()); | |
} | |
public MyString subtract(MyString str2) { | |
int differenceInLength = myString.length() - str2.toString().length(); | |
if (differenceInLength > 0) { | |
return new MyString(myString.substring(0, differenceInLength)); | |
} | |
return new MyString(""); | |
} | |
public MyString multiple(MyString str2) { | |
StringBuilder stringBuilder = new StringBuilder(""); | |
int maxLength = Math.max(myString.length(), str2.toString().length()); | |
for (int index = 0; index < maxLength; index++) { | |
if(index < myString.length()) { | |
stringBuilder.append(myString.charAt(index)); | |
} | |
if(index < str2.toString().length()) { | |
stringBuilder.append(str2.toString().charAt(index)); | |
} | |
} | |
return new MyString(stringBuilder.toString()); | |
} | |
public MyString divide(MyString str2) { | |
char[] denominator = str2.toString().toCharArray(); | |
String str = myString.toString(); | |
for (char ch: | |
denominator) { | |
str = str.replaceAll(String.valueOf(ch), ""); | |
} | |
return new MyString(str); | |
} | |
@Override | |
public String toString() { | |
return myString; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (!(o instanceof MyString)) return false; | |
MyString myString1 = (MyString) o; | |
return Objects.equals(myString, myString1.myString); | |
} | |
@Override | |
public int hashCode() { | |
return myString != null ? myString.hashCode() : 0; | |
} | |
} |
Sample Unit Test of the Implementation
package com.andy.adt; | |
import org.junit.jupiter.api.Test; | |
import static org.junit.jupiter.api.Assertions.*; | |
class MyStringTest { | |
private MyString myString; | |
@Test | |
public void testAdd(){ | |
myString = new MyString("Hello"); | |
MyString result = myString.add(new MyString(" World!")); | |
assertEquals("Hello World!", result.toString()); | |
} | |
@Test | |
public void testSubtract_WhenSecondParameterIsLong() { | |
myString = new MyString("Hello"); | |
MyString result = myString.subtract(new MyString(" World!")); | |
assertEquals("", result.toString()); | |
} | |
@Test | |
public void testSubtract_WhenFirstParameterIsLong() { | |
myString = new MyString("Robot"); | |
MyString result = myString.subtract(new MyString("Ok")); | |
assertEquals("Rob", result.toString()); | |
} | |
@Test | |
public void testDivide() { | |
myString = new MyString("Hello"); | |
MyString result = myString.divide(new MyString("world")); | |
assertEquals("He", result.toString()); | |
} | |
@Test | |
public void testMultiple() { | |
myString = new MyString("Hello"); | |
MyString result = myString.multiple(new MyString("world")); | |
assertEquals("Hweolrllod", result.toString()); | |
} | |
} |