FailureAnalyzer in Spring Boot

FailureAnalyzer in Spring Boot

In this post, we will be exploring  FailureAnalyzer in Spring Boot. We will also learn to Create a Custom FailureAnalyzer in Spring Boot.

 

Introduction

Most of the time when we encounter an exception at the server startup time, we need to read it very closely to understand what went wrong before we try to fix it.

Through FailureAnalyzer, Spring Boot provides a great way to intercept exception at the startup and will turn them in more human readable format (We don’t have to scroll through the entire stack trace). Spring Boot comes with a number of  FailureAnalyzer starting from application context related exceptions, JSR-303 validations and more.

Here is an example where port 8080 was already in use and when we tried to run our Spring Boot application on port 8080, PortInUseFailureAnalyzer intercepted this exception and provided a more readable and user-friendly error message.

***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

Here is a list of the few FailureAnalyzer provided by Spring Boot

  1. PortInUseFailureAnalyzer
  2. NoUniqueBeanDefinitionFailureAnalyzer
  3. BeanCurrentlyInCreationFailureAnalyzer

You can find a complete list of FailureAnalyzer by checking org.springframework.boot.diagnostics package under Spring Boot. 

Spring Boot provides an easy way to create our own custom FailureAnalyzer.

 

1. Creating Custom FailureAnalyzer

To create our own custom FailureAnalyzer, we can use AbstractFailureAnalyzer as our convenient extension point.AbstractFailureAnalyzer will check if a specified exception is present and will allow our custom analyzer to handle it.

Let’s create a custom FailureAnalyzer in Spring Boot for the following use case

  1. We will try to inject a different bean for a given dependencies.
  2. When we will try to inject it, Spring will throw BeanNotOfRequiredTypeException since we are trying to inject a different bean.

Here is our sample FailureAnalyzer code

public class CustomFailureAnalyzer extends AbstractFailureAnalyzer<BeanNotOfRequiredTypeException> {

    /**
     * Returns an analysis of the given {@code failure}, or {@code null} if no analysis
     * was possible.
     *
     * @param rootFailure the root failure passed to the analyzer
     * @param cause       the actual found cause
     * @return the analysis or {@code null}
     */
    @Override
    protected FailureAnalysis analyze(Throwable rootFailure, BeanNotOfRequiredTypeException cause) {
        String message ="####################### This is a custom fail Message ################ %n"+
                getDescription(cause);
        return new FailureAnalysis(message , (String)null, cause);
    }

    private String getDescription(BeanNotOfRequiredTypeException ex) {

        StringWriter description = new StringWriter();
        PrintWriter printer = new PrintWriter(description);
        printer.printf(
                "The bean %s could not be injected"
                        + "due to %s",
                ex.getBeanName(), ex.getRequiredType().getName());
        return description.toString();
    }
}

The main point is the analyze() method which will get triggered and Spring Boot will pass on a Throwable object along with the case (Exception which was thrown by Spring for our case).  We can get detail information from the cause instance to print a user-friendly message.

 

2. Registering Custom FailureAnalyzer

We need a special way to register our custom FailureAnalyzer with Spring Boot so as Spring Boot should be able to call our custom FailureAnalyzer in case exception is thrown by the system. We need to register it using spring.factories property file in META-INF folder.

In case META-INF or spring.factories properties file is not present, we need to create it manually. To register custom FailureAnalyzer, add following entry in spring.factories

org.springframework.boot.diagnostics.FailureAnalyzer=\
  com.umeshawasthi.failureanalyzer.CustomFailureAnalyzer

if you have multipleFailureAnalyzer You can register all of those in as a comma separated entries

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.umeshawasthi.failureanalyzer.CustomFailureAnalyzer,\ com.umeshawasthi.failureanalyzer.CustomFailureAnalyzer1

At this point, we are all set with our CustomFailureAnalyzer and ready to test it.

 

3. FailureAnalyzer in Action

I have created 2 classes in my demo project with the following signature

public class AdminDAO {

    public void helloAdmin(){
        System.out.println("Hello Admin");
    }
}
@Repository("adminDAO")
public class AdminDAOImpl {

    public void setupAdmin(){
        //default implimentation
    }
}

I have created another Controller where I am trying to inject “adminDAO” bean to AdminDAO.

@RestController
public class HelloWorldController {
   @Resource(name = "adminDAO")
   private AdminDAO adminDAO;
   //some methods
}

If I run my Spring Boot Application, Spring will try to inject adminDao of type AdminDAOImpl in AdminDAO, since these are not compatible, Spring will throw BeanNotOfRequiredTypeException. In the current use case, Spring Boot will check to determine a valid FailureAnalyzer is registered and will pass on information to registered FailureAnalyzer.

In our case, we have registered CustomFailureAnalyzer to handle such case, Spring Boot will pass on this information to our custom FailureAnalyzer to produce a more user-friendly message.

Here is the output when we will run our application
***************************
APPLICATION FAILED TO START
***************************
Description:
################# This is a custom fail Message ################ %nThe bean adminDAO could not be injecteddue to com.umeshawasthi.service.AdminDAO

Summary

In this article, we explored an interesting feature provided by Spring Boot. We saw how Spring Boot FailureAnalyzer work and how to create our own custom FailureAnalyzer.

All the code of this article is available Over on Github. This is a Maven-based project.

Java NIO2 File Attributes

Introduction to Java NIO2 File Attributes API

In this post, we will cover Java NIo2 File Attributes. File attributes are also known as metadata. Metadata can be used to find out information about the file systems like if it’s a regular file or a directory, who is the owner of the file or directory.

I have already covered Java NIO2Java NIO Path and Java NIO Selector as part of the new NIO features introduced in Java 7. 

 

Introduction

File metadata can be used to get information about the file ranging from the size of the file to the access permissions. These File Attributes can be used to check critical information before moving ahead with real file-based operations. 

I will be covering different metadata attributes in this post.

 

1.   Basic File Attributes

To get information about all the basic attributes of the file, we can use Files.readAttribute() method. This method will return BasicFileAttributes which can be used to access various basic file attributes.This approach is more efficient as we are not required to make a separate call to the underlying file system to read individual attributes.

We will get BasicFileAttributes for a given path and then check what all information we can get from this

Path path = Paths.get("/Users/umesh/personal/tutorials/source");
BasicFileAttributeView fileAttributeView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
BasicFileAttributes basicFileAttributes = fileAttributeView.readAttributes();

We first retrieved BasicFileAttributeView and retrieved.BasicFileAttributes from it.We went this route since BasicFileAttributeView contains set of file attributes consist of mandatory and optional file attributes as defined by the BasicFileAttributes interface.

