How to pass parameters spring batch Intellij maven - java

I'm reading a spring batch book and making the examples that show because I will start to work with java and spring batch the next month(now I use c#), one example uses ParameterValidator to validate receiving one parameter name so the maven test will work only if the parameter it was past,
public class ParameterValidator implements JobParametersValidator {
#Override
public void validate(JobParameters parameters) throws JobParametersInvalidException {
String fileName = parameters.getString("fileName");
if(!StringUtils.hasText(fileName)) {
throw new JobParametersInvalidException("fileName missing");
}
else if(!StringUtils.endsWithIgnoreCase(fileName, "csv")) {
throw new JobParametersInvalidException("fileName parameter does " +
"not use the csv file extension");
}
}
I tried passing the data using arguments tag in pom.xml:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<arguments> fileName=foo.csv</arguments>
</configuration>
</plugin>
</plugins>
, editing the test:
and try other answers I found on internet but always raise the error of missing parameter.
Is it possible to pass arguments using this IDE and maven?
Thanks!

You can just pass in command line argument through args[] passed to main function and call CommandLineJobRunner.main(args) as if you are executing from cmd

Related

JSON ObjectMapper with javac "-parameters" behaves when run via maven, not via InteliJ IDEA

As you can probably gather from the title, this is a somewhat complicated issue.
First of all, my goal:
I am trying to achieve conversion of my java classes to and from JSON without having to add any json-specific annotations to them.
My java classes include immutables, which must initialize their members from parameters passed to the constructor, so I have to have multi-parameter constructors that work without #JsonCreator and without #JsonParameter.
I am using the jackson ObjectMapper. If there is another ObjectMapper that I can use that works without the problem described herein, I'd be happy to use it, but it would have to be equally reputable as the jackson ObjectMapper. (So, I am not willing to download Jim's ObjectMapper from his GitHub.)
My understanding as to how this can actually be achieved, in case I am wrong somewhere:
Java used to make method (and constructor) parameter types discoverable via reflection, but not parameter names. That's why the #JsonCreator and #JsonParameter annotations used to be necessary: to tell the json ObjectMapper which constructor parameter corresponds to which property. With Java 8, the compiler will emit method (and constructor) parameter names into the bytecode if you supply the new -parameters argument, and will make them available via reflection, and recent versions of the jackson ObjectMapper support this, so it should now be possible to have json object mapping without any json-specific annotations.
I have this pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test.json</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Json Test</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<sourceDirectory>main</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<plugins>
<plugin>
<!--<groupId>org.apache.maven.plugins</groupId>-->
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<!--<compilerArgument>-parameters</compilerArgument>-->
<!--<fork>true</fork>-->
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
And I use it to compile and run the following little self-contained program:
package jsontest;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import java.io.IOException;
import java.lang.reflect.*;
public final class MyMain
{
public static void main( String[] args ) throws IOException, NoSuchMethodException
{
Method m = MyMain.class.getMethod("main", String[].class);
Parameter mp = m.getParameters()[0];
if( !mp.isNamePresent() || !mp.getName().equals("args") )
throw new RuntimeException();
Constructor<MyMain> c = MyMain.class.getConstructor(String.class,String.class);
Parameter m2p0 = c.getParameters()[0];
if( !m2p0.isNamePresent() || !m2p0.getName().equals("s1") )
throw new RuntimeException();
Parameter m2p1 = c.getParameters()[1];
if( !m2p1.isNamePresent() || !m2p1.getName().equals("s2") )
throw new RuntimeException();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule( new ParameterNamesModule() ); // "-parameters" option must be passed to the java compiler for this to work.
mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true );
mapper.configure( SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true );
mapper.setSerializationInclusion( JsonInclude.Include.ALWAYS );
mapper.setVisibility( PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY );
mapper.enableDefaultTyping( ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY );
MyMain t = new MyMain( "1", "2" );
String json = mapper.writeValueAsString( t );
/*
* Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class saganaki.Test]: can not
* instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
*/
t = mapper.readValue( json, MyMain.class );
if( !t.s1.equals( "1" ) || !t.s2.equals( "2" ) )
throw new RuntimeException();
System.out.println( "Success!" );
}
public final String s1;
public final String s2;
public MyMain( String s1, String s2 )
{
this.s1 = s1;
this.s2 = s2;
}
}
Here is what happens:
If I compile the program using mvn clean compile and then run or debug it from within Idea, it works fine and it displays "Success!".
If I do "Rebuild Project" from within Intellij Idea and then I run/debug, it fails with a JsonMappingException that "No suitable constructor found for simple type jsontest.MyMain".
The strange thing (to me) is, the code before the instantiation of the ObjectMapper checks to make sure that constructor parameter names are present and valid, effectively ensuring that the "-parameters" argument has been successfully passed to the compiler, and these checks always pass!
If I edit my "debug configuration" in Idea and in the "Before launch" section I remove "Make" and I replace it with "Run maven goal" compile then I can successfully run my program from within Idea, but I do not want to do have to do this. (Also, it does not even work very well, I guess I must be doing something wrong: quite often I run and it fails with the same exception as above, and the next time I run it succeeds.)
So, here are my questions:
Why does my program behave differently when compiled by maven than when compiled with Idea?
More specifically: what is ObjectMapper's problem given that my assertions prove that the "-parameters" argument was passed to the compiler, and arguments do have names?
What can I do to make Idea compile my program the same way as maven (at least with respect to the problem at hand) without replacing Idea's "Make"?
Why does it not work consistently when I replace the default "Make" with "Run maven goal" compile in Idea's debug configuration? (What am I doing wrong?)
EDIT
My apologies, the assertions were not necessarily proving anything, since they were not necessarily enabled with -enableassertions. I replaced them with if() throw RuntimeException() to avoid confusion.
As far as I can see in the IntelliJ Community edition sources, IntelliJ is not doing anything with the compilerArgs you're specifying.
In MavenProject.java, there are two places where the compilerArgs are being read:
Element compilerArguments = compilerConfiguration.getChild("compilerArgs");
if (compilerArguments != null) {
for (Element element : compilerArguments.getChildren()) {
String arg = element.getValue();
if ("-proc:none".equals(arg)) {
return ProcMode.NONE;
}
if ("-proc:only".equals(arg)) {
return ProcMode.ONLY;
}
}
}
and
Element compilerArgs = compilerConfig.getChild("compilerArgs");
if (compilerArgs != null) {
for (Element e : compilerArgs.getChildren()) {
if (!StringUtil.equals(e.getName(), "arg")) continue;
String arg = e.getTextTrim();
addAnnotationProcessorOption(arg, res);
}
}
The first code block is only looking at the -proc: argument, so this block can be ignored. The second one is passing the values of the arg element (which you are specifying) to the addAnnotationProcessorOption method.
private static void addAnnotationProcessorOption(String compilerArg, Map<String, String> optionsMap) {
if (compilerArg == null || compilerArg.trim().isEmpty()) return;
if (compilerArg.startsWith("-A")) {
int idx = compilerArg.indexOf('=', 3);
if (idx >= 0) {
optionsMap.put(compilerArg.substring(2, idx), compilerArg.substring(idx + 1));
} else {
optionsMap.put(compilerArg.substring(2), "");
}
}
}
This method is only processing arguments which start with -A, which are used to pass options to the annotation processors. Other arguments are ignored.
Currently, the only ways to get your sources to run from within IntelliJ are to enable the flag yourself in the "Additional command line parameters" field of the compiler settings (which isn't portable), or by compiling with maven as a pre-make step in your run configuration. You probably have to file an issue with Jetbrains if you want this to be possible in IntelliJ automatically.

Why is a directory referenced as a classpath resource null if the directory is empty?

I've got the following unit test class, which referenced some test data files as classpath resources:
package com.altanqa.project.parser;
public class ParserTest {
private static final URL VALID_DIR = ParserTest.class.getResource("testData-VALID");
private static final URL INVALID_DIR = ParserTest.class.getResource("testData-INVALID");
private static final URL MISSING_DIR = ParserTest.class.getResource("testData-MISSING");
// ...
}
The directory structure referenced here looks like this:
src/test/java/com/altanqa/project/parser
ParserTest.java
src/test/resources/com/altanqa/project/parser
testData-VALID
data
test-data.txt
testData-INVALID
data
test-data.txt
testData-MISSING
data
The Parser under test takes a directory, and knows to look in it for data/testData.txt. The test class here runs the parser, giving it valid data, invalid data, and missing data, to check that the parser deals with each situation correctly. Valid and invalid data works fine, but the MISSING URL is null. If I put a different file (say, a.txt) in test-data-MISSING, the URL is properly initialised, but without any files in the directory, it is null. Is this a peculiarity of the class loader? Is there a way around it, i.e. to have the MISSING_DIR URL initialise correctly, even with nothing in its subdirectory?
Thank you!
Credit goes to Boris for highlighting that this is a Maven issue, rather than anything with the Java. The maven-resources-plugin needs to be configured to include empty directories when copying resources. In the pom:
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
...
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
...
</plugin>
</plugins>
</build>

Surefire JUnit test does not log failed Assume in test xml files

I am using
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
</plugin>
and
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
to test my project.
I have a very simple test method
#Test
public void test() throws IOException {
Assume.assumeTrue("I am broken, so I am ignored", false);
// some tests
}
When I build the project with maven, I get the following code snippet in the surefire xml file
<testcase name="test" classname="com.stackoverflower.experiment.Test" time="0">
<skipped/>
</testcase>
I do not think this is the correct behavior of surefire, since assumption failures are treated the same as ignored, it should follow the same logging standard as ignored. This JIRA clearly says the reason should be logged.
What do you think? Is there a workaround to get that message into the xml file?
Thanks
Update 1
The reason I cannot use #Ignore is because I do not want to hard code a test as ignored. I want it to be skipped based on some precondition that cannot be determined at coding time.
The Assume methods mostly used in JUnit Theories when combinations of DataPoints are not valid for a given Theory. You should be using the Assert class, not Assume. Here is your example test, re-written to use the correct class:
#Test
public void test() throws IOException {
Assert.assertTrue("I am broken", false);
// some tests
}
It is meant for false assumptions to be ignored, as mentioned in the Javadoc for Assume

Using JUnit RunListener in IntelliJ IDEA

I'm working on project where I need to perform some action before running each JUnit test. This problem was solved using RunListener that could be added to the JUnit core. The project assembly is done using Maven, so I have this lines in my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<properties>
<property>
<name>listener</name>
<value>cc.redberry.core.GlobalRunListener</value>
</property>
</properties>
</configuration>
</plugin>
So, everything works using:
mvn clean test
But when tests are started using IntelliJ (using its internal test runner) the actions coded in our RunListener are not executed, so it is impossible to perform testing using IntelliJ infrastructure.
As I see, IntelliJ does not parse this configuration from pom file, so is there a way to explicitly tell IntelliJ to add RunListener to JUnit core? May be using some VM options in configuration?
It is much more convenient to use beautiful IntelliJ testing environment instead of reading maven output.
P.S. The action I need to perform is basically a reset of static environment (some static fields in my classes).
I didn't see a way to specify a RunListener in Intellij, but another solution would be to write your own customer Runner and annotate #RunWith() on your tests.
public class MyRunner extends BlockJUnit4ClassRunner {
public MyRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
// run your code here. example:
Runner.value = true;
super.runChild(method, notifier);
}
}
Sample static variable:
public class Runner {
public static boolean value = false;
}
Then run your tests like this:
#RunWith(MyRunner.class)
public class MyRunnerTest {
#Test
public void testRunChild() {
Assert.assertTrue(Runner.value);
}
}
This will allow you to do your static initialization without a RunListener.

