Best way to run spring boot 2 rest services - spring

I am writing an app that exposes some functions via REST service.
To do this I am using Spring Boot 2, but what is the best way to put it on production environment?
Is a good idea run the jar using java?

Short answer
yes it is a good idea.
Long answer
Spring Boot features a plugin that prepends a service script (Unix-compatible) in the JAR file itself. That makes the JAR file executable in Unix/Linux environments and you can easily install it as a service. Excerpt from https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html follows:
To create a "fully executable" jar with Maven, use the following plugin configuration:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
If packaging for Windows, the startup script isn't of much use and can be omitted. You would need to run using java -jar ... on windows, or install a service wrapper. Another excerpt from the Spring Boot doco:
A Spring Boot application can be started as a Windows service by using winsw.
A (separately maintained sample) describes step-by-step how you can create a Windows service for your Spring Boot application.

You can make it fully executable with below code in your pom.xml. You can run with shell script or as systemv or initd service[Spring Boot DOC]. This is the best tutorial link I have found explaining the multiple run as service options. You might want to take a look at spring doc for production ready features.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>

Related

Quarkus Endpoints in dependency jars

I have a quarkus application which has dependencies to another maven module within the same project
within that module are REST endpoints
For some strange reason i cannot access those endpoints tho.. It seems quarkus will only accept endpoints of java classes within the quarkus module, or am I mistaken?
I foudn a solution:
if yopu add the jandex, endpoiints of other modules are being scanned, and can thus be found :
<build>
<plugins>
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
You can do this by creating a dummy extended class:
Lets assume your imported jar has this pattern, app\proto-gen\1.0-SNAPSHOT\proto-gen-1.0-SNAPSHOT.jar
Add the below to application.properties,
quarkus.index-dependency.mygrpc.group-id=app
quarkus.index-dependency.mygrpc.artifact-id=proto-gen
#Singleton
MyGrpc extends XImplBase{
//your implementation
}
beans you extended/implemented in your current project will be started.
Check https://quarkus.io/guides/cdi-reference. You need to add a beans.xml to external models, create an index or reference the dependency using quarkus.index-dependency in the application.properties.
Then it will work when running tests or using the runner. But not in dev, because there is a probably in the current version (1.1.1Final). This problem has been fixed in the master, though, and will be available in the next release next month.
Please check ClassCastException in Quarkus multi-module project for more details.

TypeNotPresentExceptionProxy error at integration-test with maven-failsafe-plugin spring-boot 1.4

I'm getting ArrayStoreException: TypeNotPresentExceptionProxy when running integration-test with maven-failsafe-plugin and spring-boot 1.4.
You can see this error if you run joinfaces-example with
mvn -Pattach-integration-test clean install
I realized that the error does not occur if I change spring-boot-maven-plugin to run at pre-integration-test phase instead of package one.
More, this error started when I upgraded spring boot to 1.4. No error occurs if I change jsf-spring-boot-parent version to 2.0.0 which uses spring boot 1.3 version.
I actually found the answer in Spring Boot 1.4 release notes, short answer is that maven-failsafe-plugin is not compatible with Spring Boot 1.4's new executable layout. Full explanation below :
As of Failsafe 2.19, target/classes is no longer on the classpath and
the project’s built jar is used instead. The plugin won’t be able to
find your classes due to the change in the executable jar layout.
There are two ways to work around this issue:
Downgrade to 2.18.1 so that you use target/classes instead
Configure the spring-boot-maven-plugin to use a classifier for the
repackage goal. That way, the original jar will be available and used
by the plugin. For example :
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
An alternative is documented here: https://github.com/spring-projects/spring-boot/issues/6254
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<!--
Make failsafe and spring-boot repackage play nice together,
see https://github.com/spring-projects/spring-boot/issues/6254
-->
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
</configuration>
</plugin>
This worked better for me, because when I used the "exec" solution, Spring failed to find my configuration files when starting the container. Which could probably be fixed by adding some further configuration parameters, I suppose, but this solution works "out of the box" for me.

Spring Boot with Cucumber E2E (Selenium) testing

