Gradle spring and angular custom build - spring

I'm new to gradle. I have a spring boot and angular project.
I'm using com.moowork.node to build angular project. I need 2 to create separate tasks the first one to build spring and angular and produce fat jar, and second task to only build spring boot without angular project
I tried
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
task appNpmInstall(type: NpmTask) {
args = ['install']
}
task appNpmBuild(type: NpmTask) {
args = ['run', 'build']
}
task copyWebApp {
doLast {
copy {
from 'dist' into '../build/resources/main/static'
}
}
}
appNpmBuild.dependsOn appNpmInstall
copyWebApp.dependsOn appNpmBuild
then
task("buildFull") {
dependsOn('frontend:copyWebApp')
dependsOn build
}
But this build the frontend app without spring boot and not product the Jar

You can provide a folder path to the jar plugin and then all files from there will be copied to the final jar.
jar {
from 'dist'
}

A suggestion, plz avoid the fat jar to have the angular's dist folder. Run the fat jar ( say on port 8081). Simply keep the angular's dist folder on any web server (for e.g. Nginx server, say port 8080). Have the angular app point to REST services running on 8081.

Related

How to create a Jar file of a spring boot application using Intellij and gradle [duplicate]

I'm trying to build an executable jar in Spring Boot + Gradle project, but for now nothing works. Here is the simplest possible structure. Possibly, something is missing in Gradle configuration.
Gradle:
buildscript {
ext {
springBootVersion = '1.5.8.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
jar {
manifest {
attributes 'Main-Class': 'com.example.demo.DemoApplication'
}
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
}
Main config file:
#RestController
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#GetMapping(value = "/")
public String index() {
return "index";
}
}
When I ran the jar file like java -jar 1.jar, I got this exception:
[main] ERROR org.springframework.boot.SpringApplication - Applicati
on startup failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to proces
s import candidates for configuration class [com.example.demo.DemoApplication];
nested exception is java.lang.IllegalArgumentException: No auto configuration cl
asses found in META-INF/spring.factories. If you are using a custom packaging, m
ake sure that file is correct.
at org.springframework.context.annotation.ConfigurationClassParser.proce
ssDeferredImportSelectors(ConfigurationClassParser.java:556)
at org.springframework.context.annotation.ConfigurationClassParser.parse
(ConfigurationClassParser.java:185)
at org.springframework.context.annotation.ConfigurationClassPostProcesso
r.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308)
at org.springframework.context.annotation.ConfigurationClassPostProcesso
r.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228)
at org.springframework.context.support.PostProcessorRegistrationDelegate
.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.ja
va:272)
at org.springframework.context.support.PostProcessorRegistrationDelegate
.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92)
at org.springframework.context.support.AbstractApplicationContext.invoke
BeanFactoryPostProcessors(AbstractApplicationContext.java:687)
at org.springframework.context.support.AbstractApplicationContext.refres
h(AbstractApplicationContext.java:525)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationConte
xt.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.
java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringAppli
cation.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java
:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java
:1118)
at org.springframework.boot.SpringApplication.run(SpringApplication.java
:1107)
at com.example.demo.DemoApplication.main(DemoApplication.java:13)
Caused by: java.lang.IllegalArgumentException: No auto configuration classes fou
nd in META-INF/spring.factories. If you are using a custom packaging, make sure
that file is correct.
at org.springframework.util.Assert.notEmpty(Assert.java:277)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelecto
r.getCandidateConfigurations(AutoConfigurationImportSelector.java:153)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelecto
r.selectImports(AutoConfigurationImportSelector.java:95)
at org.springframework.context.annotation.ConfigurationClassParser.proce
ssDeferredImportSelectors(ConfigurationClassParser.java:547)
... 14 common frames omitted
What might be wrong?
In Boot 2.x, the bootJar and bootWar tasks are responsible for packaging the application.
The bootJar task is responsible for creating the executable jar file. This is created automatically once the java plugin is applied.
In case the executable jar/war file is not generated run the below gradle task manually.
$./gradlew bootJar
Similarly, bootWar generates an executable war file and gets created once the war plugin is applied.
We can execute the bootWar task using:
$./gradlew bootWar
Note that for Spring Boot 2.x, we need to use Gradle 4.0 or later.
I created a project with all the sources you provided. Running "gradle build" from terminal, switching to /build/libs and then running "java -jar artifactname" works just fine.
Have you tried to clean and recompile? Which Version of Gradle are you using?
In spring boot you can directly create executable jar file by
springBoot {
executable = true
}
Please try
jar{
baseName = 'myapp'
version = 'version'
}
It will create jar with name myapp-version.jar
Do ./myapp-version.jar from command line.it will execute
Refer following link for more info. https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
I just recently tried a Spring boot application with 2.1.4.Release with Gradle build.
I ran the following command from the directory in Windows CMD.
gradlew clean build
(upon required JDK8 installed in the system), I was able to see the JAR generated under,
<project-directory>/build/libs/<project-name-version.jar>
Hope this helps though older question.
Reference:
My two cents.
When using spring-boot if you want to customize the MANIFEST.MF file, you need to set the bootJar task, it won't work on the default jar task.
bootJar {
manifest {
attributes 'Start-Class': 'com.baeldung.DemoApplication'
}
}
https://www.baeldung.com/spring-boot-main-class
If you're trying to make your .jar file executable, for use such as in a systemd service. You'll have to edit the bootJar task and enable launchScript.
build.gradle
bootJar {
launchScript()
}
or with Gradle Kotlin DSL build.gradle.kts
tasks {
bootJar {
launchScript()
}
}
You should now be able to run your project's .jar file as an executable.

