Running Spring Batch jobs from the command line - spring

I don't know how to call a Job defined in Spring Batch using CommandLineJobRunner, documentation details are not enough for me.
I've followed the Spring Batch official guide to write Jobs in Spring Batch using Java annotations e.g. #EnableBatchProcessing because I wanted to avoid XML configuration files for the description of the job, the steps, etc.
So far I have:
a configuration class (com.package.bla.bla.ClassContainingTheBatchConfiguration see below) where I've put all the stuff defining ItemReader, ItemProcessor, ItemWriter, Job, and Step (with return jobs.get("nameOfTheJob") see below) using a #Bean annotaion.
a class with a main method with SpringApplication.run(...) and and annotation with #ImportResource("classpath:META-INF/spring/applicationContext.xml") to import some beans I need when processing the data in the Job.
On the Maven side I am currently using some plugins:
maven-jar-plugin specifying <addClasspath>true</addClasspath> and the class containing the main method in the tag <mainClass>
maven-assembly-plugin because I would like a unique executable jar containing all the stuff in the dependencies, I am using <phase>package</package> to be able to build the jar in the package phase, I am also using <goal>single</goal> to be able to properly build the jar using the assembly
maven-compiler-plugin specifying I am using Java 1.7
I think I've configured all the things I need to configure, however after having a Maven BUILD SUCCESS I am not able to run the job from the command line:
java -cp ./target/JAR_FILE_NAME.jar org.springframework.batch.core.launch.support.CommandLineJobRunner com.package.bla.bla.ClassContainingTheBatchConfiguration nameOfTheJob
Is throwing IOException due to the java.io.FileNotFoundException regarding com.package.bla.bla.ClassContainingTheBatchConfiguration. How should I specify the parameters in the command line in order to get the Job executed?

If you are already using SpringApplication from Spring Boot, why not finish the job and use #EnableAutoConfiguration as well, and also the Maven plugin (see for example this guide)? That way you will get something working pretty quickly and you can always add your own features later.

