Encoding issue when building with mvn - java

I'm currently working on a Maven plugin that uses JAXB. The problem is that whether I launch a clean install in IntelliJ or in a console, I don't get the same results. JAXB is reading an XML file encoded in UTF-8, which contains special characters.
In IntelliJ, these characters are read without any problem.
But in the console, these characters are replaced with '?' (I can see it if I do a sysout).
I found the source of my problem, but I don't really understand it and I don't know how to solve it: when IntelliJ runs mvn, it adds an extra parameter -Dfile.encoding=UTF-8
java -classpath /usr/share/maven/boot/plexus-classworlds-2.4.jar -Dclassworlds.conf=/usr/share/maven/bin/m2.conf -Dmaven.home=/usr/share/maven -Dfile.encoding=UTF-8 org.codehaus.plexus.classworlds.launcher.Launcher clean install
When I run mvn in command line, I can add this extra parameter but it will appear after the class name:
java -classpath /usr/share/maven/boot/plexus-classworlds-2.4.jar -Dclassworlds.conf=/usr/share/maven/bin/m2.conf -Dmaven.home=/usr/share/maven org.codehaus.plexus.classworlds.launcher.Launcher -Dfile.encoding=UTF-8 clean install
In both cases, if I sysout the content of System.getProperty("file.encoding"), I get the same value "UTF-8", but a different behaviour.
Of course I configured my pom.xml correctly using a property like this:
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
I also tried to add a second property named "file.encoding" but it does not help.
My question is: why does the position of this system property change the behaviour of my program, and how can I fix my problem when I run mvn from command line?
Thanks in advance.

Maybe try including this XML in your pom.xml file:
<project>
[...]
<build>
[...]
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</source>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</build>
</project>

As suggested in other questions, the JVM starts with a default file encoding (usually the system file encoding) which is used every time Readers and Writers are used without an explicit encoding. Overriding the system property file.encoding at runtime does not change this behavior, you really have to specify -Dfile.encoding when starting the JVM if you want it to be the default encoding.
To fix my issue, I reused project.build.sourceEncoding in my Maven plugin (I had this problem in a custom plugin) to override file.encoding at runtime, and use this file.encoding to instantiate InputStreamReader and OutputStreamWriter with an explicit encoding as 2nd parameter.
As resources were correctly copied by the maven-resource-plugin in UTF-8, my problem was gone :D.

Related

Maven Compile Plugin By Command

I have a project in Windows-1254 file encoding and some of files are in UTF-8 encoding.
<properties>
<project.build.sourceEncoding>Windows-1254</project.build.sourceEncoding>
<project.reporting.outputEncoding>Windows-1254</project.reporting.outputEncoding>
<version.plugin.maven.resources>3.1.0</version.plugin.maven.resources>
<functionAppName>az-app-core</functionAppName>
</properties>
I added plugin in pom and compiles correctly with mvn compile.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
<executions>
<execution>
<id>compile1</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<excludes>
<exclude>**/StringUtil.java</exclude>
<exclude>**/TurkceInputTag_FaceLift.java</exclude>
<exclude>**/TurkceInputTag.java</exclude>
</excludes>
<encoding>Windows-1254</encoding>
</configuration>
</execution>
<execution>
<id>compile2</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<includes>
<include>**/StringUtil.java</include>
<include>**/TurkceInputTag_FaceLift.java</include>
<include>**/TurkceInputTag.java</include>
</includes>
<encoding>UTF-8</encoding>
</configuration>
</execution>
</executions>
</plugin>
But I need to compile project by command not just clean compile but also give all configurations(defined above compile1, compile2 executions) to maven like
maven compile-plugin:compile -Dexecutions/execution1/id=compile1,encoding=Windows-1254,excludes=....
I can't change File types encoding to only UTF-8 or Windows-1254 encoding. I need to compile project using both 2 encoding.
How can maven plugin compiles by command with configurations, encoding,executions etc.?
Unfortunately the command line for Maven is not as flexible as you might like it to be for what you're wanting to achieve. (I have quite a big question about why you're trying to achieve it, and can't just specify that information in the POM as you've demonstrated).
If you look at the goal documentation for maven-compiler-plugin:compile, you'll see that some of the options, like encoding, have a 'user property'. This, prefixed with -D to make it a system property, allow you to configure it from the command line:
mvn <goals/phases> -Dencoding=... -Dmaven.compiler.failOnError=...
But running a goal from the command line will give a single execution, not the set of two that you want. So your options might be:
Run the mvn command twice, with different options on each one. Tricky though as you can't specify inclusions/exclusions.
Split the project into more than one, having different options for encoding in each, and run those from the command line.
Get around whatever limitation it is that is giving you this issue in the first place, and run from the POM as you've defined rather than on the command line.
I second khmarbaise.
All source code files in one project need to have the same encoding. Choose one and convert the other source code files.
EDIT:
You mentioned that you could not convert the files, but unfortunately, you did not tell us why.
Whatever hinders you to do it, you need to solve that issue.
So if your colleagues, managers or customers tell you not to change encoding, then you need to solve this problem by talking to these people, explaining them that a Maven project needs to have one (and just one) source code encoding and convincing them to change that.
Feel free to comment on my answer if I misunderstood you.

