Engineering Full Stack Apps with Java and JavaScript
We will use Gradle build tool in this example for creating your first spring program. All other notes in this section will be using Maven in general. You can refer to our notes section on Gradle for learning more about Gradle and translating the maven dependencies I specify. If you go to the Spring Framework page, you can see dependency details for Maven or Gradle builds.
PS: If you are not familiar with Gradle, or don’t want to build your application using Gradle, you can skip this note, as there is an alternate note that uses Maven, that also specifies how to directly use Spring dependency jars.
You should have downloaded Gradle and added it to path following http://javajee.com/getting-started-with-gradle-hello-world-build-in-windows-os.
You should also have some idea about Gradle. You can read about Gradle @ http://javajee.com/build-tools-for-java-applications.
An active internet connection is required for Gradle to download dependencies when required. If you don’t have an internet connection, but have the jars downloaded, follow the flatDir approach in the end to compile the source.
We will create a simple class, JJWriter.java, with a single method write. This class is a regular pojo (plain old java object) class with no spring specific code. We will create a simple spring config file, spring.xml with a simple bean definition to configure the class as a bean; and then test all these together using a simple test class, JJWriterMain.java. Note that the name of the config file can be anything.
JJWriter.java
The JJWriter.java has a single method write:
package com.javajee.spring;
public class JJWriter {
public void write() {
System.out.println("Default Writer");
}
}
The spring config xml spring.xml has a bean definition for JJFileWriter:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="jjwriter" class="com.javajee.spring.JJWriter">
</bean>
</beans>
We will give an id to each of our bean definitions so that we can refer to it with that name from our code.
You will need this file in the classpath while executing the application (while running gradle run). For the example, place it alongside com folder under build\classes\main after building (after gradle build).
Note: Make sure that you are using the latest xsd. You can find the xsds within your downloaded distribution under schemas folder.
The test class JJWriterMain will ask spring to create and return us an object of the class type defined using the class attribute of the bean using the bean id:
package com.javajee.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JJWriterMain {
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("spring.xml");
JJWriter writer = (JJWriter)context.getBean("jjwriter");
writer.write();
}
}
Select an empty folder for this exercise.
Create a file called build.gradle with below contents:
apply plugin: 'java'
apply plugin:'application'
mainClassName = "com.javajee.spring.JJWriterMain"
dependencies {
compile 'org.springframework:spring-context:4.0.5.RELEASE'
runtime 'org.springframework:spring-context:4.0.5.RELEASE'
}
repositories {
mavenCentral()
}
The apply plugin: 'java' applies the java plugin, and that is all needed to compile a Java file following the Gradle default conventions. For more details, please refer to http://javajee.com/building-first-java-program-with-gradle-from-command-line.
apply plugin:'application' and mainClassName property are needed to run the application, for compiling it is not needed. The mainClassName property specify the main class that needs to be run
I got the dependencies closure that needs to be used from the Spring Framework page http://projects.spring.io/spring-framework after selecting Gradle as the build tool.
You need to connect to a repository to get dependencies. We are connecting to Maven Central Repository. For details on Gradle dependency management, refer to http://javajee.com/using-gradle-with-maven-part-2-dependencies-and-repositories.
Gradle provides some default conventions to reduce the code written and we will use those default conventions in this example. Note that we haven’t specified much details in the build file.
Place your source code maintaining the package folder structure (e.g. com\javajee\spring) under Gradle required folder structure src\main\java in the selected folder for this excercise. Final folder structure to place above java source files will be src\main\java\com\javajee\spring.
Compile the code by running ‘gradle build’ from command prompt (from the selected folder) as:
gradle build
You should get the output with BUILD SUCCESSFUL.
You can see that additional folders - build and .gradle - are created by Gradle. The folder build\classes\main will have the compiled class files in correct package folder structure.
Before calling run, you need to copy the spring.xml to build\classes\main. You can now run the application as:
gradle run
You will see the output with:
Default Writer
To execute the class JJWriterMain outside gradle you will need all the dependency jars in the classpath while executing, which are spring-core-x.x.x.RELEASE.jar, spring-beans-x.x.x.RELEASE.jar, spring-context-x.x.x.RELEASE.jar, spring-expression-x.x.x.RELEASE.jar and commons-logging-x.x.x.jar. These are expected to be there in the runtime environment.
You can add the below code to the build.gradle file if you want to package the contents of dependent jars also to the final jar file which is created under build\libs folder:
jar {
from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
In case you have downloaded the jars and put in a folder, you can specify the flat directory, instead of a repository, to resolve dependencies using the flatDir configuration of the repository:
repositories {
flatDir name: 'localDiskRepo', dirs: 'lib1'
}
If there are more directories, you can use the syntax:
repositories {
flatDir dirs: ['lib1', 'lib2']
}
Here lib1 and lib2 directories should be in the same level as build.gradle file. You can also specify absolute or relative paths (with proper escaping if necessary):
flatDir dirs: ['D:\\GRADLE\\lib1', '../GRADLE/lib2']
Another thing to note here is that, when you specify flatDir to specify a flat directory, you need to specify all required dependencies, unlike before. So for compiling a basic Spring code, instead of specifying only compile 'org.springframework:spring-context:4.0.5.RELEASE', you need to specify as:
dependencies {
compile 'org.springframework:spring-context:4.0.5.RELEASE'
compile 'org.springframework:spring-core:4.0.5.RELEASE'
compile 'org.springframework:spring-beans:4.0.5.RELEASE'
compile 'org.springframework:spring-expression:4.0.5.RELEASE'
compile 'org.apache.commons.logging:commons-logging:1.1.3'
}
I have placed all Spring jars in lib1 and commons logging jar in lib2. Gradle will assume the jar file name from the name and version part above (E.g. spring-core-4.0.5.RELEASE.jar), and search the folders specified as flatDirs. For compiling code, only first 3 jars are require. However to execute (run), you will need all 5 jars.
The WAR plugin can be used to package the deployable into a WAR file and we can also package any dependent jars in the WAR.
The Spring Tool Suite (STS) provides good support for working with Spring and Gradle in eclipse. There is also an eclipse plugin for Gradle that will generate all required files so that a Gradle project can be imported into eclipse.