Once we have BasicFileAttribute, we can get all basic file attribute information from it.

1.1   Check Creation Time

To find creation time of the file, use creationTime() method

basicFileAttributes.creationTime()

 

1.2  Last Access Time

basicFileAttributes.lastAccessTime()

 

1.3  Check for Directory

We can also check if a given path is a file or directory 

basicFileAttributes.isDirectory()

 

1.4  Basic Attribute Example

Here is complete example demonstrating various methods available to get basic file information.

Path path = Paths.get("/Users/umesh/personal/tutorials/source");
BasicFileAttributeView fileAttributeView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
BasicFileAttributes basicFileAttributes = fileAttributeView.readAttributes();

System.out.println("creationTime: " + basicFileAttributes.creationTime());
System.out.println("lastAccessTime: " + basicFileAttributes.lastAccessTime());
System.out.println("lastModifiedTime: " + basicFileAttributes.lastModifiedTime());

System.out.println("isDirectory: " + basicFileAttributes.isDirectory());
System.out.println("isOther: " + basicFileAttributes.isOther());
System.out.println("isRegularFile: " + basicFileAttributes.isRegularFile());
System.out.println("isSymbolicLink: " + basicFileAttributes.isSymbolicLink());
System.out.println("size: " + basicFileAttributes.size());

All method related to getting time returns FileTime object which is different than simple TimeStamp 

2.  File Owner Information

In order to get high-level file ownership information, We can use FileOwnerAttributeView provided by Java NIO2 API.

FileOwnerAttributeView fileOwner=Files.getFileAttributeView(path, FileOwnerAttributeView.class);
System.out.println("File Owner Name " +fileOwner.getOwner());

You can get information about the POSIX or DOS file attributes by passing DosFileAttributes.class or PosixFileAttributes.class to Files.getFileAttributeView() method.

 

3. File Store Attributes

Java NIO2 API provides a convenient FileStore class to get information about the file. We can use this class to get information about the underlying file system like how much space is available, how much used etc. 

FileStore store = Files.getFileStore(path);

long total = store.getTotalSpace() / 1024;
long used = (store.getTotalSpace() - store.getUnallocatedSpace()) /1024;
long available = store.getUsableSpace() /1024;

Summary

In this post, we covered basics as how to get information about the basic file attributes using Java 7 NIO2 File Attributes.

 

All the code of this article is available Over on Github. This is a Maven-based project.

Java Base64 Encoding and Decoding

Java Base64 Encoding and Decoding

In this post, we will explore various options of Java Base64 Encoding and Decoding. We will be covering mainly new Base64 API introduced in Java 8.

 

Introduction

Base64 encoding was missing from standard JDK before Java 8. Java 8 introduced a simple yet powerful API under java.util package or specifically a utility class java.util.Base64. In this post, we will be covering Java Base64 encoding and decoding.

The Base64 class consists of static factory methods for obtaining Base64 based encoder and decoder. We can obtain following 3 types of Base64 encoder/ decoder

  1. Basic
  2. URL and FileName
  3. MIME 

 

1.  Java 8 Basic Encoder

Java 8 Basic Base64 encoder is a simple encoder.It will simply encode without adding any line feed/line separator characters. 

void basicEncoder(final String input) {
    String simpleBase64 = Base64.getEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
    System.out.println(simpleBase64);
}

The output of the encoder will be mapped to characters in the Base64 Alphabet: A-Za-z0-9+/ and it will reject data that is outside this base64 alphabet.

 

1.1  Java 8 Basic Decoder

Decoding encoded String back to original form is quite simple with new API, all we have to do it to get encode and pass decoded data to it.

void basicDecoder(final String encodedData) {
    byte[] decodeData = Base64.getDecoder().decode(encodedData);
    System.out.println(new String(decodeData, StandardCharsets.UTF_8));
}

We are no longer required to use those external dependencies (e.g. Sun classes etc) to do encoding and decoding. 

2.  URL Encoding

URL encoding works very similarly to Basic encoding and it uses “URL and Filename safe Base64 Alphabet”. 

String input= "search?_base64";
void urlEncoding(final String input) {
    String urlEncode= Base64.getUrlEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
    System.out.println("Encoding using URL Encoder "+urlEncode);
}

2.1  URL Decoder

URL decoder work in a similar way as encoder work, we need to get UrlDecoder() and pass the encoded data to it.

void urlDecoding(final String encodedData) {
    byte[] decodeData = Base64.getUrlDecoder().decode(encodedData);
    System.out.println(new String(decodeData, StandardCharsets.UTF_8));
}

3.  MIME Encoding

MIME encoding will use Base64 encoding using Basic Alphabet and encoded output will be converted into MIME format (no more than 76 characters each and uses a carriage return ‘\r’ followed immediately by a linefeed ‘\n’ as the line separator).

private static void mimeEncoder(){
    StringBuilder stringBuffer = new StringBuilder();
    for (int t = 0; t < 10; ++t) {
        stringBuffer.append(UUID.randomUUID().toString());
    }

    String mimeEncoding = Base64.getMimeEncoder().
                          encodeToString(stringBuffer.toString().getBytes(StandardCharsets.UTF_8));

    System.out.println("MIME Encoding is " +mimeEncoding);
}

Output

MIME Encoding is:: ZjY5NzBkYTctMDFmNy00YmY3LTk4YjAtMmYxZGUzYzNhM2QwZTNmM2I4M2EtODg0Yy00ZjlkLTlm
YTgtMjIzZWY1ZTMzNGQ2ODVlZDA0ZDQtMjJjMy00NzUxLWEwYTYtYzM2ZTNhOTFjNzk0MmEwY2Iz
ZDYtYmRmNC00MmUzLTllMzQtZjIzMDRkMmMxMzgyMmIxNTExZjEtZDdkYS00ZjIwLTlhMzUtYjYy
ZTFiNTc3ZmQ1NzM3NDViM2ItNTRkMC00MTM4LTgxMjMtNmQ4ZDgyMzRlYTI4YTA1NjFhMGEtNWY3
NC00NDdmLTlhNWItOWIxNTgxOWY4NzJlMTRhZThmN2MtNjdiOS00ZDcwLWEwZmYtOGEyNjM3MDBm
NzNlMTRiNzdiY2YtYWI2ZS00MmNmLWI5NjAtMjFmZThmZjZmMmJjYWU0MmQ0MmUtZDE1ZC00NTdk
LThmMzUtNTUyMTlhMzRiMmYx

2.1  MIME Decoder

byte[] decodeData = Base64.getMimeDecoder().decode(encodedData);
System.out.println(new String(decodeData, StandardCharsets.UTF_8));

 

