Passing Data to Future Steps in Spring Batch

It is often useful to pass information from one step to another. This can be done through the ExecutionContext. The catch is that there are two ExecutionContexts: one at the Step level and one at the Job level. The Step ExecutionContext remains only as long as the step, while the Job ExecutionContext remains through the whole Job. On the other hand, the Step ExecutionContext is updated every time the Step commits a chunk, while the Job ExecutionContext is updated only at the end of each Step.

The consequence of this separation is that all data must be placed in the Step ExecutionContext while the Step is executing. Doing so ensures that the data is stored properly while the Step runs. If data is stored to the Job ExecutionContext, then it is not persisted during Step execution. If the Step fails, that data is lost.

public class SavingItemWriter implements ItemWriter<Object> {
    private StepExecution stepExecution;

    public void write(List<? extends Object> items) throws Exception {
        // ...

        ExecutionContext stepContext = this.stepExecution.getExecutionContext();
        stepContext.put("someKey", someObject);
    }

    @BeforeStep
    public void saveStepExecution(StepExecution stepExecution) {
        this.stepExecution = stepExecution;
    }
}

To make the data available to future Steps, it must be “promoted” to the Job ExecutionContext after the step has finished. Spring Batch provides the ExecutionContextPromotionListener for this purpose. The listener must be configured with the keys related to the data in the ExecutionContext that must be promoted. It can also, optionally, be configured with a list of exit code patterns for which the promotion should occur (COMPLETED is the default). As with all listeners, it must be registered on the Step as shown in the following example:

Java Configuration

@Bean
public Job job1() {
	return this.jobBuilderFactory.get("job1")
				.start(step1())
				.next(step1())
				.build();
}

@Bean
public Step step1() {
	return this.stepBuilderFactory.get("step1")
				.<String, String>chunk(10)
				.reader(reader())
				.writer(savingWriter())
				.listener(promotionListener())
				.build();
}

@Bean
public ExecutionContextPromotionListener promotionListener() {
	ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();

	listener.setKeys(new String[] {"someKey" });

	return listener;
}

Finally, the saved values must be retrieved from the Job ExecutionContext, as shown in the following example:

public class RetrievingItemWriter implements ItemWriter<Object> {
    private Object someObject;

    public void write(List<? extends Object> items) throws Exception {
        // ...
    }

    @BeforeStep
    public void retrieveInterstepData(StepExecution stepExecution) {
        JobExecution jobExecution = stepExecution.getJobExecution();
        ExecutionContext jobContext = jobExecution.getExecutionContext();
        this.someObject = jobContext.get("someKey");
    }
}

In similar way, @AfterStep annotated method can be used to read/write the ExecutionContext and can access in future Step.

@AfterStep     
public ExitStatus afterStep(StepExecution execution) {         
         this.stepExecution = stepExecution;
         return execution.getExitStatus();
 }

I hope you have enjoyed this post and it helped you to Passing Data to Future Steps in Spring Batch. Please like and share and feel free to comment if you have any suggestions or feedback.

Tagged : / /

Mockito doesn’t give a Hangover – Java Unit Tests

The following blog is based on an understanding of unit testing with the JUnit framework. In case your are not familiar with JUnit please check the following JUnit article.
Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors. We will cover some basic Mockito annotations that are mostly used by the developers.

How do I drink it?

To add mockito into the project, we can add the desired mockito version by any means i.e. maven, gradle or jar file.

pom.xml
<dependency>
	<groupId> org.mockito </groupId>
	<artifactId> mockito-core </artifactId>
	<version> 2.+ </version>
	<scope> test </scope>
</dependency>
build.gradle
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.23.4'
Verify interactions
import static org.mockito.Mockito.*;

// mock creation
List mockedList = mock(List.class);

// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();

// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
Stub method calls
// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);

// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");

// the following prints "first"
System.out.println(mockedList.get(0));

// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));

Mockito Annotations

Before we go further, let’s explore different ways to enable the use of annotations with Mockito tests.
The first option we have is to annotate the JUnit test with a MockitoJUnitRunner as in the following example:

@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
…
}

Alternatively, we can enable Mockito annotations programmatically as well, by invoking MockitoAnnotations.initMocks():

@Before
public void init() {
MockitoAnnotations.initMocks(this);
}

Lastly, we can use a MockitoJUnit.rule() as shown below:

public class MockitoInitWithMockitoJUnitRuleUnitTest {
 
    @Rule
    public MockitoRule initRule = MockitoJUnit.rule();
 
