Spring-boot application can only be launched with spring-boot:run when forking - java -jar fails - spring-boot

I have a Spring Boot web application that I cannot start when using the executable jar directly.
I am using Spring Boot 1.2.0.RELEASE, Maven 3.0.5, Java 1.7.0_72.
I have a requirement to use the hp-roman8 character set - in order to handle incoming requests from some remote legacy systems. To provide the hp-roman8 charset I use net.freeutils.jcharset in version 1.5.
The jcharset artifact is installed in my local repository
However when launching my application using java -jar the application fails to start and I get "java.nio.charset.UnsupportedCharsetException: hp-roman8" as cause.
The same error occurs if I do mvn spring-boot:run unless I configure spring-boot-maven-plugin to always fork.
With <fork>true</fork> spring-boot:run starts the application successfully and the hp-roman8 charset is available on the classpath.
However <fork>true</fork> has no effect on the created jar, so I am still unable to launch my application using java -jar - and continue to get the "java.nio.charset.UnsupportedCharsetException: hp-roman8".
The jcharset-1.5.jar is included correctly in the created executable jar file next to the rest of the dependencies in the path "lib/jcharset-1.5.jar" so I don't quite understand why it is not available on the classpath when launching the jar.
Have any of you seen similar behavior, or have any ideas as to what I could try out in order to troubleshoot or even resolve this problem?
update:
I have also tried changing the main-class to use the PropertiesLauncher instead (using the <layout>ZIP</layout> tag in the plugin configuration) - see http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-maven-packaging.
Afterwards I added loader.path to my application.properties. Even if I specify the absolute path to jcharset-1.5.jar I still get the UnsupportedCharsetException.
I also tried using an exploded archive but still no go.

You could use Maven's shade plugin rather than Spring Boot's Maven plugin. The main difference is that the shade plugin takes all of your project's dependencies and packages them directly in the jar file, i.e. it doesn't use nested jars. While this has some disadvantages, it does mean that a single class loader is used to load all of your application's classes and, therefore, JCharset is available to the application class loader.
When you're using the Shade plugin, you shouldn't use Spring Boot's starter parent. You may want to import Boot's dependency management instead.
Your pom would look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-sample-jcharset</artifactId>
<version>0.1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-sample-jcharset</name>
<description>Spring Boot sample showing the use of JCharset in an executable jar</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Any additional dependencies, including JCharset -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>sample.jcharset.SampleJCharsetApplication</Main-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Related

Provide Spring Boot git and build information via /actuator/info endpoint when using maven as a build tool

I am using this Spring Boot guide Building a RESTful Web Service with Spring Boot Actuator. When accessing endpoint /actuator/info I am getting empty json response {}.
The actuator api documentation mentions response structures which contain build information like artifact, group, name, version and git information like branch, commit etc.
How can I enable the documented response structures. I want to use maven as build tool (not gradle). This is my pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>actuator-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>actuator-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
After further research I found the answer in the documentation:
Git Information
Add this to plugins section of pom.xml. maven will generate this file during build ./target/classes/git.properties. Spring will read contents of this file and include it in the response of /actuator/info
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>
See Git Commit Information and Generate Git Information
Build Information
Add an execution goal to spring-boot-maven plugin. This will generate the file ./target/classes/META-INF/build-info.properties. Spring will read contents of this file and include it in the response of /actuator/info
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.7.RELEASE</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
Source: Build Information and Generate Build Information
Below is the working solution on Gradle.
Gralde Version 7.3.2
SpringBoot Version: 2.6.1
To include actuators for the project. below dependency should be added to the build.gradle file.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
By default only health is available over web. So to enable the info actuator add below entry in your application.yml
management:
endpoints:
web:
exposure:
include: "health,info"
Now when we run the application and attempt to access the /actuator/info end point it prints empty json in response. This is the default behavior of info actuator end point.
To generate the buildInfo from build.gradle, add below in your gradle file
springBoot {
buildInfo()
}
Now if you run the application and hit /actuator/info endpoint, output will be your project's build info
{"build":{"artifact":"actuator-service","name":"","time":"2022-01-12T18:16:28.468Z","version":"0.0.1-SNAPSHOT","group":"com.example"}}
Additional we can configure to generate the git commit information. To do this, you have to apply below plugin
id "com.gorylenko.gradle-git-properties" version "1.5.1"
Once done, on the project build, it will generate a file called git.properties in your build/resources folder.
And now the /actuator/info endpoint will also generated the git information from the git.properties. By default it won't generate all configs from git.properties.
If you want to see full git configuration in /info endpoint, do the below config in application.yml
info:
git:
enabled: true
mode: full
References:
https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/html/howto-build.html#howto-build-info
https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/html/howto-build.html#howto-git-info
I had the same problem, /actuator/info always returns {}
First, add plugins (lombok is not necessary):
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>
Second, go Maven -> compile. Now, in target/classes should be generated git.properties and META-INF folder with build-info.properties.
Finally, run your app and that's it!
You can do that for example by adding the following to your application.properties
info.app.name=#project.name#
info.app.version=#project.version#
info.app.encoding=#project.build.sourceEncoding#
info.app.java.version=#java.version#
Source: https://dzone.com/articles/magic-with-spring-boot-actuator