4.  Conclusion

In this post, we explored  Java Base64 Encoding and Decoding API introduced in Java 8. This new API is simple and powerful and at the same time will be available within the JDK without the need for external dependencies (commons-codec or sun.misc.BASE64Decoder).

All the code of this article is available Over on Github. This is a Maven-based project.

References

Base64

StackWalker API In Java 9

Introduction to StackWalker API In Java 9

In this post, we will be covering  StackWalker API in Java 9Stack Walking API is yet another features being introduced in Java 9

 

Introduction

To put Stack Walk API  in Java 9 in simple words, It provides capabilities to walk through the stack in Java. StackWalker provides a snapshot of the current thread stack trace along with some methods to access it.

Before Java 9, There was no standard / efficient way to access selected frames of the stack and get information about the Class instance of each frame. We have the following options available to get information from the Stack Trace

  1. getStackTrace() method from java.lang.Throwable Class which returns an array of StackTraceElement.

So if you want to get information about the stack trace before Java 9, a simpler code will look similar to 

StackTraceElement[] stackTrace = new Throwable().getStackTrace();

Above method require JVM to capture the snapshot of the entire stack and return this information back to the calling method / API. This is not a very efficient solution due to following use cases.

  1. Capturing the entire snapshot of the stack is not an efficient memory operation and will have an impact.
  2.  You might only need some frame from the stack but still, you will be provided with the entire snapshot.
  3. Taking into account the second point, We have to process some frames which might not be useful for us.
  4. One of the most important points is that as part of StackTraceElement objects, you will get information about the class name, method name but will never get hold of the actual Class instance.
  5. Some of the VM implementation may strip some stack information in favor of performance, so you might not get full stack information even when calling Thread.getStackTrace() method.

If you want you can use java.lang.SecurityManager.getClassContext() method to get access to the Class instance but I will not be covering that part in this post.

 

1. Why Use StackWalker

One of natural question which comes to our mind is why do we need  StackWalker API in Java 9? Here are some of the benefits which you will be getting from this new API.

  1. It will provide you a way to filter/skip classes which give us the flexibility to process our interest specific classes.
  2. StackWalker API provides a way to load only certain frames (e.g. load only 10 frames) which will be helping us to handle performance issue.
  3. We can directly get instance of the declaring class without using java.lang.SecurityManager.getClassContext() method.
  4. It will provide you a way to understanding application behavior more easily.

 

2. StackWalker Basic

Let’s cover some of the basic of the StackWalker API along with details as to how we can use it in future.StackWalker class is easy to use and provide some convenient method to work on the stack.

 

2.1 Obtaining a StackWalker

StackWalker API provides a static getInstance method which can be used to obtained StackWalker instance.

StackWalker stackWalker = StackWalker.getInstance();

There are other variants of the getInstance() method which can be used based on the individual requirements.

Let’s start building our example to demonstrate various features of the StackWalker API in Java 9.

 

3  StackWalker Demo

Here is our sample class with some method creating method chain.

package com.umeshawasthi.java9.example.stackwalker;

public class StackWalkerExample {


    public static void stackWalkerMethod1() {
        stackWalkerMethod1();
    }

    public static void stackWalkerMethod2() {
        stackWalkerMethod2();
    }

    public static void stackWalkerMethod3() {
        stackWalkerMethod3();
    }

    public static void stackWalkerMethod4() {
        mainWalkerMethod();
    }

    public static void printCompleteStackTrace() {

    }

}

3.1  Get All Stack Information

In order to get the complete stack, we will get an instance of the StackWalker and will use walk method to opens a sequential stream.

public static void printCompleteStackTrace() {

    List<StackWalker.StackFrame> stack = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
            .walk((s) -> s.collect(Collectors.toList()));

     stack.forEach(System.out::println);
}

In above method we get an instance of the StackWalker and use the walk method opens a sequential stream of StackFrames for the current thread. 

Here is the output of the above method.

java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.printCompleteStackTrace(StackWalkerExample.java:39)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.stackWalkerMethod3(StackWalkerExample.java:28)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.stackWalkerMethod2(StackWalkerExample.java:23)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.stackWalkerMethod1(StackWalkerExample.java:18)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.main(StackWalkerExample.java:13)

 

3.2  Filter StackFrames for Certain Classes

Let’s say we are only interested in a stack from a specific class, to achieve this we do not have to go through each and every frame. StackWalker API provides a convenient option to filter out results which are of our interest.

public void filterStackFrame() {
    List<StackWalker.StackFrame> filterFrames = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
            .walk((s) -> s.filter(f -> f.getClassName().contains(StackWalkerDemo3.class.getName()))
                    .collect(Collectors.toList()));

    filterFrames.forEach(System.out::println);
}

As we saw in above example, We are only interested in the StackFrame from the StackWalkerDemo3 class, so we passed it as a filter and StackWalker API will filter out it for us. Below is the output of the above code

java/com.umeshawasthi.java9.example.stackwalker.StackWalkerFilterExample$StackWalkerDemo3.stackWalkerMethod3(StackWalkerFilterExample.java:35)

3.3  Shows all Reflection and Hidden Frames

StackWalker API provides a way to show all reflection and hidden Frames which are hidden by default. StackWalker configured with this SHOW_REFLECT_FRAMES option will show all reflection frames, a similar way we can use SHOW_HIDDEN_FRAMES  to show all hidden frames.

 

public static void printCompleteStackTrace() {

    List<StackWalker.StackFrame> stack = StackWalker.getInstance(StackWalker.Option.SHOW_REFLECT_FRAMES)
            .walk((s) -> s.collect(Collectors.toList()));

     stack.forEach(System.out::println);
}

3.4  Limit Number of StackFrames

Let’s say we just want the top 3 stack frames from the current thread, we can use limit option for achieving this. 

List<StackWalker.StackFrame> stack = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
        .walk((s) ->s.limit(3).collect(Collectors.toList()));

 

3.5  Get Calling Class Instance

We discussed in the starting of this post that StackWalker API provides a way to get hold of the calling class Instance which was not possible before Java 9 (We do have some indirect way). To get hold of the calling class instance you need RETAIN_CLASS_REFERENCE while getting StackWalker instance.

RETAIN_CLASS_REFERENCE will retain an instance of all classes walked by StackWalker, we can use getCallerClass and getDeclaringClass method to get hold of the class instance.

 

public static void getCallerClass() {

    Class calledClass = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
            .getCallerClass();

    System.out.println("Caller Class is " +calledClass.getCanonicalName());
}

Output of above program is