NoClassDefFoundError in EXE for JavaFX application built with gradle and launch4j

I'm trying to build a JavaFX exe using a pipeline on bitbucket with Gradle and the Launch4j plugin. It successfully builds, but when I download it and try to run the exe I get this error: java.lang.NoClassDefFoundError: javaFx/application/application.
I tried the build from IntelliJ using the same gradle file and it works Okay. I say Okay because in the launch4j folder there is the exe along with a lib Dir, which has the jar files. Ideally, would like all of the jar files in the exe (It doesn't run without the lib Dir). Anyhoo, with the build from the pipeline, it looks like it can't find the javafx jar. I did create another class called Launcher that doesn't extend Application but does call my main class, that does extend Application. I heard there were issues trying to import the JavaFx if it extends Application so I created another entry point into the application. With that said, here is most of my gradle file:
plugins {
id 'java'
id 'idea'
id "com.google.protobuf" version '0.8.19'
id 'org.openjfx.javafxplugin' version '0.0.13'
id 'org.beryx.jlink' version '2.24.1'
id 'checkstyle'
id 'pmd'
id 'edu.sc.seis.launch4j' version '2.5.3'
}
application {
mainModule = 'com.verlodesktopapplication'
mainClass = 'com.verlodesktopapplication.Launcher'
}
javafx {
version = '17.0.2'
modules = ['javafx.controls', 'javafx.fxml', 'javafx.swing']
}
jlinkZip {
group = 'distribution'
}
jar {
manifest {
attributes(
'Main-Class': 'com.verlodesktopapplication.Launcher'
)
}
}
launch4j {
headerType="gui"
mainClassName='com.verlodesktopapplication.Launcher'
icon = "${projectDir}/icons/testicon.ico"
outfile="VDA.exe"
jreRuntimeBits="64"
jar="${buildDir}/libs/verlo-desktop-application-1.0.jar"
}
Here is what the manifest looks like:
Manifest-Version: 1.0
Main-Class: com.verlodesktopapplication.Launcher
Shouldn't the manifest include all of the jars? Any idea how to do that?

Gradle subproject ordering and generate jar (spring boot + angular)

I am a Gradle newby. I have the following project setup:
Root
core: contains spring boot 2 application
ui: angular 5 front-end application
Goal: I want to run 'gradle build' from my root folder and it should contain one jar file which includes the Angular app.
I got the 'ui' covered:
apply plugin: "com.moowork.node"
buildscript {
repositories globalRepositories
dependencies {
classpath "com.moowork.gradle:gradle-node-plugin:1.2.0"
}
}
node {
// based on current version of Angular 5
version = "8.9.1"
npmVersion = "5.6.0"
download = true
}
task buildAngular(type: NpmTask) {
args = ['run', 'build']
}
buildAngular.dependsOn(npm_install)
build.dependsOn(buildAngular)
The above gradle definition will build and generate the Angular files in the static backend core application.
The 'core' gradle build file looks like this (I excluded the dependencies), nothing special:
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'xxx.xxxxxx'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
targetCompatibility = 1.8
buildscript {
repositories globalRepositories
ext {
springBootVersion = '2.0.0.M7'
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
jar {
baseName = 'spring-boot-angular'
version = '1.0.0'
}
How can I make this possible? I want the following actions to be triggered when I run 'gradle build' from my root project:
run first 'gradle build' in ui
then second run 'gradle build' in core
use the generated jar file from 'core' as the end result
I can't stand the groovy like syntax, can't wait for Gradle Kotlin DSL to mature :P
Hope somebody can help. I will open source this setup (together with Spring 5, Hibernate 5 and flyway) when I get this up and ready. Thanks in advance.
You need to include the result of the frontend (ui) buildAngular task inside the jar generated in the backend (core) build:
bootJar {
dependsOn ':ui:buildAngular'
into('BOOT-INF/classes/static') {
from "${project(':ui').projectDir}/dist"
}
}
The fact that the bootJar task now depends on the buildAngular task of the frontend will make gradle order them as needed.
You can browse this project of mine to have an example using basically the same setup (except it uses yarn instead of npm to resolve dependencies)
Answer of JB Nizet should work. You can also add the following in the root gradle file:
build.dependsOn("core:build").mustRunAfter("ui:build")
Above answer is in my opinion cleaner.

Defining multi-module dependency using custom configuration in Gradle does not trigger required tasks

I have two modules in my Gradle project:
ts containing single page app sources
edge containing Java sources which will serve said SPA
I have managed to integrate Yarn build with Gradle so that executing gradle :ts:assemble will produce single zip file with compiled js files and also including that archive in the final JAR via gradle :edge:processResources using custom configuration that expects zip files. Everything works fine if I just manually invoke gradle :ts:assemble :edge:processResources however if I try gradle :edge:processResources the build will fail immediately with File not found error. Somehow Gradle doesn't know that it should assemble ts project before processing resources of edge
ts/build.gradle
configurations {
create("default")
}
artifacts {
add("default", assemble) {
name = project.name
version = project.version
classifier = extension
}
}
//Yarn tasks omitted for brevity
edge/build.gradle
configurations {
bundle
}
dependencies {
bundle project(":ts")
//other dependencies
}
processResources {
configurations.bundle.files.each { bundle ->
from zipTree(bundle)
into "public"
}
}

Spring Boot war file works with embedded but not with standalone Tomcat

I want to create a war file from a Spring Boot application, which I can deploy to a standalone Tomcat container, not using the embedded one.
I can create the war file and run it on its own using "java -jar pdfjs-annotator.war" and it works fine.
I built the application using gradle bootRepackage (Using Gradle, Tomcat7, Java 1.7).
But when I deploy the war file to a standalone Tomcat and start it, the app seems to boot without errors according to the log, but I cannot access any of the resources nor do the controller urls work.
For example, my index.html is a static html page under src/main/resources/static/index.html, which I can usually call via localhost:8080/index.html, but when deployed to a standalone Tomcat, the page does not get delivered (it's then in the war file in WEB-INF/classes/static/index.html) through that same url. And also any kind of controller mapping don't seem to work. I am getting a 404 error instead.
build.gradle:
buildscript {
ext {
springBootVersion = '1.2.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("io.spring.gradle:dependency-management-plugin:0.5.0.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'
war {
baseName = 'pdfjs-annotator'
version = '1.0.0-SNAPSHOT'
}
allprojects {
apply plugin: 'java'
sourceCompatibility = 1.6
targetCompatibility = 1.6
}
repositories {
mavenCentral()
}
configurations {
providedRuntime
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-data-rest")
compile("org.springframework.boot:spring-boot-starter-web")
runtime("mysql:mysql-connector-java")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
testCompile("org.springframework.boot:spring-boot-starter-test")
compile ('org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final')
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
My main application class:
#EnableJpaRepositories
#SpringBootApplication
public class PdfAnnotator extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(PdfAnnotator.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PdfAnnotator.class);
}
}
When I look into the exploded war, I do see the following META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Start-Class: com.mypackage.pdfcomment.PdfAnnotator
Spring-Boot-Version: 1.2.3.RELEASE
Main-Class: org.springframework.boot.loader.WarLauncher
The gradle build process usually generated two war artifacts, one named .war and one named .war.original - the .war is the one that holds proper MANIFEST.MF entries and it's the one I used to deploy to the standalone Tomcat.
What's missing? I already checked other questions here on SO:
spring boot war without tomcat embedded
Deploying a WAR in tomcat
and also the Spring Boot docs, but could not find a hint of what's wrong.
* === Update === *
I installed a brand new Tomcat7, deployed the war file there, and everything's working fine. Seemed to be some issue with the Tomcat instance/configuration I had running. Not sure what exactly the issue was, but I won't bother to check it further since it's working fine now with the new Tomcat.
I had this exact problem. It was because my application was built with Java 1.8 but Tomcat was running with 1.7. Everything appeared to deploy properly and there were no errors. I simply got a 404 trying to hit my services which had otherwise been fine with the embedded tomcat server. Took me ages to figure it out but it was just a case of upgrading java on the Tomcat installation.
The project is actually setup correctly and it turned out that the problem was with the Tomcat instance I was running. Probably something wrong with the configuration or jars. The instance is in place already for a long time, maybe things got messed up over time.
Now with a brand new Tomcat7 instance installed, the war works just fine.

Resources