    ...
}

In this case, we must remember to make our rule public.

In our example, we are going to use the following annotations:-

  • @Mock – The @Mock annotation is used to create and inject mocked instances. We do not create real objects, rather ask mockito to create a mock for the class.
  • @InjectMocks – In mockito, we need to create the object of class to be tested and than insert it’s dependencies (mocked) to completely test the behavior. To do this, we use @InjectMocks annotation.

So, Let’s first create an interface called CalculatorService to provide mathematical functions.

CalculatorService.java
public interface CalculatorService {
   public double add(double input1, double input2);
   public double multiply(double input1, double input2);
}

Then, create a Java class to represent MathApplication.

MathApplication.java
public class MathApplication {
   private CalculatorService calcService;

   public void setCalculatorService(CalculatorService calcService){
      this.calcService = calcService;
   }

   public double add(double input1, double input2){
      return calcService.add(input1, input2);
   }

   public double multiply(double input1, double input2){
      return calcService.multiply(input1, input2);
   }
}

Let’s test the MathApplication class, by injecting in it a mock of calculatorService. Mock will be created by Mockito.

MathApplicationTest.java
import static org.mockito.Mockito.when;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

//RunWith attaches a runner with the test class to initialize the test data
@RunWith(MockitoJUnitRunner.class)
public class MathApplicationTest {
	
   //InjectMocks annotation is used to create and inject the mock object
   @InjectMocks 
   MathApplication mathApplication = new MathApplication();

   //Mock annotation is used to create the mock object to be injected
   @Mock
   CalculatorService calcService;

   @Test
   public void testAdd(){
      //add the behavior of calc service to add two numbers
      when(calcService.add(20.0,40.0)).thenReturn(60.0);
		
      //test the add functionality
      Assert.assertEquals(mathApplication.add(20.0, 40.0),60.0);
   }
}

 The test is successfully run using Mockito annotations.

The @Mock annotation is alternative to Mockito.mock(classToMock). They both achieve the same result. Using @Mock is usually considered “cleaner“, as we don’t fill up the tests with boilerplate assignments that all look the same.The other widely used are mentioned below:

  • @Spy – The @Spy annotation is used to create a real object and spy on that real object. A spy helps to call all the normal methods of the object while still tracking every interaction, just as we would with a mock.
  • @Captor – The @Captor annotation is used to create an ArgumentCaptor instance which is used to capture method argument values for further assertions.

I hope you have enjoyed this post and it helped you to understand the basics of mockito framework for unit testing in Java. Please like and share and feel free to comment if you have any suggestions or feedback.

Tagged : / /

JUnit Annotations with Example

Introduction

Annotations were introduced in Junit4, which makes Java code more readable and simple. This is the big difference between Junit3 and Junit4 that Junit4 is annotation based.

JUnit5 is the next generation of JUnit. The goal is to create an up-to-date foundation for developer-side testing on the JVM. This includes focusing on Java 8 and above, as well as enabling many different styles of testing.With the knowledge of annotations in JUnit5, one can easily learn and implement a JUnit test.

JUnit offers integration with CI/CD tools such as Jenkins, Teamcity etc. to help you create a sturdy delivery pipeline.

Basic Java Annotations

So here are some basic JUnit annotation that are mostly used and required for unit testing :

  • @Test – This is the test method to run, public void
  • @BeforeClass – This annotation is used if you want to execute some statements before all the test cases for e.g. test connection must be executed before all the test cases., public static void
  • @AfterClass – This annotation can be used if you want to execute some statements after all test cases for e.g. Releasing resources after executing all test case, public static void
  • @Before – This annotation is used if you want to execute some statement such as preconditions before each test case, public void
  • @After – This annotation can be used if you want to execute some statements after each Test Case for e.g resetting variables, deleting temporary files ,variables, etc, public void

A simple example will help us to understand the working of JUnit annotations.

Java Class to be tested

We are going to use a simple example regarding Account balance where we want to perform our unit testing.

package com.thecodersstop.junit;
 
public class Account {
    private double bal;
 
    public Account(double bal) {
        this.bal = bal;
    }
 
    public double getBal() {
        return bal;
    }
 
    public void setBal(double bal) {
        this.bal = bal;
    }
 
    public void withdraw(double withdrawAmount) {
        this.bal = bal - withdrawAmount;
    }
 
    public void deposit(double depositAmount) {
        this.bal = bal + depositAmount;
    }
}

Junit Test Cases