Is there a way to specify to push complete jar folder on both driver and executors?

Is there any way to specify complete folder path of the jars to be pushed on driver as well as executor like --jars in spark-submit, which excepts comma separated jar names with full path. But it's tedious work if we do have too many jars to be pushed on both driver as well as executor.
Question : Is there a way to specify to push complete jar folder on both driver
and executors?
Yes you can make uber jar which is self contained distribution with all depedencies packed inside.
sample if you are using maven, you can use maven shade plugin or assembly plugin for this. below is shade example.
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.maventest</groupId>
<artifactId>mytest</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>mytest</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>uber-${artifactId}-${version}</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>
If you are using sbt see this
your spark submit will look like ....
spark-submit [PATH_TO_YOUR_UBER_JAR]/[YOUR_UBER_JAR].jar
Further reading for example Googles article : Managing Java dependencies for Apache Spark applications
Running spark on yarn you have to be able to set spark.yarn.archive or spark.yarn.jars in spark-defaults.conf configuration file.
spark.yarn.archive is intended for distribution of the archive with all the jars you need on your executors.
spark.yarn.jars is for separate jars.
You may find more information in the official docs.

How can i make my CSS reload on page refresh? gwt maven

Here is the project i'm working on: https://github.com/veracityidinc/idf-sandbox
I'm a front end dev so this is all a bit unclear to me.
I looked at the build log to try to figure after of course consulting google, and i see people saying stuff about a plugin and copying files. It just seems very weird to me that a web project - be it whatever kind - doesn't do this out of the box. It is very tedious to have to close and run the server any time i make a change. Also very weird that the html part of the app actually does this on its own.
GWT only deals with JS (and assets directly loaded by the code through special code constructs), not the other web assets.
DevMode (mvn gwt:run with Mojo's plugin) will serve your webapp, and Mojo's plugin will additionally copy the src/main/webapp on launch. If you want to update your web assets without restarting the DevMode, run mvn war:exploded -Dgwt.compiler.skip. And similarly for resources (in src/main/resources): run mvn process-resources.
This is also one good reason to adopt a different project layout, separating client and server code into distinct Maven modules, and running client and server code separately too (mvn gwt:codeserver for client code, through the net.ltgt.gwt.maven:gwt-maven-plugin, and mvn jetty:run or similarly for server code and web assets)
Using GWT SDM -Super dev mode- you will get this out of box, the SDM will keep running i the background and watch for files modified and upon refresh it will incrementally recompile your app and reload resources.
if you are using maven to get SDM to work you need to create a GWT project and apply the maven plugin, the recommended plugin is the tbroyer plugin and to create a GWT project that already configured correctly out of the box you can use the tbroyer multi module gwt-maven-archetype.
following the instructions from the archetype when you issue the command
mvn gwt:codeserver -pl *-client -am you are actually starting the SDM. the other command is starting your application server.
the generated project has a xxx-server module in which you can find a css file. once you run both commands and can load your application in the browser try to change some styles in that file and refresh the page, the changes should be reflected.
this is a sample plugin configuration when generating a project from the archtype
<plugin>
<groupId>net.ltgt.gwt.maven</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<configuration>
<moduleName>[replace this with your module]</moduleName>
<moduleShortName>app</moduleShortName>
</configuration>
</plugin>
now if you are not using this multi module structure you might try the start the application and the SDM using mvn gwt:devmode this should start the SDM for you
and if you are using uibinder, and you are editing styles in the *.ui.xml files when the SDM recompiles it should also pick the changes.
Edit
Checking on your project i made some changes to make it work.
first i changed the pom.xml, you can use my version for later projects but i think the better way is the generate a project using tbroyer archetype
The pom
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.candorgrc.idfusion</groupId>
<artifactId>idf-sandbox</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>IdFusion™ Sandbox</name>
<properties>
<!-- Setting maven.compiler.source to something different to 1.8 needs
that you configure the sourceLevel in gwt-maven-plugin since GWT compiler
2.8 requires 1.8 (see gwt-maven-plugin block below) -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<inject.gin.version>2.1.2</inject.gin.version>
<inject.guice.version>3.0</inject.guice.version>
<libsass.version>0.2.10-libsass_3.5.3</libsass.version>
<lesscss.version>1.7.0.1.1</lesscss.version>
<elemental2.version>1.0.0-RC1</elemental2.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt</artifactId>
<version>2.8.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.elemental2</groupId>
<artifactId>elemental2-dom</artifactId>
<version>${elemental2.version}</version>
</dependency>
<dependency>
<groupId>com.google.gwt.inject</groupId>
<artifactId>gin</artifactId>
<version>${inject.gin.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${inject.guice.version}</version>
</dependency>
</dependencies>
<build>
<!-- Output classes directly into the webapp, so that IDEs and "mvn process-classes"
update them in DevMode -->
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<plugins>
<!-- GWT Maven Plugin -->
<plugin>
<groupId>net.ltgt.gwt.maven</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.0-rc-8</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<moduleName>com.candorgrc.idfusion.sandbox.IdfSandbox</moduleName>
<moduleShortName>IdfSandbox</moduleShortName>
<failOnError>true</failOnError>
<!-- GWT compiler 2.8 requires 1.8, hence define sourceLevel here if
you use a different source language for java compilation -->
<sourceLevel>1.8</sourceLevel>
<warDir>${project.build.directory}/${project.build.finalName}</warDir>
<classpathScope>compile+runtime</classpathScope>
<!-- URL(s) that should be opened by DevMode (gwt:devmode). -->
<startupUrls>
<startupUrl>sandbox.html</startupUrl>
</startupUrls>
</configuration>
</plugin>
<plugin>
<groupId>org.lesscss</groupId>
<artifactId>lesscss-maven-plugin</artifactId>
<version>${lesscss.version}</version>
<configuration>
<sourceDirectory>${project.basedir}/src/main/webapp/less</sourceDirectory>
<outputDirectory>${project.basedir}/src/main/webapp/less</outputDirectory>
<compress>true</compress>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
you will also need to create a new package on the same level as the client package and name it public this is the default public resource used by gwt. this should go in the src folder com.candorgrc.idfusion.sandbox.public then move your css file sandbox.css into this package.
once you do these changes you will be able to reload the css when you refresh the page as long as your IDE knows that the css is changed and it should move it to the correct location in the target folder.

Import spring boot app into another project

So I am attempting to add a spring boot executable jar as a dependency in another project (Testing framework).
However once added to the pom and imported. Java imports don't work properly. If I look inside the jar all packages are prepended with:
BOOT-INF/classes.some.package.classname.class
There is also some spring boot related packages, MANIFEST etc etc.
Not if I switch the spring boot app's build to just install and deploy a regular jar using the spring-boot-maven-plugin
This changes and everything works fine. Unfortunately this is not a solution for us as we lean on the executable jar as part of our release process.
Can I build a deploy both versions of the jar and use a classifier to determine each?
Thanks
Turns out this exact scenario can be achieved using the spring-boot-maven-plugin.
Spring boot app's pom:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.1.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
...
</plugin>
project using the spring boot jar can be added as normal:
<dependency>
<groupId>com.springboot</groupId>
<artifactId>app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
OR if you want to reference the executible jar
<dependency>
<groupId>com.springboot</groupId>
<artifactId>app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
<classifier>exec</classifier>
</dependency>

Spring boot with maven multi module project

I have a maven multi module project designed like the first answer in following SO post:
Multi-module maven with Spring Boot
Now I want a common maven module that can contain some models to be used by multiple microservices. If I make this common project as a child of the first level parent pom (so that all dependencies injected by boot like jpa, jackson etc are available to common), then STS/Spring is detecting it as a boot application and complains about no Main class on maven build.
Can someone suggest how I can achieve this?
Current Code:
parent pom.xml: (Only relevant parts included)
<project>
<name>...</name>
<groupId>...</groupId>
<artifactId>...</artifactId>
<packaging>pom</packaging>
<version>...</version>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M3</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
child (common module) pom.xml (only relevant parts), not to be boot app:
<project>
<artifactId>...</artifactId>
<version>...</version>
<name>...</name>
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
</parent>
</project>
I don't have all the details regarding your project but my best guess is that the spring-boot-maven-plugin is defined on the parent (or you are using the spring-boot-starter-parent in your root pom). This effectively ask the build to package your module as a Spring Boot app (which is not what you want).
STS probably looks for that hint to figure out if a module contains a Spring Boot application or not. Maybe it would be nicer if it looks for a main class annotated with #EnableAutoConfiguration (or SpringBootApplication).
You can fix the problem easily (from the build side) by specifying the skip property of the repackage goal
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
If STS still picks up the module as a Spring Boot app, I'd create an issue in their tracker
Normally, Spring Boot won't start a web container if it's not present in the module.
I would suggest you to analyse your dendencies using the command
mvn dependency:tree
One more brute-force way of ensuring is use this configuration in your application.properties
spring.main.web-environment=false
Here are two ways to fix this:
You can add the skip property like #Stephane Nicoll mentioned. However, this will completely ignore the test cases inside that module. https://docs.spring.io/spring-boot/docs/current/maven-plugin/examples/it-skip.html
Another option is to add a classifier property to make a separate executable jar out of this module. https://docs.spring.io/spring-boot/docs/current/maven-plugin/examples/repackage-classifier.html
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
This fix will make sure the dependent module get its required jar and the source module will still be an executable one.

Resources