Caller Class is com.umeshawasthi.java9.example.stackwalker.StackWalkerGetClass

 

4  Summary

In this post, we explore StackWalker API being introduced in Java 9. We checked how we can get stack based on our requirement with an option to filter or limit results along with the ability to display hidden frames. We explored possibility to get hold of the calling Class instance using Java 9 StackWalker API

If you are interested in learning other features being introduced in Java 9, Please read following posts on Java 9

Java 9 REPL

Collection Factory Methods in Java 9

All the code of this article is available Over on Github. This is a Maven-based project.

References

JEP 259

StackWalker

@ConfigurationProperties in Spring Boot

Introduction to @ConfigurationProperties in Spring Boot

In this article, we will be covering @ConfigurationProperties in Spring Boot. Spring Boot provides a very clean way to load properties for a given application.It provides an easy and manageable way to externalized configurations along with the ability to bind and validate these configurations.

 

1. Introduction

Consider following entries in a property file (say custom.properties)

user.firstName = Umesh
user.lastName = Awasthi
user.greeting = Hello Umesh
user.blogName = umeshawasthi.com

If I have to use these property files in the Spring application (without Spring Boot), I will be using it in following way

public class SimpleSpringPropertyTest {
    @Value("${user.firstName}") private String firstName;
    @Value("${user.lastName}") private String lastName;
 } 

@Value("${proprties}") annotation is quite handy and easy to use, but it will really be a very tedious process if we have a number of properties. Spring Boot has introduced a new approach to handling these properties in a more clean way with an option to validate these configuration value.

 

2. Setup

We do not need any special setup to enable @ConfigurationProprties feature in Spring Boot, We need to define spring-boot-starter-parent as our parent in our project’s pom.xml

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.3.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

Above entry in pom.xml will ensure that all required dependencies are in your class path.

 

3. Introduction to @ConfigurationProprties

In order to understand this feature, we can take an example of a custom property file which contains configuration properties for Database, Email Server and something else, on a high level that property might look like


#Database Configuration

db.driver =org.hsqldb.jdbcDriver
db.username	=test
db.password	=test
db.tablePrefix =_prefix

#SMTP Configuration

mail.from [email protected]	 
mail.host [email protected]
mail.port =25
mail.security.userName 	=test
mail.security.password 	=test

#Server Configurations

server.tomcat.httpPort =80
server.tomcat.sslPort =443
server.tomcat.ajpPort =444
server.tomcat.jmxPort =445

#Global Properties
username=umesh
welcomeMessage = Welcome Umesh!!!

3.1 Binding Properties

We will start by creating a separate POJO class to store and handle our application specific configuration properties by annotating it with @ConfigurationProperties 

@Configuration
@ConfigurationProperties
public class ApplicationConfigurationProp {

}

@Configuration annotation will allow Spring to detect and register this Bean which means we can inject this configuration bean in our application. Above code will work fine if we want to access only global properties (i.e. username and welcomeMessage).

@Configuration annotation is most suitable when we want to access hierarchical properties and we want to access/filter properties based on the prefix. Let’s say we want to bind all the properties starting with prefix “mail” to our  ApplicationConfigurationProp  Class, we can use prefix property on the @ConfigurationProperties annotation.

 

@Configuration
@ConfigurationProperties(prefix = "mail")
public class ApplicationConfigurationProp {


    private String from;
    private String host;
    private int port;

    //getter and setter

    public static class Security{
        private String userName;
        private String password;

        //getter and setter
    }

}

Once we run above application, all properties defined in the property files with prefix “mail” will automatically be bind / assigned to this object.

 

3.2 Binding Custom Properties File

While working on the above example we assume that all these properties are defined in the Spring Boot’s application.properties file, let’s say we want to define these properties in our custom property file (custom.properties) and not in the application.properties file. We can use @PropertySource annotation to define custom property file.

@Configuration
@PropertySource("classpath:custom.properties")
@ConfigurationProperties(prefix = "mail")
public class ApplicationConfigurationProp {
}

 

3.3 Relaxed binding

One of the interesting features of the Spring Boot property binding is “relaxed binding rules”. Under relaxed binding, Spring Boot doesn’t need to be an exact match between the properties.

For a given property db.username, all of the following variation are valid in Spring Boot property binding

Property NameDescription
db.userName 
db.user-name Dashed notation will work for username
db.user_name underscore notation
db.USER_NAMEupper case format

 

4. Property Validation

We can use JSR-303 Validation API to validate property defined using@ConfigurationProperties. In order to use bean validation with Spring Boot, we need to add JSR-303 compliant validation API in our project. For this post, I will be using Hibernate Validator by adding it in our pom.xml file

<dependency>
    <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>5.4.1.Final</version>
   <relativePath/>
</dependency>

We need to add standard @Validated annotation in order for bean validation to validate given bean. To understand how Bean Validation will work with @ConfigurationProperties let’s take an example where we want to ensure that userName should be validated against following rules

  1. Minimum length of username should be 5
  2. User Name length can not be more than 10.

In order to achieve this, we will be adding JSR-303 javax.validation constraint annotations directly on your configuration class.

@Configuration
@PropertySource("classpath:custom.properties")
@ConfigurationProperties(prefix = "mail")
@Validated
public class ApplicationConfigurationProp {

    @Valid
    private Security security= new Security();

    public static class Security{

        @Length(max = 10, min = 5)
        private String userName;

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }
    }

}

We have following property file defined in our custom.properties file 

mail.security.userName  =test

If we run our application, Spring Boot will try to bind userName property in our configuration class and it will throw error as validation will fail for the given property


***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target com.umeshawasthi.confi[email protected]69637b10 failed:

    Property: mail.security.userName
    Value: test
    Reason: length must be between 5 and 10


Action:

Update your application's configuration

I have used .properties file in this post, Please note that @ConfigurationProperties supports both .properties and .yml file

5. Complex or Nested Properties

I have taken a simple example (with nested class) to demonstrate how Spring Boot can map these properties in our configuration class, We can use similar techniques to bind even complex hierarchy using Spring Boot’s @ConfigurationProperties

app.servers[0]=dev.test.com
app.servers[1]=foo.test.com

To bind above properties using Spring Boot’s @ConfigurationProperties, We only need to define properties in the target bean either as a java.util.List, or Set. Converting these properties in to List or Map will be handled by Spring DataBinder. (You can even register your custom Data Binder to map custom properties).

@ConfigurationProperties(prefix="app")
public class AppConfig {

    private List servers = new ArrayList();

    public List getServers() {
        return this.servers;
    }
}

Summary