Here we have our test cases for the Account java class. This test class includes all the basic annotations mentioned above.

package com.thecodersstop.junit;

import org.junit.*;
 
public class AccountTest extends Assert {
    private Account account;
    private static double bal;
 
    @BeforeClass
    public static void BeforeClass() {
		// Code executed before the first test method
        bal = 100;
        System.out.println("Before Class");
    }
 
    @Before
    public void beforeTest() throws Exception {
		// Code executed before each test
        account = new Account(bal);
    }
 
    @Test
    public void testCase1() {
        Assert.assertEquals("Test balance", account.getBal(), bal, 0);
        System.out.println("Test balance. Balance: " + account.getBal());
    }
 
    @Test
    public void testCase2() {
        account.deposit(10);
        Assert.assertEquals("Test deposit", account.getBal(), bal, 10);
        System.out.println("Test deposit. Balance: " + account.getBal());
    }
 
    @Test
    public void testCase3() {
        account.withdraw(30);
        Assert.assertEquals("Test withdraw", account.getBal(), bal, 30);
        System.out.println("Test withdraw. Balance: " + account.getBal());
    }
 
    @After
    public void afterTest() throws Exception {
		// Code executed after each test
        account = null;
        System.out.println("refresh");
    }
 
    @AfterClass
    public static void AfterClass() {
		// Code executed after the last test method
        balance = 0;
        System.out.println("After Class");
    }
}

Run the JUnit Test Cases

Here is the output of our test cases. As we can see, the sequence of the executed test methods, complies with what we described in the starting. This JUnit test is fully passed.

Before Class
Test balance. Balance: 100.0
refresh
Test deposit. Balance: 110.0
refresh
Test withdraw. Balance: 70.0
refresh
After Class

JUnit offers integrations with IDEs such as Eclipse, IntelliJ etc. so you could test run your code quickly and easily.

Execution Sequence of JUnit Annotations

Here is a basic process flowchart of JUnit annotations that will help you to understand the flow, step by step.

@Ignores – This annotation can be used if you want to ignore some statements during test execution for e.g. disabling some test cases during test execution.

I hope you have enjoyed this post and it helped you to understand the basics of JUnit annotations. Please like and share and feel free to comment if you have any suggestions or feedback.

Tagged : / /

Java Beans and POJOs are not same

POJO classes and Beans both are used to define java objects to increase their re-usability and readability. POJOs do not have other restrictions while beans are special POJOs with some restrictions. So let’s first discuss about POJO classes and then try to apply some restrictions on them to achieve Beans.

POJO

POJO refers to the Plain Old Java Object. It is an ordinary Java object, not bound by any special restriction other than those forced by the Java Language Specification.They are simple to put in writing and perceive. They were introduced in EJB 3.0 by Sun Microsystems.

In Hibernate, POJO classes are used to store data and retrieve data.

Example of POJO Class.
public class Employee {
   String name;
   public String id;
   private double salary;
   public Employee(String name, String id,double salary) {
      this.name = name;
      this.id = id;
      this.salary = salary;
   }
   public String getName() {
      return name;
   }
   public String getId() {
      return id;
   }
   public Double getSalary() {
      return salary;
   }
}

The above example is a well-defined example of POJO class. As you can see, there is no restriction on access-modifier of fields. They can be private, default, protected or the public. It is also not necessary to include any constructor in it.

JavaBeans

A JavaBean is still a POJO but introduces a strict set of rules around how we implement it:

  • Access levels – properties are private and we expose getters and setters
  • Method names – getters and setters follow the getX and setX convention (in the case of a boolean, isX can be used for a getter)
  • Default Constructor – a no-argument constructor must be present so an instance can be created without providing arguments, for example during deserialization
  • Serializable – implementing the Serializable interface allows us to store the state
Example of Java Bean Class.
public class EmployeeBean implements Serializable {
 
    private static final long serialVersionUID = -3761445487636086334L;
    private String name;
    private LocalDate startDate;
 