In my project, I have to current Maven modules setup:
- Application
|- (application code, using Spring Boot 1.2.6)
- E2E-testing (has a dependency to Application)
|- src
|- main
|- java
|- AbstractCucumberTest.java
Before, this used to be a Spring 3 application serving JSP pages, so no Boot included. I refactored it to be a Boot application.
The E2E testing setup basically built a WAR file of the application code, and the E2E module booted a Jetty server, running that WAR. All was well.
Now, after the refactor, not so much.
The Jetty setup no longer works as-is. When I boot the WAR, I'm getting class loading exceptions, which are related to Jetty itself. Now, I'm not hung up on Jetty, it's just a testing container for me. So I started digging around in the Boot documentation, because I was convinced there had to be a way to make it all "Boot'-iful, meaning: I could simply boot the application when launching the tests. And there is, of course, so I ended up with these annotations on my AbstractCucumberTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationConfig.class, loader = SpringApplicationContextLoader.class)
#WebIntegrationTest({"spring.profiles.active=local"})
public abstract class AbstractCucumberTest extends SeleniumTest {
So, basically, I'm loading the application config of the application, and launching the Tomcat server from the test. And all rejoiced, because now the application was successfully booting upon launching a Cucumber test. The application boots, it reads the classpath, Liquibase boots, everything is working alright. I can call the Actuator endpoints, which all work fine. Even the REST endpoints of the application are all working, so Spring MVC is doing its thing.
However, 1 thing is not, and that's serving JSP's -- and that's of course a deal breaker for E2E tests. Every time I surf to a page, I get the same unnerving 404 error. Before you ask: yes, tomcat-embed-jasper and jstl are present. They are present in the application, I even added them to the E2E pom, no luck. In fact, these are the things I tried, but they all failed:
Excluding the tomcat-embed-jasper and jstl dependency from the application
Copying over the JSP's from the application to the resources of the E2E module
Setting up my own CucumberConfig, which basically contained the same configuration as the ApplicationConfig
It just seems to me that the application cannot find the JSP's. Everything else is working just fine, just the JSP's are not found/served.
Does anyone have any thoughts?
Oh, on a side note, I tried using the spring-boot-maven-plugin, to try and boot the application that way. Problem is, though, that it cannot be forked. In the 1.2.6 release, the fork simply ... does not fork. When I say fork, I mean it in the Jetty way: it boots the application, and gives control back to Maven. It instantiates a "stop" command, which Maven can call after all tests have run.
In the 1.3.0.BUILD-SNAPSHOT version, it should be present (using the start goal), but that's still not working for me.
[EDIT] For what it's worth, the Application module is configured to build a WAR file. So it's not JAR packaging.
To whom it may concern, eventually I turned to the Maven Cargo plugin, which works just fine. I configured it in the pom of the E2E testing module. As you can see, my application is marked as a deployable, and the cargo plugin boots at the pre-integration-test phase, and shuts down at post-integration-test phase.
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.16</version>
<configuration>
<container>
<containerId>tomcat8x</containerId>
<zipUrlInstaller>
<url>
http://archive.apache.org/dist/tomcat/tomcat-8/v8.0.27/bin/apache-tomcat-8.0.27.zip
</url>
</zipUrlInstaller>
</container>
<deployables>
<deployable>
<groupId>my.group.id</groupId>
<artifactId>Application</artifactId>
<type>war</type>
<properties>
<context>/context</context>
</properties>
</deployable>
</deployables>
<configuration>
<type>standalone</type>
<properties>
<cargo.servlet.port>9999</cargo.servlet.port>
<cargo.jvmargs>-Dspring.profiles.active=local</cargo.jvmargs>
</properties>
</configuration>
</configuration>
<executions>
<execution>
<id>start-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>

How to compile Spring Boot applications with Java 8 --parameter flag

Spring documentation tells that, if we compile our project using Java 8 --parameters flag, we can skip giving parameter names in annotations like #PathVariable. That means, we can just use #PathVariable id instead of #PathVariable("id") id.
In a Spring Boot Maven application, I was curious to know how to tell the compiler to use the parameters flag. Is it on by default? Do we need to provide something in the pom.xml?
In Spring Boot 2.0, the --parameters flag should be enabled by default. See yuranos87's answer.
For older versions, in the pom.xml file, you can specify Java compiler options as arguments of the Maven compiler plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
I don't remember needing to do it explicitly in any of my projects. Maybe you just need to add spring-boot-starter-parent(I know, sometimes might not be an option). Otherwise, Spring has already taken care of everything for you.
It is mentioned multiple times in Spring Boot documentation. For example, here:
To allow the input to be mapped to the operation method’s parameters, code implementing an endpoint should be compiled with -parameters. This will happen automatically if you are using Spring Boot’s Gradle plugin or if you are using Maven and spring-boot-starter-parent.
UPDATE
The way Spring Boot does it is quite straight forward(in spring-boot-parent and spring-boot-starter-parent poms):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<parameters>true</parameters>
</configuration>
</plugin>

"mvn spring-boot:run": "/health" endpoint with project version

I'd like to use Spring Boot's actuator endpoint /info to show project metadata such as the Maven-provided project version.
To do so, I followed the appropriate part in Spring Boot's documentation.
The shown solution works for me when my Spring Boot application starts up with java -jar [...].
Just as the documentation says, it doesn't work when the application starts up with mvn spring-boot:run — in that case, my /info endpoint reports "version":"#project.version#".
The documentation mentions that one has to properly configure Spring Boot's Maven plugin, but I could not find any information about doing so.
How can I configure my Maven project in order to have a mvn spring-boot:run-started Spring Boot application to show project metadata?
Configure the spring-boot-maven-plugin with <addResources>false</addResources>.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
<configuration>
<addResources>false</addResources>
</configuration>
</plugin>
Source

Resources