In this post, we explored @ConfigurationProperties in Spring Boot. We explored how this is being used by Spring Boot to bind properties in our object. We checked how to specify customer property path for binding properties and way to validate injected properties using JSR-303 Bean Validation API. We touched briefly relax binding feature. 

Spring Boot Provides a very clean and flexible approach to bind property files in configuration object.

 

Complete Example

All the code of this article is available Over on Github. This is a Maven-based project.

Java NIO2 WatchService

Java NIO2 – Watching a directory for changes

Java NIO2 WatchService was introduced in Java 7 as part of the NIO2. WacthService provides the ability for monitoring a file or directory for change.

In this articles, we will explore this exciting yet less known feature introduced under Java 7 NIO.  

 

1. Introduction 

WatchService can also be called as notification API, It allows the user to register directory(s) with the service with the ability for us to define a type of event we are interested (like file creation, deletion etc. ), it will notify user when it will detect change in the directory(s).

e.g. Let’s say you want to detect any if a new file(s) are being created in a given directory, you can use WacthService to register this directory and tell service to notify you if a new file is being created.

Most of the modern IDE provide such feature which enables them to detect any file change happening in the workbench (Have you ever seen a popup indicating file has been changed, please update ). If we want to implement a similar feature, we can create a polling API but the solution might not be perfect.

Java 7 NIO2 WacthService is a scalable solution to achieve above objectives.

 

2. WatchService Overview

The first step is to create a WatchService instance using FileSystems class

WatchService watchService = FileSystems.getDefault().newWatchService();

Register all directories with WatchService, which we are planning to monitor, during this registration we also need to specify what kind of event  we are interested in

Path directory = Paths.get("/Users/umesh/personal/tutorials/source");
WatchKey key = directory.register(watchService,
        ENTRY_CREATE,
        ENTRY_DELETE,
        ENTRY_MODIFY);

Pay close attention to following 2 points

  1. Path’s register method took WatchService as the first method
  2. The second argument to the method is of type StandardWatchEventKinds, which indicates what kind of event we are interested.

We can only register Watchable interface with WacthService and since Path class implements it, so this directory/path got registered with WacthService.

 

3.  StandardWatchEventKinds

While registering with WacthService, we need to specify what event(s) we are interested in. You can pass any or all of the following value during registration.

 

Event NameDescription
ENTRY_CREATETriggered when a new entry is created in the watched directory (file or directory creation).
ENTRY_DELETETriggered when an entry is deleted/ moved in watched directory.
ENTRY_MODIFYTriggered when an entry is modified in the watched directory.
OVERFLOWIndicates that events might have been lost or discarded. You do not have to register for the OVERFLOW event to receive it.

You won’t be able to register individual files in WacthService. Service will throw NotDirectoryException in case you will register files with WacthService.

 

3.  WatchKey

When we register with WacthService, it returned WacthKey as a token, WacthKey contains certain state.

  1. When we first register with WatchService, WacthKey will be in ready state.
  2. In the case of an event, the key is signaled and queued so that it can be retrieved.
  3. WatchKey will remain in the same state until we call reset method.

 

4.  Processing Event

WatchService do not have any callback feature, it provided number of different ways to poll for getting this information

WatchKey pollEvent= watchService.poll();

poll() method will return queued key if available or will return null if unavailable.

WatchKey watchKey = watchService.poll(long timeout, TimeUnit units);

Above will return key immediately if available, in case it is not available, API will wait till the time specified in “timeout” parameter.

If we want to wait till the event occurred, We can use wait() method of the API. This method will return key immediately (if available) else it will wait for the event

WatchKey wait = watchService.take();

For WacthService to work correctly, we need to put the event back in the ready state once it has been processed. Call reset method on the WacthKey to reset it

key.reset();

In order to process rest of events, we need to fetch List of WatchEvent from the pollEvent() method. Here is a small example indicating how to handle and process these events in a real life use case.

WatchKey wait;
while ((wait = watchService.take()) != null) {
    for (WatchEvent<?> event : key.pollEvents()) {
        if (event.kind() == ENTRY_CREATE) {
            //handle create
        }
        if (event.kind() == ENTRY_DELETE) {
            //handle delete
        }
    }
}

5.  Complete Example

package com.umeshawasthi.tutorials.corejava.io.nio2;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

import static java.nio.file.StandardWatchEventKinds.*;

/**
 * Created by umesh on 6/15/17.
 */
public class NIOWatchService {

    public static void main(String[] args) throws IOException, InterruptedException {

        WatchService watchService = FileSystems.getDefault().newWatchService();

        Path directory = Paths.get("/Users/umesh/personal/tutorials/source");
        directory.register(watchService,
                ENTRY_CREATE,
                ENTRY_DELETE,
                ENTRY_MODIFY);

        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                if (event.kind() == ENTRY_CREATE) {
                    //handle create
                }
                if (event.kind() == ENTRY_DELETE) {
                    //handle delete
                }

                System.out.println(event.kind()+ " Event Happened on "+event.context());
            }

            key.reset();
        }
    }
}

When we run this program and done some changes in the source directory, we saw following output

ENTRY_MODIFY Event Happened on index2.html
ENTRY_MODIFY Event Happened on .DS_Store
ENTRY_CREATE Event Happened on untitled folder
ENTRY_MODIFY Event Happened on .DS_Store
ENTRY_CREATE Event Happened on WatchService
ENTRY_DELETE Event Happened on untitled folder

 

6.  When to Use WatchService

Watch Service API provides really some interesting features and  can be used in following places easily

  1. Processing files (e.g. Processing product price file), If price file is dropped in the directory, it will notify custom program to process it.
  2. An application server that watches a directory, waiting for some file to redeploy.

 

In this article, we explore one of the interesting feature introduced under Java 7 NIO Package. We explored various features of WatchService API and discussed how to use the different poll method to get information about the event. We also created a complete example to demonstrate how all these pieces work together.

All the code of this article is available Over on Github. This is a Maven-based project.

 

References

WatchService

Java Garbage Collector

Introduction to  Java Garbage Collector

In this post, we will explore what is Java Garbage Collector, How Java Garbage Collector Work? We will also cover what are the different Garbage collector available in Java and what are the new enhancement/improvement available in Java 8.

This post covers basic of the Java Garbage Collector API and does not provide inside view of the API.

 

1. What is the garbage collector in Java

In very simple terms, garbage collection is an automatic memory management programme in Java which removes the unused object in a Java programme. It process heap memory and will identify the object which are in use and which are not.It looks for objects which are not in use and simply get rid of those unused objects.

for (String name : nameList) {
    String s = name.getName();
}