    public EmployeeBean() {
    }
    public EmployeeBean(String name, LocalDate startDate) {
        this.name = name;
        this.startDate = startDate;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //  additional getters/setters
}

Due to this it is stated that all JavaBeans are POJOs but not all POJOs are JavaBeans.

I hope you have enjoyed this post and it helped you to understand the difference between JavaBeans and POJO classes. Please like and share and feel free to comment if you have any suggestions or feedback.

Tagged :

Configure Logging to File in Spring Boot in just one line

Introduction

Logging in spring boot is very flexible and easy to configure. Spring Boot’s default configurations provides a support for the use of Java Util Logging, Log4j2, and Logback. In each case, loggers are pre-configured to use console output with optional file output also available.

A new, freshly-generated Spring Boot application doesn’t come with any explicit logging configuration, and it will use Logback by default, the logging framework for Java, and the successor to the old log4j.
Logging is configured automatically when you add the spring-boot-starter-web dependency to your project.
Spring boot’s internal logging is written with Apache Commons Logging so it is one and only mandatory dependency. Till, boot 1.x – we had to import it manually. Since boot 2.x, it is downloaded transitively. To be more precise, spring-boot-starter-web depends on spring-boot-starter-logging, which pulls in spring-jcl for us.

File Output

By default, Spring Boot logs only to the console and does not write log files. To make Spring Boot write to a log file, you can set the logging.path property in your application.properties file:

logging.path = ./                      #  spring.log in current folder
logging.path = relativepath/logs       #  relativepath/logs/spring.log
logging.path = /fullpath/logs          #  /fullpath/logs/spring.log

With this configuration, Spring Boot will write to the console and also to a log file called spring.log, at the path you specify.
If you want to choose your own log filename instead of spring.log, then you can set the property logging.file, in your application.properties, e.g.:

logging.file = logfile.log                  # in current folder
logging.file = relativepath/logfile.log     # relative path with filename
logging.file = /fullpath/logfile.log        # full path with filename

Log files rotate when they reach 10 MB and, as with console output, ERROR-level, WARN-level, and INFO-level messages are logged by default. Size limits can be changed using the logging.file.max-size property. Previously rotated files are archived indefinitely unless the logging.file.max-history property has been set.

Logback does not have a FATAL level. It is mapped to ERROR.

We can configure separate property files for each environment like application-dev.properties and application-prod.properties. Follow the naming convention of application-{environment}.properties where {environment} is replaced with the environment name. Depending on your VM options or environment variables, one of these can be chosen.

Spring Cloud Config doesn’t support default Logback properties.

Log Format

The default log output from Spring Boot resembles the following example:

2020-03-08 11:57:51.102  INFO 55469 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2020-03-08 11:57:51.203  INFO 55469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-03-08 11:57:51.203  INFO 55469 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1358 ms
2020-03-08 11:57:51.608  INFO 55469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

The following items are output:

  • Date and Time: Millisecond precision and easily sort-able.
  • Log Level: ERRORWARNINFODEBUG, or TRACE.
  • Process ID.
  • --- separator to distinguish the start of actual log messages.
  • Thread name: Enclosed in square brackets (may be truncated for console output).
  • Logger name: This is usually the source class name (often abbreviated).
  • The log message.

Customization

To help with the customization, some other properties are transferred from the Spring Environment to System properties, as described in the following table:

Spring EnvironmentSystem PropertyComments
logging.exception-conversion-wordLOG_EXCEPTION_CONVERSION_WORDThe conversion word used when logging exceptions.
logging.fileLOG_FILEIf defined, it is used in the default log configuration.
logging.file.max-sizeLOG_FILE_MAX_SIZEMaximum log file size (if LOG_FILE enabled). (Only supported with the default Logback setup.)
logging.file.max-historyLOG_FILE_MAX_HISTORYMaximum number of archive log files to keep (if LOG_FILE enabled). (Only supported with the default Logback setup.)
logging.pathLOG_PATHIf defined, it is used in the default log configuration.
logging.pattern.consoleCONSOLE_LOG_PATTERNThe log pattern to use on the console (stdout). (Only supported with the default Logback setup.)
logging.pattern.dateformatLOG_DATEFORMAT_PATTERNAppender pattern for log date format. (Only supported with the default Logback setup.)
logging.pattern.fileFILE_LOG_PATTERNThe log pattern to use in a file (if LOG_FILE is enabled). (Only supported with the default Logback setup.)
logging.pattern.levelLOG_LEVEL_PATTERNThe format to use when rendering the log level (default %5p). (Only supported with the default Logback setup.)

You can customize the default logging configuration by:

  • Setting some specific Spring Boot properties (these can go in your application.propertiesapplication.yml or as environment variables)
  • Adding a logback.xml onto the classpath, which Spring Boot will detect and use to configure Logback
  • Adding a logback-spring.xml onto the classpath, which Spring Boot will detect and use to configure Logback.
Tagged : / / / / /
%d bloggers like this: