@Input- A JAVA API to Map Console Input into Models - compatible with Spring BOOT and other frameworks

@Input- A JAVA API to Map Console Input into Models - compatible with Spring BOOT and other frameworks

This small but useful API addresses USE-CASEs similar to described below-

A Java application often need to be run on console, and as a 'NOHUP' process. E.g. a server application - or a micro service component . There are generally lots of properties that need to be configured across different environments. Common approaches to provide configuration parameters include externalization of properties, picking values from System /Environment Variables, or simply passing them as command line arguments. Passing paraneters in command line does not have a good user experience and might change with versions of the build; and needs first-time users to be aware of their possible permutations . Secondly, parameters that are used by the Framework/Container often needs parameters to be passed as application parameters, or VM parameters. The java command to execute a JAR, with a good many hefty VM parameters, becomes clumsy . A better option would be to go for a console-based input. Trouble is - you need to manually prompt for and accept values for different fields. We're fine if there are even ten fields to be input; but with change in fields , it'd still need developers to waste time on the console-input module.

The API -a basic Work-through

We assume any class , let us say, SomeClass

/*
    Any POJO -with any number of fields
    Types of the Fields are  primitive types, String,Date,File -the most common
    ones that are needed for configuration.
    But the class may contain any other type, nesting , methods etc. as any other normal
    class .

*/

public class SomeClass {
	
	private String name;
	
	private int marks;
	
	private float percentage;
	

	private Date dob;
	
	// For checking only 
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return name+" "+marks+" "+dob+" "+percentage;
	}
	
}

We want a to automatically prompt for and accept values of the fields of the classes, such as the one shown above.

We add EasyInput.jar to build path of the project and annotate the fields that are needed at run time.

package com.soham.testpkg;


import java.io.IOException;
import java.util.Date;


import com.soham.libaries.autoinput.annotations.Inputable;
import com.soham.libaries.autoinput.io.ConsoleInput;
import com.soham.libaries.autoinput.types.Type;


public class SomeClass {
	@Inputable(type=Type.STRING)
	private String name;

	@Inputable(type=Type.INT,defaultStringValue="0")
	private int marks;

	@Inputable(type=Type.FLOAT,defaultStringValue="0")
	private float percentage;
	
	@Inputable(type=Type.DATE)
	private Date dob;
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return name+" "+marks+" "+dob+" "+percentage;
	}
	
	


}


Parameters to @Inputable do commendable justice to their names with regard to what they stand for. There are, at present 3 parameters viz. type, defaultStringValue and shouldValidate [Refer to Javadoc for details]

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, IOException {
		SomeClass s=new SomeClass();
		
        System.out.println(s);
		/* This line is important and executes console prompt and input */
        ConsoleInput.inputObject(s);
		
        System.out.println(s);
	}

No alt text provided for this image

Now that we saw its basic functionality, let us test its compliance with Spring BOOT

Assume that the following properties need to be configured following above approach

#Port on which to run application

server.port=8080

 

#mongo config

#------------

app.database.mongo.host=localhost

app.database.mongo.port=27017

 

# Directory where reports are saved

-----------------------------------

app.output.reporting.basedir=D:/abc

 

# The Application should stop some activity post this date

------------------------------------------------------------

app.global.timelines.expiry=30-APR-2019  

However, as it’s infeasible (precisely w.r.t Standard Operational Activity) to edit the properties within an executable JAR (that is normally distributed) , we need to pass hefty blocks of strings as VM parameters.

E.g.

java -jar -Dapp.output.reporting.basedir=E:/xyz -Dserver.port=9091 -D app.database.mongo.host=192.168.1.34 -Dapp.database.mongo.port=27018 -D app.global.timelines.expiry=30-APR-2019

Also, on a remote terminal, one would rather use

nohup java -jar -Dapp.output.reporting.basedir=E:/xyz -Dserver.port=9091 -D app.database.mongo.host=192.168.1.34 -Dapp.database.mongo.port=27018 -D app.global.timelines.expiry=30-APR-2019 &

We have a configuration model class as shown below

@Configuration

@ComponentScan(basePackages = { "com.somepkg.*" })

@PropertySource("classpath:application.properties")

public class DTO_Config {

 

       @Value("${server.port}")

       private int port;

 

       @Value("${app.database.mongo.host}")

       private String mongoHost;

 

       @Value("${app.database.mongo.port}")

       private int mongoPort;

 

       @Value("#{new java.io.File(\"${app.output.reporting.basedir}\")}")

       private File reportGenDir;

 

       @DateTimeFormat(pattern = "dd-MM-yyyy")

       @Value("${app.global.timelines.expiry}")

       private Date dtExpiry;

 

We annotate it

@Inputable(type=Type.INT,defaultStringValue="8080")

       @Value("${server.port}")

       private int port;

       @Inputable(type=Type.STRING,defaultStringValue="localhost")

      

       @Value("${app.database.mongo.host}")

       private String mongoHost;

 

       @Value("${app.database.mongo.port}")

       @Inputable(type=Type.INT,defaultStringValue="27017")

      

       private int mongoPort;

 

       @Value("#{new java.io.File(\"${app.output.reporting.basedir}\")}")

       @Inputable(type=Type.FILE,defaultStringValue="/usr/local/reports")

      

       private File reportGenDir;

       @Inputable(type=Type.DATE,defaultStringValue="10-Apr-2018")

      

       @DateTimeFormat(pattern = "dd-MM-yyyy")

       @Value("${app.global.timelines.expiry}")

       private Date dtExpiry;

Write a method to the above class to convert fields to java.util.Properties

public Properties toProperties() {

             Properties properties=new Properties();

             properties.put("server.port", this.port);

             properties.put("app.database.mongo.host", this.mongoHost);

             properties.put("app.database.mongo.port", this.mongoPort);

             properties.put("app.output.reporting.basedir", this.reportGenDir);

             properties.put("app.global.timelines.expiry", this.dtExpiry);

             return properties;

       }

Finally, in the main method of the class annotated with @SprinBootApplicaton

DTO_Config consoleConfig = new DTO_Config();

/* This one-liner does the trick*/
consoleConfig = ConsoleInput.inputObject(consoleConfig);

                   
SpringApplicationBuilder builder = new SpringApplicationBuilder();

                   

builder

       .sources(SpringBootApplicationMainClass.class)

       .properties(consoleConfig.toProperties());

                   

SpringApplication application = builder.build();

 

application.run(args);

Screenshot below shows an execution of the program -

No alt text provided for this image


In current version of the API, supported date format is dd-MM-yyyy . Validation check if a File exists/is accessible 

Like
Reply

To view or add a comment, sign in

More articles by Soham Sengupta

Others also viewed

Explore content categories