In above code, We are creating String object in each iteration and if you pay attention, the object created in the previous iteration is no longer in use, if we will keep running this loop (say 1000 time), we will create these objects which are no longer in reference and us simply call these objects are Garbage. Each object creation takes some memory and if we keep on going (say 100000 times) at some point JVM will run of memory.

In order for better memory management, JVM comes with Garbage Collector which perform automatic memory management (i.e. JVM will pull it whenever required to clean up some memory).

 

2. How Java Garbage Collection Really Works

One of the main misunderstandings about the Java Garbage Collector is that it remove dead objects (not in reference) which it works in opposite way ( 🙂 ). Garbage collector keeps trek of all the live objects and everything else is marked as garbage.

In theory, Java Garbage collector work in a very simple fashion

  1. When an object is no longer in use, Garbage collector will claim memory used by this unused object and will use it for future object creation.
  2. There will not be any explicit object deletion and head memory will remain with JVM.

In order to determine which object is alive and which is garbage, JVM uses a special object also known as GC root (garbage collection root). JVM will treat the object as alive if the programme can reach to root object.

I will skip this discussion as to how JVM marked an object as GC root, this topic needs a separate blog post.

2.1 Mark and Sweep Algorithm

JVM uses the mark and sweep algorithm to determine/mark which object is in use and which is no longer in use. This algorithm work in 2 steps

  1. In the first step, it will process all references and will mark all those objects which are alive.
  2. As a second step, it will reclaim all the heap memory for all the objects which are not marked as alive.

While it seems simple, keep in mind that Garbage collector mark object alive based on the reference, in case you created an object which is not in use but still referred by some instance, it will be treated as alive object (even it is not in use).

 

3. Java Garbage Collector Types

One of another major misunderstanding about Java Garbage collector is that JVM has only 1 Garbage collector but the truth is there are around 5 garbage collectors (as per JDK7).

We will be covering these different garbage collector in the next segment. All these GC algorithms work on a very fundamental assumption that “Objects in Heap are short lived and should be recycled as quickly as possible.

 

3.1 Serial GC

It’s the simplest and least usable one. It was mainly designed for a single threaded environment. Do not use Serial GC. One of the main issue with Serial GC is its ability to freeze all threads whenever it’s active (one of the reasons why it is called as Serial GC), this can cause serious application performance issue.

In order to enable Serial GC, you need to pass following parameters to the JVM 

-XX:+UseSerialGC 

 

3.2 Parallel GC

This is the default GC in Java 7 and Java 8. Parallel GC use multiple threads to scan heap for the GC process. Having the ability to use multiple threads makes this GC much faster, however, it will stop all application thread whenever it’s performing GC operation (full or partial GC operation). Parallel GC is also known as Throughput collector.

This is the default GC for the JVM, in case you want to change some other GC collector to Parallel GC, you need to specify following JVM parameter

-XX:+UseParallelGC

 

3.3 CMS GC

Concurrent-Mark-Sweep also known as CMS GC use multiple threads to scan through the head for possible GC process. It works as follows

  1. It used multiple threads to scan through the heap and will recycle unused object 

Multiple threads denote concurrency, scanning head denotes marking (where it marks alive object in heap) and recycles unused objects is marked as sweep hence Concurrent-Mark-Sweep. One of the main advantages of this algorithm is having a very slow pause time of application threads as it works in parallel to application threads (without stopping them ).

This GC is best suitable for application where application response time is a critical aspect. CMS GC has some disadvantages.

  1. Since it works in concurrency mode, it usually requires more memory and CPU usage.
  2. In case running application have done some changes to the heap state when GC was running, it will be forced to redo some final steps to make sure it has the updated reference information.
  3.  One of the main disadvantages of the CMS GC is encountering Promotion Failure (Long Pauses) which happens due to the race conditions.

This does not default GC in JVM, use the following command to enable it for the underlying JVM

XX:+USeParNewGC

 

3.3 G1 GC

JDK 7 introduced a new GC known as The Garbage-First (G1), collector. One of the fundamental difference between G1 Collector and other collector is a division of the Heap into multiple regions.The JVM generally targets around 2000 regions varying in size from 1 to 32Mb. 

G1 collector normally uses multiple background threads to scan these regions and will pick the region with most garbage objects (that’s why we call it Garbage First). 

In order to enable this GC, you need to pass the following parameter to JVM. 

 XX:+USeG1GC

There are couple of advantages of over other GC 

  1. It’s fast as compare of other GC since it will target region with most garbage objects.
  2. G1 GC will compact heap on the go which other GC lacks.
  3. Since G1 split Heap into multiple regions, a common “stop the world (pausing all running application threads )” is avoided by this GC (In place of scanning entire heap, it will scan on region basis).
  4. G1 GC is really a performance boost in the current scenarios where big heap size and multiple JMV per machines is common architectures

 

3.4 G1 GC and Java 8

Java 8 added a new feature called String Deduplication , String takes a lot of heap size and this new feature will ensure if a given String is duplicated across the heap, it will be automatically pointed to same internal char[], thus avoiding multiple copies of the same content. 

Use following JVM argument to enable this feature

-XX:+UseStringDeduplication

It tries to Reduce the Java heap live-data set by enhancing the G1 garbage collector so that duplicate instances of String are automatically and continuously deduplicated.

When G1 GC come into picture, it will perform following operations

  1. It scans objects in the heap and check is applied to see if the object is a candidate for string deduplication.
  2. All such items are added to a queue and deduplication thread will process this queue to make sure all duplicate instances are pointing to the same internal char[].

Another significant change happened in Java8 memory management is the removal of PermGen. It indicates that this memory management will also be performed by JVM and it’s a step to handle those OutOfMemoryError.

Please read Will Java 8 Solve PermGen OutOfMemoryError? to get more details and reasons for removing it in Java 8.

 

I hope that it will give you a high-level overview of different Garbage Collector available in Java along with how they work and how we can be configured in the JVM. We also get a high-level overview of the new enhancement and changes introduced in the Java 8 for the G1 collector.

Java NIO Selector

Java NIO Selector

In this post, we will explore feature and the basic understanding of Java NIO Selector API. The selector is an NIO component with an ability to monitor or examine multiple channels and determines which is ready for the IO operation (read or write).

One of the benefits of this is to use single thread to manage multiple channels which in simple terms is “multiple network connections”

1.  Use of  NIO Selector 

If you are familiar with threads, you must be aware that switching between thread is an expensive process as it involves underlying operating system, also thread means a new process which eventually will consume some memory. (With new OS, switching threads is not a big issue)

With Java NIO Selector, you can use a single thread to manage multiple channels, in other words, you are not creating multiple threads to manage multiple channels.