Maven Codehaus findbugs plugin "onlyAnalyze" option not working as expected

Update for the impatient: it's simple, use package.- for sub-package scanning instead of package.*, as-per martoe's answer below!
I cannot seem to get onlyAnalyze working for my multi-module project: regardless of what package (or pattern) I set, maven-findbugs-plugin doesn't evaluate sub-packages as I'd expect from passing it packagename.*.
To prove either myself or the plugin at fault (though I always assume it's the former!), I setup a small Maven project with the following structure:
pom.xml
src/
main/java/acme/App.java
main/java/acme/moo/App.java
main/java/no_detect/App.java
which is very simple!
The POM has the following findbugs configuration:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.4.0</version>
<executions>
<execution>
<phase>verify</phase>
<goals><goal>findbugs</goal><goal>check</goal></goals>
</execution>
</executions>
<configuration>
<debug>true</debug>
<effort>Max</effort>
<threshold>Low</threshold>
<onlyAnalyze>acme.*</onlyAnalyze>
</configuration>
</plugin>
</plugins>
</build>
and every App.java has the following code with two obvious violations:
package acme;
import java.io.Serializable;
public class App implements Serializable
{
private static final class NotSer {
private String meh = "meh";
}
private static final NotSer ns = new NotSer();// Violation: not serializable field
public static void main( String[] args )
{
ns.meh = "hehehe";// Vilation: unused
System.out.println( "Hello World!" );
}
}
Note that no_detect.App has the same content as above, but my expectation is that it wouldn't be evaluated by findbugs because I have the "onlyAnalyze" option set to acme.* which I assume would evaluate acme.App and acme.moo.App and nothing else.
I now execute a mvn clean install to clean, build, test, run findbugs, package, install, which produces the following findbugs report (snipped for brevity) and results in a build failure which is expected because acme.App and acme.moo.App:
<BugInstance category='BAD_PRACTICE' type='SE_NO_SERIALVERSIONID' instanceOccurrenceMax='0'>
<ShortMessage>Class is Serializable, but doesn't define serialVersionUID</ShortMessage>
<LongMessage>acme.App is Serializable; consider declaring a serialVersionUID</LongMessage>
<Details>
<p> This field is never read.&nbsp; Consider removing it from the class.</p>
</Details>
<BugPattern category='BAD_PRACTICE' abbrev='SnVI' type='SE_NO_SERIALVERSIONID'><ShortDescription>Class is Serializable, but doesn't define serialVersionUID</ShortDescription><Details>
<BugCode abbrev='UrF'><Description>Unread field</Description></BugCode><BugCode abbrev='SnVI'><Description>Serializable class with no Version ID</Description></BugCode>
To summarise: only acme.App is analysed, acme.moo.App isn't (bad) and neither is no_detect.App (good).
I tried with two wildcards in the onlyAnalyze option but that produces a successful build but with a findbugs error (Dangling meta character '*' etc).
I tried with onlyAnalyze set to acme.*,acme.moo.* which analyzes all the expected classes (acme.App and acme.moo.App) which means it "works" but not as I expect; i.e. I have to explicitly declare all parent-packages for the classes I want to analyze: that could get large and difficult to maintain on a multi-module project!
Do I have to define every package I want analyzed, or can I declare a wildcard/regex pattern that will do what I want?
I'd rather not use the inclusion/exclusion XML because that requires far more setup and reasoning that I don't currently have time for...
To cite the Findbugs manual: "Replace .* with .- to also analyze all subpackages"

Categories