If the first argument to the CommandLineJobRunner is your #Configuration FQCN instead of a resource path, the ClassPathXmlApplicationContext constructor that's called from the CommandLineJobRunner's start() method will break.
int start(String jobPath, String jobIdentifier, String[] parameters, Set<String> opts) {
ConfigurableApplicationContext context = null;
try {
context = new ClassPathXmlApplicationContext(jobPath);
If you've already written a class with a main(), that replaces the CLJR, you shouldn't be passing CLJR as the class name in the command line. Pass that instead.

dont use spring.batch.job.enabled=false
then run using java -jar [jar-files] --spring.batch.job.names=[job-name]

Related

Spring Boot Application - Running jar file gives ResourceFinderException error

Created a jar file for a spring boot multimodule application and ran the jar file using java -jar command. While starting the application, it gives ResourceFinderException. When I analyzed it, the issue is happening because in my ResourceConfig file, i have used the package for my api end points. If I use register(service.class), the application starts fine. Any suggestion how can I provide the package instead of using register? The reason I want to use package is because I have lots of services inside multiple packages and the code looks very ugly if i use register for all the services. The ResourceConfig file looks like below.
public class AppResourceConfig extends ResourceConfig {
public AppResourceConfig {}{
super();
property("jersery.config.beanValidation.enableOutputValidationErrorEntity.server");
**packages("com.api");**
register(GsonProvider.class);
register(RequestContextFilter.class);
register(NotFoundExceptionMapper.class);
register(DefaultExceptionMapper.class);
}
}
Here the issue is with highlighted line: packages("com.api")
If I comment out this code application will be up. Otherwise it is giving org.glassfish.jersey.server.internal.scanning.ResourceFinderException: java.io.FileNotFoundException: api-01.03.00.04-snapshot.jar (No such file or direcotry)
Note: api-01.03.00.04-snapshot.jar is the jar file for one of the module in a project

How to pass spring.config.location="somepath" while building SpringBoot application with command-line Gradle (6.4) build

I have a SpringBoot application where I have application.properties file outside of project (it's not in usual place src/main/resources).
While building application with gradle clean build, it fails as code is not able to find properties files.
I have tried many command to pass vm args, gradle opts but its not working.
gradle clean build -Djvmargs="-Dspring.config.location=/users/home/dev/application.properties" //not working
It fails on test phase when it creates Spring application context and not able to substitute property placeholders. If I skip test as gradle clean build -x test it works.
Though I can run the app with java -jar api.jar --spring.config.location=file:/users/home/dev/application.properties
Please help how I can pass spring.config.location=/users/home/dev/application.properties in gradle build using command line so that build runs with all Junit tests
If I were you, I would not get involved the actual properties to junit test. So I would create a test properties for the project under src/test/resources/application-test.properties and in junit test I would load the test properties.
Example:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyProperties.class)
#TestPropertySource("classpath:application-test.properties")
public class MyTestExample{
#Test
public void myTest() throws Exception {
...
}
}
System properties for running Gradle are not automatically passed on to the testing framework. I presume this is to isolate the tests as much as possible so differences in the environment will not lead to differences in the outcome, unless explicitly configured that way.
If you look at the Gradle API for the Test task, you can see that you can configure system properties through through the systemProperty method on the task (Groovy DSL):
test {
systemProperty "spring.config.location", "/path/to/my/configuration/repository/application.properties"
}
If you also want to read a system property from the Gradle command line and then pass that the test, you have to read it from Gradle first, e.g. as a project property, and then pass that value to the test:
test {
if (project.hasProperty('testconfig')) {
systemProperty 'spring.config.location', project.getProperty('testconfig')
}
}
Run it with gradle -Ptestconfig="/path/to/my/configuration/repository/application.properties" build
However, I would discourage using system properties on the build command line if you can avoid it. At the very least, it will annoy you greatly in the long run. If the configuration file can be in different locations on different machines (depending on where you have checkout out the repository and if it is not in the same relative path to your Spring Boot repository), you may want to specify it in a personal gradle.properties file instead.
I think there is a misunderstanding.
spring.config.location is used at runtime
As you validated:
java -jar api.jar --spring.config.location=file:/users/home/dev/application.properties
spring.config.location is used or required at runtime, not at build time.
When your spring boot app is building, an application.properties is required. An approach could be use an src/main/resources/application.properties with template values, but at runtime you will ignore it spring.config.location=file...
For unit tests
In this case as #nikos-bob said, you must use another properties, commonly inside of your src/test/resources
Environment variables instead external properties
We don't want to have hardcoded values in our main git repository src/main/resources/application.properties so the first idea is use an external properties. But this file must be stored in another git repository (equal to main repository ) or manually created.
Spring and other frameworks give us an alternative: Use environment variables.
So instead of manually external creation of application.properties or store it in our git repository, your spring boot app always must have an application.properties but with environment variables:
spring.datasource.url=jdbc:oracle:thin:#${DATABASE_HOST}:${DATABASE_PORT}:${DATABASE_SID}
spring.datasource.username=${DATABASE_USER}
spring.datasource.password=${DATABASE_PASSWORD}
spring.mail.host = ${MAIL_HOST}
spring.mail.username =${MAIL_USERNAME}
spring.mail.password =${MAIL_PASSWORD}
Advantages:
No manually creation of application.properties allowing us a more easy devops automations
No spring.config.location=file.. is required

Spring boot - Setting configration property thru program arguments

I have a spring boot application and the setting file with the below annotation.
#ConfigurationProperties("test.prop")
public class TestPropSettings {
private String name;
}
The following property in the application.properties set this value.
test.prop.name=XYZ
But, I would like to pass thru program arguments without having the property file.
Tried with,
-Dtest.prop.name=XYZ in eclipse program arguments. But, it does not work. Is there any other way?
Thanks
If you start your jar directly, you can override the property like this:
java -jar your-app.jar --test.prop.name=XYZ
In Eclipse you also need to pass --test.prop.name=XYZ in you program arguments.

JUnit class is not displayed in JMeter

I have created a Java project with 1 class containing 2 simple tests, exported as jar and added the jar in my JMeter JUnit folder, now after restarting the JMeter i don't see my class in JMeter even after selecting Annotation 4 option.
This is my class:
package print;
import org.junit.Test;
public class PrintClass {
#Test public void test() {
System.out.println("Hello World..!");
}
}
Consider the following checklist:
Your JUnit test class should have either empty constructor or constructor taking a single string as an argument. Other options are not supported
You should place your .jar file(s) under "lib/junit" folder of your JMeter installation
If there are any dependencies you need to put them somewhere in JMeter classpath as well
JMeter restart will be required to pick the .jars up
In case of any problems first of all check jmeter.log file (normally it lives under "bin" folder of your JMeter installation and contains enough troubleshooting information)
See How to Use JUnit With JMeter article for more details.
Even I faced same kind of issue then I added the dependency jars to the lib file.
Make sure you copy these files at this location -> apache-jmeter-5.1.1\lib
1.Selenium webdriver jar file (selenium-server-standalone)
2. Junit4 Jar file (junit4)
Make sure you add Jar file from eclipse or any IDE to this location -> apache-jmeter-5.1.1\lib\junit
1. Jar file which contains the automation selenium code (Using Junit)
Restart Jmeter and continue which the normal process of adding thread group and adding Junit sampler etc...
This resolved my issue and I was able to run my scripts on Jmeter.
In eclipse make sure that you create a JUnit class, not just the class and add junit annotations to this, even i was facing the same issue, it got resolved when i was created a JUnit class and then uploaded my project in JMeter
Did you put the jar in :
/lib/junit
Check you jar by running below command to see if it is ok:
jar -tvf <your jar>
And its dependencies as described in:
JUnit test classes not showing up in JMeter
See this for more details:
http://jmeter.apache.org/usermanual/junitsampler_tutorial.html

Spring Boot "unable to resolve class" with Groovy

I'm new to Groovy, Spring Boot, and Gradle (using gradle as well) and am trying to build a small test program.
I have a main class EvalMain and a InputObj class in a com.eval package.
#Controller
class EvalMain {
#RequestMapping("/")
#ResponseBody
public static String textTest() {
def iO = new InputObj("dsa", "dasdsa", "U1dBRw==");
return iO.xorString();
}
}
when running "spring run EvalMain.groovy" I get the following error:
startup failed:
file:<filepath>EvalMain.groovy: 14: unable to resolve class InputObj
# line 14, column 18.
def iO = new InputObj("dsa", "dasdsa", "U1dBRw==");
I tried throwing an import at the top but then spring boot complained about this too? What am I missing here? Any help would be much appreciated, thanks!
after adding the import:
import com.eval.InputObj;
I get this error:
file:/<filePath>/EvalMain.groovy: 2: unable to resolve class com.eval.InputObj
# line 2, column 1.
import com.eval.InputObj
^
1 error
Not sure if this is a good way to do it, but I was able to run it with "spring run .groovy .groovy" I wonder if there's the equivalent of a makefile?
Try to run spring run *.groovy.
Spring Boot CLI is for quick prototyping a single Groovy script. It tries to autoload all Spring Boot dependencies, but its your responsibility to include your additional dependencies
If you have just multiple source files you have to pass it to the CLI.
If it is an external dependency, include it with a #Grab, see here.
However, you have Gradle and more than one source file. Therefor it might be the time to switch from the Spring Boot CLI to a normal Gradle project.
Just go to the guides and choose "Build with Gradle". Then you will see an example Gradle build file. Also the Gradle Spring Boot plugin documentation provides samples.
You can start your application with gradlew bootRun.

Resources