Java NIO Selector
Java NIO Selector

2.  Selector Configurations

The selector is part of the java.nio package. We can register multiple channels with Selector, once registration is done, Selector API will inform us if any NIO activity happens with these registered channels.

3.  Creating Selector

A new selector can be created by using open method of Selector class.JDK internally call system-wide default SelectorProvider.

Selector selector = Selector.open();

 

3.  Register Channels with Selector

For Selector to monitor different channels, we need to register these channels with Selector.To register, use register method of the selectable channel.

SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("https://www.javadevjournal.com",80));

socketChannel.configureBlocking(false);
SelectionKey key= socketChannel.register(selector, SelectionKey.OP_READ);

with configureBlocking(false), we are setting it in non-blocking mode. While registering the first parameter passed to register method is the selector.

The second parameter is called “interest set”, it indicates at what even selector should notify us. SelectionKey provides following 4 options as “interest set”

Operation NameDescription
OP_READWhen server is ready to read from Channel
OP_WRITEReady to write
OP_CONNECTWhen the client is trying to connect.
OP_ACCEPTWhen the server accepts client connection request

Register method will return SelectionKey represent channel register with the selector. 

 

4.  Selection Key

Channel registration with the selector return SelectionKey object SelectionKey is a representation of the SeletableChannel and contains few of the interesting elements, in order to utilise selector efficiently, a basic understanding of these elements is desired.

4.1  Interest Set

Interest set contains information about the event we are interested. It is an integer value. We can use interestOps() method to get set which is valid for current Channel.

We can use int value returned by interestOps method along with SelectionKey class to determine correct interest set.

int interestSet= key.interestOps();

 

4.2  Ready Set

Ready set defined a set of event that selected channel is ready for, the Ready set is also represented by an integer value.Use readyOps() method to get information about the Ready Set.

int readySet= key.readyOps();

Alternatively, you can use SelectionKey’s utility method to get these values.

key.isAcceptable();
 key.isConnectable();

 

Keep in mind that these methods will return a boolean value and not an integer.

4.2  Channel and Selector

Use SelectionKey class to get information about the associated Channel and Selector 

key.channel();
 key.selector();

 

5.  Channel Selection Process

As of now we have done following work 

  1. Create Selector.
  2. Create Desired Channel.
  3. Register channel with the selector.

Once we register multiple channels with the selector, use the select method to get the interested channel  (e.g If we want Channel ready for reading, we will get channel ready for reading).

selector.select();

Above method will work in blocking mode, It returns only after at least one channel is selected.Returned int value represents a number of channels ready for the operation.

As I said, select() the method will give us a hint as how many channels are ready for the operation, we can access all these ready channels by using selectedKeys() method.

Set<SelectionKey> readyToUseChannel= selector.selectedKeys();

You can iterate over the set to get information about the ready channels and can use the desired channel to perform required information (Read, Write operation etc.).

Set<SelectionKey> readyToUseChannel= selector.selectedKeys();

for(SelectionKey selectionKey : readyToUseChannel){
    if(selectionKey.isAcceptable()){
        // connection accepted
    }
    else if(selectionKey.isReadable()){
        //channel ready to read
    }
}

References

Selector

Java Directory Size

Java Directory Size

In this post, we will learn how to get the Java directory size or size of a folder in Java using Java 7, Java 8 and Apache Commons API.

 

1.  Get Size Using Java 7

We will be using Files.walkFileTree() method to recursively transverse through the files/directory to calculate the size.

public class DirectorySizeJava7 {

    public static void main(String[] args) throws IOException {

        Path rootDirectory= Paths.get("/Users/umesh/personal/tutorials/source/bootstrap");
        AtomicLong size= new AtomicLong(0);

        Files.walkFileTree(rootDirectory, new SimpleFileVisitor<Path>(){

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                    throws IOException{

                 size.addAndGet(attrs.size());
                return  FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exception)
                    throws IOException
            {
               //log exception
                throw exception;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exception) {

                //log exception for error in reading file if exception is not null
                return FileVisitResult.CONTINUE;
            }

        });

        System.out.println("size of the folder is :: " + size);
    }

}

Output

the size of the folder is:: 1650691

I have used AtomicLong in above example to store size, which guarantees that the value can be used in a concurrent environment.

 

2.  Get Size Using Java 8

We will be using  Stream API along with Lambda expression provided by Java 8 to calculate the size of the folder.

public class DirectorySizeJava8 {

    public static void main(String[] args) throws IOException {

        Path rootDirectory = Paths.get("/Users/umesh/personal/tutorials/source/bootstrap");

        long directorySize = Files.walk(rootDirectory)
                .map(f -> f.toFile())
                .filter(f -> f.isFile())
                .mapToLong(f -> f.length()).sum();
    }
}

 

We used stream API and making sure to filter out all directories by using filter(f -> f.isFile()). Please be aware that length method is not guaranteed to be 0 for directories. 

We converted the result to LongStream by using mapToLong method and finally summed up the results to get the size.

Output

the size of the directory is::1650691

Note

Keep in mind following information while using  walkFileTree or walk method under Java 7 and Java 8

  1. Underlying Java Security Manager can throw an exception in case we do not have permission to access it.
  2. Symbolic links can lead to infinite loop issue.

 

3.  Get Size Using Apache Commons

Apache Commons IO’s FileUtils class provide a clean way to calculate the size of a given directory.

public class DirectorySizeApacheCommons {

    public static void main(String[] args) {

        File rootDirectory = new File("/Users/umesh/personal/tutorials/source/bootstrap");
        long size= FileUtils.sizeOfDirectory(rootDirectory);

        System.out.println("The Size of directory is:: "+size);
    }

}

Output

The Size of directory is:: 1650691

You need to be aware of the following 

  1. You have to check if the file is directory else API will throw IllegalArgumentException.
  2. It might also throw IllegalArgumentException if the directory is being concurrently modified. Check IO-449.

 

4.  Get Size Readable format

Printing information in human readable format is always a preferred way. Here is a small programme to print size information obtained in this post in human readable format.

public class DirectorySizeApacheCommons {

    public static void main(String[] args) {

        File rootDirectory = new File("/Users/umesh/personal/tutorials/source/bootstrap");
        long size= FileUtils.sizeOfDirectory(rootDirectory);
        readableFileSize(size);
    }

    public static void readableFileSize(long size){
        final String[] units = new String[] { "B", "kB", "MB", "GB", "TB" };
        int unitGroups = (int) (Math.log10(size)/Math.log10(1024));
        System.out.println(new DecimalFormat("#,##0.#").format(size/Math.pow(1024, unitGroups)) + " " + units[unitGroups]);
    }

}