Passing an options/arguments file to Maven compiler plugin

The javac command can be configured with a file by specifying that file on the command line with #:
javac #compileargs
I want to use that syntax in Maven so I can collect parts of the command line arguments in such a file instead of Maven's pom.xml.
The Maven compiler plugin does not seem to have a specific tag for that, so I tried compilerArgs:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<compilerArgs>
<arg>#compile-args</arg>
</compilerArgs>
<fork>true</fork>
</configuration>
</plugin>
But then javac complains:
javac: invalid flag: #compile-args
Usage: javac <options> <source files>
use --help for a list of possible options
If I get the actual command Maven is executing (with -X) and call that myself it works, though.
I recently had a similar problem with spaces in compiler options so I assume a similar process is screwing with me here.
Background info: The maven-compiler depends on the plexus compiler.
If the build process gets forked it will take all specified arguments and create a temporary config file on its own (see the code). The argument file will also include the user defined argument file, but the documentation points out that:
Use of the at sign (#) to recursively interpret files is not supported.
This means referencing an options file from Maven is not possible.

change classpath in Appassembler - Maven Plug-In

I'm using default appassembler configuration for generating execution script:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<configuration>
<programs>
<program>
<mainClass>SomeMainClass</mainClass>
<name>data-generator</name>
</program>
</programs>
</configuration>
</plugin>
after generating, my execution script contains lines such as:
set CLASSPATH = C:\Program Files (x86)\my-program\bin\\..\repo"\junit\junit\4.10\junit-4.10.jar
The goal is to change this paths to the following:
set CLASSPATH = C:\Program Files (x86)\my-program\bin\..\lib\junit\junit\4.10\junit-4.10.jar
Is there some good way to achieve this?
I've seen there are many optional parameters for this plugin but I'm not sure how to use it.
Could you bring more details to your question?
If you want to change default repository folder name, which is "repo", you can add following to configuration section
<repositoryName>lib</repositoryName>
All of your dependencies will be put to lib folder, so CLASSPATH will be also changed.
If you would like to shorten your CLASSPATH, you may add this option
<useWildcardClassPath>true</useWildcardClassPath>
Please tell me, if it solved your problem.

Specifying the Date in the tag generated by the maven-release-plugin

Within our project we declare our SVN tags in the format:
YYYY-MM-DD - v{project.version} [${environment}]
eg 2012-01-16 - v1.0.1 [LIVE]
Is it possible to achieve this with the maven-release plugin (version 2.2.2)?
It worth pointing out that the version and the environment parts are obtained and work with the release plugin. It is purely the timestamp that can't be retrieved.
This is what I would expect would work:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<preparationGoals>clean verify</preparationGoals>
<tagNameFormat>${timestamp} - v#{project.version} [${env}]</tagNameFormat>
<checkModificationExcludes>
.
.
.
</checkModificationExcludes>
</configuration>
</plugin>
The timestamp property is generated successfully using the buildnumber-maven-plugin as it is added to the manifest file for inclusion to the war file.
I have tried adding buildnumber:create goal into the preparation goals but it produces the following output when executing the release:prepare
What is SCM release tag or label for "Project Name"? (a.b.c.d) null - v1.0.1 [LIVE]: :
The issue seems to be that the the timestamp property is not generated at the point the tagName is being set which indicates that the preparation goals are not performed at the stage is asks for the tagName.
The following might work (will test it after lunch) although it i'd much rather just call release:prepare
mvn buildnumber:create release:prepare
Any input would be welcomed.
Cheers
EDIT
I have tested using the buildnumber:create release:prepare and it does work as expected although I did have to make further modifications which to be honest is a bit of a pain.
The TagNameFormat currently contains:
YYYY-MM-DD - v{project.version} [${environment}]
This contains spaces and square brackets and upon executing with this format you will get a error indicating the URL is not properly URI encoded. To get round this you must specify the tagNameFormat in a format that is already URI Encoded such as:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<preparationGoals>clean verify</preparationGoals>
<tagNameFormat>${timestamp}%20-%20v#{project.version}%20%5B${env}%5D</tagNameFormat>
<checkModificationExcludes>
.
.
.
</checkModificationExcludes>
</configuration>
</plugin>
This is nasty but it does work and it will create the tag as required.
Would be still interested to see if anyone has any suggestions as to how to get the timestamp in the tagNameFormat by just executing:
mvn release:prepare
and not
mvn buildnumber:create release:prepare
As of Maven 2.1 there is a variable: maven.build.timestamp available which can be configured using a property:
<properties>
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
</properties>
See: http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Available_Variables
This might make the buildnumber plugin no longer required and should be simpler to use.

Environment Variable with Maven

I've ported a project from Eclipse to Maven and I need to set an environment variable to make my project work.
In Eclipse, I go to "Run -> Run configurations" and, under the tab "environment", I set "WSNSHELL_HOME" to the value "conf".
How can I do this with Maven?
You can just pass it on the command line, as
mvn -DmyVariable=someValue install
[Update] Note that the order of parameters is significant - you need to specify any options before the command(s).[/Update]
Within the POM file, you may refer to system variables (specified on the command line, or in the pom) as ${myVariable}, and environment variables as ${env.myVariable}. (Thanks to commenters for the correction.)
Update2
OK, so you want to pass your system variable to your tests. If - as I assume - you use the Surefire plugin for testing, the best is to specify the needed system variable(s) within the pom, in your plugins section, e.g.
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
...
<configuration>
...
<systemPropertyVariables>
<WSNSHELL_HOME>conf</WSNSHELL_HOME>
</systemPropertyVariables>
</configuration>
</plugin>
...
</plugins>
</build>
The -D properties will not be reliable propagated from the surefire-pluging to your test (I do not know why it works with eclipse). When using maven on the command line use the argLine property to wrap your property. This will pass them to your test
mvn -DargLine="-DWSNSHELL_HOME=conf" test
Use System.getProperty to read the value in your code. Have a look to this post about the difference of System.getenv and Sytem.getProperty.
You could wrap your maven command in a bash script:
#!/bin/bash
export YOUR_VAR=thevalue
mvn test
unset YOUR_VAR
For environment variable in Maven, you can set below.
http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#environmentVariables
http://maven.apache.org/surefire/maven-failsafe-plugin/integration-test-mojo.html#environmentVariables
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
...
<configuration>
<includes>
...
</includes>
<environmentVariables>
<WSNSHELL_HOME>conf</WSNSHELL_HOME>
</environmentVariables>
</configuration>
</plugin>
Following documentation from #Kevin's answer the below one worked for me for setting environment variable with maven sure-fire plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<WSNSHELL_HOME>conf</WSNSHELL_HOME>
</environmentVariables>
</configuration>
</plugin>
Another solution would be to set MAVEN_OPTS (or other environment variables) in ${user.home}/.mavenrc (or %HOME%\mavenrc_pre.bat on windows).
Since Maven 3.3.1 there are new possibilities to set mvn command line parameters, if this is what you actually want:
${maven.projectBasedir}/.mvn/maven.config
${maven.projectBasedir}/.mvn/jvm.config
There is a maven plugin called properties-maven-plugin this one provides a goal set-system-properties to set system variables. This is especially useful if you have a file containing all these properties. So you're able to read a property file and set them as system variable.
in your code add:
System.getProperty("WSNSHELL_HOME")
Modify or add value property from maven command:
mvn clean test -DargLine=-DWSNSHELL_HOME=yourvalue
If you want to run it in Eclipse, add VM arguments in your Debug/Run configurations
Go to Run -> Run configurations
Select Tab Arguments
Add in section VM Arguments
-DWSNSHELL_HOME=yourvalue
you don't need to modify the POM
You can pass some of the arguments through the _JAVA_OPTIONS variable.
For example, define a variable for maven proxy flags like this:
_JAVA_OPTIONS="-Dhttp.proxyHost=$http_proxy_host -Dhttp.proxyPort=$http_proxy_port -Dhttps.proxyHost=$https_proxy_host -Dhttps.proxyPort=$http_proxy_port"
And then use mvn clean install (it will automatically pick up _JAVA_OPTIONS).
I suggest using the amazing tool direnv. With it you can inject environment variables once you cd into the project. These steps worked for me:
.envrc file
source_up
dotenv
.env file
_JAVA_OPTIONS="-DYourEnvHere=123"
As someone might end up here changing his global Java options, I want to say defining _JAVA_OPTIONS is a bad idea. Instead define MAVEN_OPTS environment variable which will still be picked up automatically by Maven but it won't override everything like _JAVA_OPTS will do (e.g. IDE vm options).
MAVEN_OPTS="-DmyVariable=someValue"

Categories