I would like to use Gradle to build a java project and I would like to structure it as follows.
Core Library
Web App (war plugin)
Server (application plugin)
Client
Client War (war plugin)
The Web App, Server, and Client all depend on core. The Server depends on the Web App because it is going to serve it as the admin page using embedded Jetty. The Client War depends on the Client. The Client War is to be deployed to a web server for distribution of the client as a web start application.
What I would like to know is how can I tell the Server project that it depends on the Web App and needs to copy it into the proper location in it's distribution structure. I would also like to know how I can tell the Client War project to depend on the Client project and to copy the Client jar and all of it's dependencies into the proper location to build the war archive.
I plan to use the application plugin for the Server so under <root>/src/dist there will be a webapp directory where the one or possibly more web apps will reside. It is expected that the files contained in the webapp directory will be war files.
This is a new project so it can follow the standard build conventions of Gradle and the project layout expected by Gradle.
Ideally at some point the Client artifacts will be published to an internal Artifactory or Sonatype Nexus repository so that the Client War can be built with version support.
So far I have found the following resources.
Packaging JNLP Applications in a Web Archive
Generating Java Web Start files using Gradle
I believe I figured out the Web App dependency part of my problem. The Client War is a lost cause for now.
Server build.gradle
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'application'
targetCompatibility = 1.8
sourceCompatibility = 1.8
version = '0.0.1-SNAPSHOT'
group = 'com.s2d'
mainClassName = 'com.simonsoftwaredesign.example.echo.server.EchoServerApp'
repositories {
mavenCentral()
}
configurations {
webContainer
}
dependencies {
compile project(':echo-core')
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.7.v20160115'
compile group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.3.7.v20160115'
webContainer project(path: ':echo-admin', configuration: 'warApp')
}
task copyWebApps(dependsOn: configurations.webContainer, type: Copy) {
from { configurations.webContainer.collect { it } }
// I don't like how this is hard coded
// but I am not sure how to fix it
into 'src/main/dist/webapp'
}
installDist.dependsOn copyWebApps
distZip.dependsOn copyWebApps
distTar.dependsOn copyWebApps
Web App build.gradle
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'war'
targetCompatibility = 1.8
sourceCompatibility = 1.8
version = '0.0.1-SNAPSHOT'
group = 'com.s2d'
configurations {
warApp
}
repositories {
mavenCentral()
}
dependencies {
providedCompile project(':echo-core')
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
artifacts {
warApp war
}
Gradle projects depending on artifacts created by sibling projects
Related
Spring boot makes it really easy to setup a simple app.
But it takes me longer to actually get a jar file which I can upload to a remote server.
I am using IntelliJ, no command line, and I use gradle. The application is running somehow out of Intellij. But where are the created files? Where is my jar from Bootjar?
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
bootJar {
baseName = 'gs-spring-boot'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
testCompile("org.springframework.boot:spring-boot-starter-test")
// add spring data repos
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.postgresql:postgresql:42.2.4")
// REST interface
compile("org.springframework.boot:spring-boot-starter-data-rest")
// Security
compile("org.springframework.boot:spring-boot-starter-security")
}
Update: Added a picture of the project structure:
Update 2: Folder structure:
There will not be a jar created if you are just running this in your IDE. In order to do that, you need to run the gradle build (in your case) either from your IDE or the command line to get it to build it into a jar.
From the command line, go to your project directory and type this:
./gradlew build
This executes the gradle wrapper, which should download everything you need to run the build, and then executes the build.
You will then find your jar in build/lib
build/libs (if you've ran build to build the jar file)
I am learning Spring MVC and trying to use it together with Gradle and Gretty plugin. I have successfully created a "Hello World" project, however I am not able to use hot deployment with Gretty, despite setting the managedClassReload=true. I run the application by using appRun gretty task from IntelliJ. My build.gradle is as follows:
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'war'
apply from: 'https://raw.github.com/gretty-gradle-plugin/gretty/master/pluginScripts/gretty.plugin'
group = 'lukeg'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
mainClassName = 'lukeg.LearnApplication'
repositories {
mavenCentral()
maven {
url 'https://repo.spring.io/libs-snapshot'
}
}
dependencies {
compileOnly('org.projectlombok:lombok:+')
compile('org.springframework:spring-webmvc:4.3.17.RELEASE')
compile("org.aspectj:aspectjweaver:1.8.11")
compile('org.springframework:spring-context:4.3.18.BUILD-SNAPSHOT')
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
gretty {
httpPort = 8080
contextPath = '/'
servletContainer = 'tomcat9'
//reloadOnClassChange=true
managedClassReload=true
loggingLevel='DEBUG'
}
It does not matter whether I use tomcat9 or jetty9 for servlet container: the logs do not show that the changes to source files in project are detected by Gretty.
Interesingly enough, when I comment out the managedClassReload=true line and uncomment reloadOnClassChange=true the changes to source files are detected and the project is automatically reloaded.
What can be the cause for gretty's hot deployment not working? Does springloaded not work together with Spring MVC?
First of all, there is no need to depend on the plugin script you are gathering from github since org.gretty is available in the official Gradle plugin repository for some time already:
plugins {
id "org.gretty" version "2.1.0"
}
Since you are running your app inplace using appRun, your changes will not be reloaded.
You have to run you application as war, using appRunWar.
This is not mentioned in the documentation. But in the Gretty source code.
You can check the Gretty code which causing your issue in the BaseScannerManager:
if(wconfig.reloadOnClassChange)
{
if(managedClassReload)
{
if(wconfig.inplace) // <-- your problem, you are running inplace
{
log.info 'file {} is in managed output of {}, servlet-container will not be restarted', f, wconfig.projectPath
}
else
{
log.info 'file {} is in output of {}, but it runs as WAR, servlet-container will be restarted', f, wconfig.projectPath
webAppConfigsToRestart.add(wconfig)
}
}
else
{
log.info 'file {} is in output of {}, servlet-container will be restarted', f, wconfig.projectPath
webAppConfigsToRestart.add(wconfig)
}
}
With Gradle it is possible to build a .war archive from a Java project. I've always been using a project setup as follows to pack some JavaScript SPA (Angular, vue.js...) frontend and a Spring Boot backend together into one .war file:
Directory structure
/
build.gradle
settings.gradle
/server
/build/libs/server.war
/src ...
build.gradle
/client
/dist/** <== This is where e.g. webpack puts the SPA build
build.gradle
/src ...
Topmost settings.gradle
include 'client', 'server'
'server' build.gradle
plugins {
id 'java'
id 'idea'
id 'org.springframework.boot' version '2.0.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.5.RELEASE'
id 'war'
}
repositories {
mavenCentral()
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
dependencies {
compileOnly('org.projectlombok:lombok:1.16.16')
annotationProcessor('org.projectlombok:lombok:1.16.16')
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-web')
runtime('org.springframework.boot:spring-boot-devtools')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
war.dependsOn(':client:build')
war {
from '../client/dist/'
}
'client' build.gradle
plugins {
id 'com.nickcharles.yarn-run' version '1.0.1'
}
This is working just fine. But I can't imagine that this is the cleanest solution for that kind of task.
Backdraws of my solution are:
Final result of build is stored in build/libs of the :server subproject, not in the root project where it semantically belongs
The built client must be refered to in a static way.
How would a clean solution/the contents of the topmost build.gradle file look like, in order to avoid those backdraws?
At this moment I have a build.gradle file that successfuly compiles and tests (using JUnit4) a very very simple java project.
My next step is to add JSF2 support (in order to have a web JSF2 application) to this build. The idea is to host the application in my local JBoss 7.1 container. Now things became a little fuzzy to me.
What I did was to add JSF2 support to my buid by adding some dependencies, so the dependencies block is like this now:
dependencies {
compile 'org.jboss.weld.se:weld-se-core:'+weldVersion
compile 'br.gov.frameworkdemoiselle:demoiselle-core:'+demoiselleVersion
compile 'br.gov.frameworkdemoiselle:demoiselle-jsf:'+demoiselleVersion
runtime 'javax.servlet:javax.servlet-api:3.1.0'
runtime 'javax.enterprise:cdi-api:1.0-SP1'
runtime 'org.jboss.weld.servlet:weld-servlet:'+weldVersion
runtime 'com.sun.faces:jsf-api:2.2.8-02'
runtime 'org.slf4j:slf4j-log4j12:1.7.7'
testCompile 'junit:junit:4.11'
testCompile 'org.jboss.arquillian.junit:arquillian-junit-container:'+arquillianVersion
testCompile 'br.gov.frameworkdemoiselle.component:demoiselle-junit:2.3.1'
}
First strange thing that I noticed is that after refreshing the project with Gradle (by using Gradle > Refresh All menu), JBoss is unable to see it. I noticed that (it seems) Gradle disabled the use of facets in the project. If I manually activate facets and set the runtime to JBoss 7.1, then I'll be able to add it to JBoss (but I would prefer not to have to do it manually anymore).
After adding it to JBoss I can run the server, and the log says the module corresponding to my web application was correctly loaded by JBoss, however when I type it's url in a browser, the server responds with HTTP status 404.
In src/main/webapp I have the simple index.html file (shown below), so what I expected was just to see it's content in the browser, but that does not happen.
<html>
<body>
<h1>Hello world!</h1>
</body>
</html>
What am I missing?
After some study I finally understood that things were much simpler. That I was missing to understand is that I was using the wrong Gradle plug-in. I had to replace eclipse plug-in by eclipse-wtp and then specify which facets and runtime I wanted to use in my application.
The final build.gradle file is below:
apply plugin: 'java'
apply plugin: 'eclipse-wtp' // The correct plug-in!
apply plugin: 'application'
apply plugin: 'war'
sourceCompatibility = 1.7
targetCompatibility = 1.7
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
def hibernateVersion = "4.3.7.Final"
def weldVersion = "1.1.27.Final"//"2.2.7.Final" Demoiselle 2.4.1 não é compatível com Weld 2
def demoiselleVersion = "2.4.1"
def arquillianVersion = "1.1.5.Final"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
runtime 'javax.servlet:javax.servlet-api:3.1.0'
runtime 'javax.enterprise:cdi-api:1.0-SP1'
runtime 'org.jboss:jandex:1.2.2.Final'
}
eclipse {
wtp {
facet {
facet name: "java", version: "1.7" // Java version
facet name: "jst.web", version: "3.0" // Dynamic Web Application
facet name: "jst.jsf", version: "2.2" // Java Server Faces
facet name: "wst.jsdt.web", version: "1.0" // JavaScript
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.2.1'
}
I hope this may help some other people!
Im trying to create a web application using Gradle. The front end UI will be built with Angular.js and the backend should be Java. When I say backend, I mean a Java / Spring based API that will be queried using Ajax from Angular.js.
So basically what Im trying to do is to get any URL's that start with mysite.com/api/... should be routed to the src/com/veight/client files, or in other words to the Java backend. And then any other URLs such as mysite.com/login should be handled by the JavaScript / Angular.js front end.
I have the JavaScript / Angular.js routing working for the front end using the following build.gradle file. How should I go about sending routes that match mysite.com/api/... to the Java / Spring back end?
Thank you for the help!
Note: I know that Java Spring naturally does this routing where it sends certain routes mysite.com/home to one folder and other routes mysite.com/api/... are handled buy a xml file. But I think its possible to handle this in the build.gradle file. So I was hoping to prove / disprove that theory.
File Structure
.gradle
.settings
build
gradle
src
com
veight
client
WebContent
Heres my build.gradle:
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:1.2.4' // Gradle Tomcat Plugin
classpath 'com.eriwen:gradle-css-plugin:1.11.1'
classpath 'com.eriwen:gradle-js-plugin:1.12.0'
}
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'tomcat'
apply plugin: 'eclipse-wtp'
apply plugin: 'js'
apply plugin: 'css'
sourceCompatibility = 1.7
version = '1.0'
task wrapper(type: Wrapper) {
gradleVersion = '2.0'
}
repositories {
mavenCentral() // Allow access to the Maven Centeral Repo
}
dependencies {
def tomcatVersion = '7.0.54'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
}
}
sourceSets {
main {
java {
srcDirs 'src'
}
}
}
// End: Java Plugin Configuration
// Start: Tomcat Plugin Configuration
tomcatRun {
httpPort = 8080
stopPort = 8081
URIEncoding = 'utf-8'
webAppSourceDirectory = file('WebContent')
}
eclipse {
wtp {
component {
contextPath = '/'
deployName = 'client'
}
}
}