All the code of this article is available Over on Github. This is a Maven-based project.

References

Apache Commons IO

DecimalFormat

AtomicLong

Java 9 REPL

Introduction to Java 9 REPL

In this post, we will explore Java 9 REPL (Read-Evaluate-Print-Loop) feature or shortly called as JShell. Many modern languages provide a tool (Mostly called as REPL or scripting tool) for real-time statement interpretation.

One of the benefits of such tool is that you can easily test your code without creating a complete class or project.Java 9 will be introducing REPL or JShell which can be used to quickly run your code and compare results. 

This post assumes that you already have Java 9 installed on your machine, if this is not the case, install Java 9 on your machine before moving forward. 

REPL Concept is not new and some of the modern languages have provided this feature, here is the list

  1. Groovy Console
  2. Beanshell
  3. Scala

If we want to run some programme in Java (Java 8 or lower version), We need to create a project and the main method to run that code and any change require a recompile and repeat this process.

1. What is Jshell

Jshell will be shipped as part of the Java 9 and will work as scripting shell to run your Java code without the need of creating project or class with the main method.

To run Jshell, run following command with -v to get information about the version


localhost:~ umesh$ jshell -v
|  Welcome to JShell -- Version 9-ea
|  For an introduction type: /help intro

jshell> 

If you have Java 9 configured correctly, Jshell will greet you with a Unix style welcome message.

2. What is Jshell

Jshell comes with a certain set of default import. This indicates you don’t have you do explicit import for these to run you programme, to list default imports run /import command in Jshell


jshell> /import
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.nio.file.*
|    import java.util.*
|    import java.util.concurrent.*
|    import java.util.function.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.util.stream.*

jshell>

Jshell /import will give you a list of import for the current session, this means if you will add additional import and run this command again, those import will be added automatically by Jshell for the current session.

3. Simple Hello Word

Running and printing simple hello work using Jshell is quite simple and you don’t need to write a complete .java class for this.


jshell> System.out.println("Hello World from Jshell!!!");
Hello World from Jshell!!!

jshell>

Jshell is flexible in nature and you can even skip adding ; at the end of the statement and Jshell will handle it internally.


jshell> System.out.println("Hello World from Jshell!!!")
Hello World from Jshell!!!

jshell>

4. Creating and Running Method

Methods can be created and executed easily using Jshell


jshell> void helloWorld(){ System.out.println("Hello World!!");}
|  created method helloWorld()

jshell> helloWorld()
Hello World!!

jshell>

Jshell even allows you to modify your existing code, Let’s say we want to change “Hello World!!” to “Hello World from JShell”, you can easily change it.


jshell> void helloWorld(){ System.out.println("Hello World from JShell!!");}
|  modified method helloWorld()
|    update overwrote method helloWorld()

jshell> helloWorld()
Hello World from JShell!!

jshell>

5. Expressions

Jshell will accept any valid Java expression, Jshell will execute the expression, it will provide you information about the value, value type.


jshell> 3+7
$5 ==> 10
|  created scratch variable $5 : int

jshell> $5
$5 ==> 10
|  value of $5 : int

jshell>

Jshell provides you with a detailed information about the new variable ($5) it created and what is the value assigned to this new variable.You can even refer to this variable by just naming it $5

6. Variables

You can create variable and even name those variables using JShell, these variables will be visible in the current Jshell context and you can change/modify values as per your need.


jshell> int i=10
i ==> 10
|  created variable i : int

jshell> String blogName="Umesh Awasthi";
blogName ==> "Umesh Awasthi"
|  created variable blogName : String

jshell> blogName= blogName+" Java 9 REPL";
blogName ==> "Umesh Awasthi Java 9 REPL"
|  assigned to blogName : String

jshell> blogName
blogName ==> "Umesh Awasthi Java 9 REPL"
|  value of blogName : String

jshell>

7. Commands

Jshell provide number of build in command which can be used to get some insight on to the JShell, you can run these command on the JShell using forward slash (“\”) 


jshell> /vars
|    int $5 = 10
|    int i = 10
|    String blogName = "Umesh Awasthi Java 9 REPL"

jshell> /methods
|    void helloWorld()

jshell>

You can use /vars to list all variable in the current context, a similar way you can use /methods to list down all the method in the current context. Use /help to start Jshell help menu.

8. List

Jshell is quite powerful and it keeps trek of the activities happening in the current context, however, it’s not an IDE and you might want to get a list of all variables or methods or values being used in the context, Jshell provides /list method to give you all the information.


jshell> /list

   2 : helloWorld()
   3 : void helloWorld(){ System.out.println("Hello World from JShell!!");}
   4 : helloWorld()
   5 : 3+7
   6 : $5
   7 : int i=10;
   8 : String blogName="Umesh Awasthi";
   9 : blogName= blogName+" Java 9 REPL";
  10 : blogName

jshell> 

9. Save and Reload

Use /save method to save expression history, it will save a file in the same directory from which we are running the Jshell. To open saved file, we can use /open a command.


jshell> /save jshell.java
jshell> /open jshell.java

10. Forward reference

JShell provides a very good support for forward reference, this means we can refer to variable or methods which we are planning to introduce later in our code.

code class="language-vim">
jshell> double totalPendingAmount(int customerNumber){ return getCustomerPendingAmount(customerNumber);}
|  created method totalPendingAmount(int), however, it cannot be invoked until method getCustomerPendingAmount(int) is declared

jshell>

The interesting part is the output of above command, JShell indicating that we will not be able to use this method until getCustomerPendingAmount(int) is defined.

11. JShell API

Jshell also provides API which can be used by external parties to use Jshell capabilities. 

12. Why use Jshell

We are going to have a very natural question “Why use Jshell ??” , I will try to come up with some use cases where it will really be handy to use Jshell 

  1. JShell API provides a way to have a network connection, We can use it to connect to our remote server and may change few things remotely.
  2. We can even connect to DB and perform some operations.
  3. API can be used to hook into live JVM’s to get an insight of it.
  4. We can use JShell to determine and verify return type (Check video for detail)
  5. Rapid prototyping, You can quickly modify and run your programme without waiting for multiple rebuilds or redeploy.

13. Video Tutorials

It is always interesting to see things in action. Please watch this video to see Jshell in action.

Conclusion

Jshell is really interesting and powerful tool for rapid prototyping. I believe that Jshell will become a friendly tool for developers on a day to day life. Jshell has a lot of use cases but the best one for me is the ability to quickly test your code without getting into long build cycles.

Read Collection Factory Methods in Java 9  to learn how to create immutable collection in Java 9.