I have situation with my POM.xml like this:
...
<profiles>
<profile>
-some actions B
-some common for both profiles actions
</profile>
<profile>
-some actions A
-some common for both profiles actions
</profile>
</profiles>
Which ways can I use to take out the common actions to avoid copy/paste?
After that, how can I identify in my Java code which profile executes now?
I need this because the code is pretty common for both profiles, I can't separate it, so I want to create some condition in my java code, where I'll be able to choose further actions according to current Profile. I've tried to use SystemProperty configuration in my pom.xml by It was unsuccessful, I wasn't able to get this property by System.getProperty(..) and also I doubt that this is a good way.
Related
Note Well
Please see the edit section of the question below, as further investigation has rendered the majority of this question redundant.
Similar to this question, I can't seem to pass environment variables to my app on startup while using VSCode. The problem is, I have no idea what (or if an) extension is causing the issue.
I have VSCode 1.38.1 with the following extensions;
Language support for Java 0.48.0
Java Extension Pack 0.8.0
Maven for Java 0.18.2
Spring Boot Dashboard 0.1.6
Spring Boot Tools 1.10.0
and several others that I don't feel are the culprits.
What I want to do is use maven profiles to conditionally bring in dependencies, and use environment variables to trigger that. In my pom.xml, I have;
<profiles>
<profile>
<id>dev-mysql</id>
<activation>
<!-- activate if system properties 'env=dev-mysql' passed in on launch.json env property from VSCode -->
<!-- Following does not work :( -->
<property>
<name>env</name>
<value>dev-mysql</value>
</property>
<!-- Obtain the following info by running - mvn enforcer:display-info -->
<!-- <os>
<name>windows 7</name>
<family>windows</family>
<arch>amd64</arch>
<version>6.1</version>
</os> -->
</activation>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
</dependencies>
</profile>
</profiles>
I try and pass that env value in by setting it in launch.json via something like;
{
"type": "java",
"name": "Debug (Launch)-MyServiceApplication<my-service>",
"request": "launch",
"mainClass": "myapp.MyServiceApplication",
"projectName": "my-service",
"vmArgs": "-Dspring.profiles.active=local-mysql",
"env": {
"env": "dev-mysql"
}
}
I've also tried adding in maven customEnv through settings.json as the Maven for Java extension seems to suggest that "...These environment variable values will be added to the terminal session before Maven is first executed". My settings.json file looks like;
{
"java.configuration.updateBuildConfiguration": "automatic",
"files.exclude": {
"**/.classpath": true,
"**/.project": true,
"**/.settings": true,
"**/.factorypath": true
},
"maven.terminal.customEnv": [
{
"environmentVariable": "env",
"value": "dev-mysql"
}
]
}
I execute my application by hitting F5, which to my understanding executes what is shown in the launch.json snippet above. I don't quite understand how maven is invoked here. However, no matter what, it doesn't seem to ever find the environment variable and therefore include the profile specific mysql dependency. Even if I use Spring Boot Dashboard, I get the same result; the mysql dependency isn't recognised so I end up with Cannot load driver class: com.mysql.cj.jdbc.Driver
If I comment out the <property> element of my pom.xml and uncomment the <os> element, then it does bring in the profile specific mysql dependency. So I am guessing it uses the pom file correctly.
Does anyone have any clue how to set environment variables so that they'll be recognised with this configuation? Also, any further information as to what is actually executed when I hit F5 with this setup (is it maven, is it Java), it would be much appreciated.
Edit:
Some further investigation has shown that I was "...confusing Environment Variables with System Properties" comment by Wouter Lievens.
This post also suggests that "you cannot activate profiles based on system properties defined after the build plan has started execution", which may well be what happens when I just hit F5 to execute my application. This also links to some further information in this answer which clarifies that if won't work as "...profiles are the first thing evaluated before anything else to determine the effective POM.".
My workaround is to not use F5, but instead, when I have set the spring-profiles-active=local-mysql, I have to use the Maven for Java Explorer to execute a custom target of spring-boot:run -Pdev-mysql
So my last questions are;
Given the extensions I have added to VSCode combined with the above launch.json, what is actually executed when I hit F5 with this setup - is it Maven, Java or something else? If it is Java, how does the pom.xml come into play? If it is Java, is there a way of adjusting the launch.json to use mvn instead?
Is there a way to up the verbosity of the logging when I hit F5 to get a better understanding of what is actually being executed?
when running vscode driven tests, putting the environment variables in settings.json instead of launch.json works for me:
{
"java.configuration.updateBuildConfiguration": "automatic",
"java.test.config": [
{
"workingDirectory": "${workspaceFolder}",
"env": {
"STAGE_ENV": "DEV",
"AWS_REGION": "us-west-2"
}
}
]
}
however: maven tests do not read from this. I can run maven tests by adding the variables in the pom at this location:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
</plugin>
<plugin>
<!-- run unit tests -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<environmentVariables>
<!-- add them here -->
<STAGE_ENV>DEV</AWS_ACCESS_KEY>
<AWS_REGION>us-west-2</AWS_REGION>
<!-- -->
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
I have yet to find a good solution to use a single .env file to support both cases.
I am using a service in my spring project.I have following code in my web.xml:-
<init-param>
<param-name>prerenderServiceUrl</param-name>
<param-value>http://10.0.0.45:3000</param-value>
</init-param>
I have 3 profiles in my pom.xml: staging,development & production:
I am looking for the best practices to get <my.service.url> in my web.xml:
<profile>
...
<properties>
...
<my.service.url>http://10.0.0.45:300</my.service.url>
...
</properties>
</profile>
I think the maven resources plugin's filtering function what you need: (http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html)
Maybe you can consider to store environment specific variables in the target environment, not in your build scripts/properties and you can load it from the classpath during the startup. Tight coupling your environment settings with your pom.xml adds some extra effort to you to update your build settings every time when the environment changes or new servers added.
Even though you can use profiles, they shouldn't be used in this case. The idea is that you can distribute the same war over and over again and that the configuration is pulled in. Read How to pass value to maven pom.xml at rum time from java file? for all the options.
Is it possible to do this?
For example could one do something like:
System.getEnv("$(env.BUILD_URL)");
I do not have access to Jenkins, so can't try it out myself :(
Any help would be greatly appreciated.
Assuming you're using Maven (you've tagged this question as such), I simply add the following to my pom.xml file:
...
<properties>
<!-- Hudson properties: see http://wiki.hudson-ci.org/display/HUDSON/Building+a+software+project#Buildingasoftwareproject-HudsonSetEnvironmentVariables -->
<jenkins.buildId>${env.BUILD_ID}</jenkins.buildId>
<jenkins.buildNumber>${env.BUILD_NUMBER}</jenkins.buildNumber>
<jenkins.buildTag>${env.BUILD_TAG}</jenkins.buildTag>
<jenkins.cvsBranch>${env.CVS_BRANCH}</jenkins.cvsBranch>
<jenkins.executorNumber>${env.EXECUTOR_NUMBER}</jenkins.executorNumber>
<jenkins.hudsonUrl>${env.HUDSON_URL}</jenkins.hudsonUrl>
<jenkins.javaHome>${env.JAVA_HOME}</jenkins.javaHome>
<jenkins.jobName>${env.JOB_NAME}</jenkins.jobName>
<jenkins.svnRevision>${env.SVN_REVISION}</jenkins.svnRevision>
<jenkins.workspace>${env.WORKSPACE}</jenkins.workspace>
</properties>
...
...and then from your code you can simply do a:
String url = System.getProperty("jenkins.hudsonUrl"); // could be null
Putting these into properties makes life more simple for my purposes, especially when using Maven profiles to control my builds. For example, I make sure to create a "jenkins" profile that is activated when I build on a Jenkins build server. When this is done, all the aforementioned jenkins properties are set. When not run as a jenkins profile, those properties are set to some other default value. Anyway, that's another topic, but food for thought. Hopefully it make sense.
I am quite new to Maven and Java EE programming all-together.
I would like to create a stub class for authentication testing which should be activated in the default Maven build profile.
Currently I have two classes with same name but in different packages. Is it possible to somehow select the correct class to use in the build phase by setting maven build profile parameters? I am also using EJB and JSF2.0 in my project and the authentication object is created in one of the beans:
AuthUtil util = new AuthUtil();
It is possible, with some footwork. You will have to put your class(es) in a dependency and use the profiles in this manner:
<profiles>
<profile>
<id>default</id>
<dependencies>
<dependency>...</dependency>
</dependencies>
</profile>
<profile>
<id>someotherprofile</id>
<dependencies>
<dependency>...</dependency>
</dependencies>
</profile>
</profiles>
Also, the classes will have to be in the same package for this to work.
Cheers,
You can specify the concrete class in a property file, and filter property files by maven build profile, so they would get different values. Property file would then be read by java code and it would be used accordingly.
Is there some reason to do this? It doesn't feel like the right way of doing things...
In order to connect to an external system, for which each developer has a personal username and password, I need to pull in a username and password to my JUnit test cases:
String username = System.getProperty("ext.username");
The above line would be called inside any class inside my test folder
How can I best do this via Maven? I think the best scope for the property is inside settings.xml, but I'm not sure about the best way to transfer it from there into my code.
The problem is best solved using a Maven build profile.
In your POM you declare a default value for the properties (To prevent run-time possible errors).
<project>
..
<properties>
<ext.username>XXXXX</ext.username>
<ext.password>YYYYY</ext.password>
</properties>
Each developer can then override these properies in theor local build using a default profile specified in their settings file: $HOME/.m2/settings.xml
<settings>
..
<profiles>
<profile>
<id>dev</dev>
<activeByDefault>true</activeByDefault>
<properties>
<ext.username>XXXXX</ext.username>
<ext.password>YYYYY</ext.password>
</properties>
</profile>
..
</profiles>
..
</settings>
For those worried about security is also possible to encrypt the password.
Finally, it's possible to have multiple profiles configured. These can be chosen at run-time (using profile id) in order to support multiple build environments:
mvn -Pdev ..
mvn -Pprod ..