Skip to main content

Gradle : Next-gen build tool introduction

I've been recently reading about maven 3 and from a page to another I read a bit about gradle, and got interested in it, so I want to try it now and see how it feels and works in practice

so to get started you need to download gradle from here: http://www.gradle.org/downloads
then add the path to gradle bin directory to the PATH system variable and go to CMD/shell then run:

> gradle

if it worked and you got build successful let's move to setup our project structure.

a word about gradle first, is that it promises to keep the great conventions Maven provided but with the flexibility ANT  had since Maven can give you a hard time if you need to customize something.
it's a convention over configuration, yet flexible.

so back to the track, what I want to do in this project is to setup a full spring-mvc rest API server, with multiple tiers (projects) that contains DAOs, Business Entities, Services, and REST tier.

o---[ REST ] -- uses --> [Services] -- uses --> [DAOs] --- > (DB)
           |                                 |                              |
    [                          Business Entitiess                          ]

this is a simple enterprise architecture to provide loosely coupled  tiers, to simulate a real project structure to test what gradle has to offer here.

In maven I would go and create a parent project then add these projects as modules, but when I need to build a project I'll have to build every thing which takes a lot of time.

ok so in gradle we have 3 options to structure our build files [build.gradle]
1) Individual : each sub project has it's own build file
2) Unified : one build file in the master project to build all sub projects
3) Hybrid: a build file in the master project that contains common build configurations and build files in each sub project that are specific for each build file

the Hybrid in my opinion gives you the best of the two worlds so i'll use it here, the other two approaches will implicitly be implemented.

A. Setting up the project structure 

Now the directory structure of our project, i'll go to file system and create the following JSON tree:

master-proj {
build.gradle,
settings.gradle,
dao : { src :{ main : { java : {} , resources : {} } , test :{}} ,  build.gradle },
be : { source :{ code : { java : {} , res : {} }  ,  test :{} }, build.gradle },
bl : { src :{ main : { java : {} , resources : {} } , test :{}} ,  build.gradle },
rest :{ src :{ main : { java : {} , resources : {} } , test :{}} ,  build.gradle }
}

note: i'll be using git also in this tutorial to keep a reference for the code.

if you notice the 'be' src structure is different to test how easy it is to changed default project layout (src/main/java and src/main/resources) that follows maven conventions.

after creating this structure the content of build.gradle in the master project for now will only contain:
allProjects {
 apply plugin: 'java'
}
this tells gradle that all sub projects will use the java plugin without explicitly saying that in the sub projects build files

the contents of settings.gradle will be :
include 'dao', 'be', 'bl', 'rest' 

these are the names of the directories that contain the sub projects

navigate in cmd to master-proj directory and and run :
 > gradle build

what you will get is build directories inside each project like this:


Now let's go to be/build.gradle and add the following segment :

apply plugin: 'java'
sourceSets {
    main {
        java {
            srcDir 'source/code/java'
        }
        resources {
            srcDir 'source/code/res'
        }
    }
}
This will tell gradle java plugin where to find our source code, i'll leave test directory for later.

add the following class in  be/source/code/java folder (don't forget to add the directories for the package) :

package com.blabadi.gradle.be;
public class Person {
}
and in the be/source/code/res folder add an empty file call it : be.properties
 navigate to master-proj/be and run :

>gradle build
 go to master-proj\be\build, you will find more directories : (classes, dependency-cahce, resources)
open the compiler jar in lib to see it's contents:



so now we have something we can work with as start point.

now we want to import this to eclipse but we need to add eclipse config files ( .classpath, .project, .settings) gradle has a plugin for that and we can include it like the java plugin under our master project build file :

allprojects {
  apply plugin: 'java'
  apply plugin: 'eclipse' 
}

now while you are in in master-proj dir , run : 

gradle eclipse

now all your projects can be imported to eclipse to work with easier.

let's go ahead and do that:




it also figured out about our custom source directory in project 'be'



B. Dependency management

in our work we usually need the following types of dependencies:

1- 3rd party dependencies in runtime (spring jars)
2- 3rd party dependencies in compile time only ( javax.servlets )
3- 3rd party testing dependencies (junit)
4- our own frameworks jars / generated web services client jars
5- projects dependencies

some of these are on maven repositories and others aren't, gradle allows us to do everything from importing a jar from file system like ant or use central maven repo or use our own maven repo if we have one, to test this let's plan to add the following dependencies:

for DAO project it will depend on :
- spring for Dependency injection
- hibernate for persistence
- business entities project

for BL :
- spring for Dependency injection
- our own utility library [local jar]
- business entities project
- Junit4 for testing

for REST :
- spring for Dependency injection & spring web
- BL project
- BE project

BE project won't have any dependencies for now.

easiest way to get spring dependencies is to use maven central repo, and since spring core is common between more than one project let's configure this in one place.

In the master project build file i'll add this :

allprojects {
  apply plugin: 'java'
  apply plugin: 'eclipse'

  repositories {    mavenCentral()  } 
}


[':bl', ':dao', ':rest'].each { 
pn -> project(pn) {  dependencies 
      { compile 'org.springframework:spring-context:4.1.0.RELEASE'  }  
   }
}

this tells gradle to user maven central repo to download the spring context jar (and it's dependencies)
and for each of the three projects add the spring-context jar as a compile time dependency

now run gradle eclipse in the master project, it will download the spring jars then update the class path for the three projects to reference the spring-context jar from the local

for the REST project it needs spring-webmvc.jar to expose our rest api's so in rest/build.gradle
add this :

dependencies {
compile 'org.springframework:spring-webmvc:4.1.0.RELEASE'
}

and run gradle eclipse to update classpath file

for the dao we will need hibernate jars so add this to its build.gradle:

dependencies {
compile 'org.hibernate:hibernate-core:4.3.6.Final'
}

now let's convert REST project to a WAR instead of JAR, to do that add the following plugin at the top of its build file :

apply plugin: 'war'

and add the following dependency :

dependencies {
compile 'org.springframework:spring-webmvc:4.1.0.RELEASE'
compile project(':bl')}

this is how we add a dependency  between the projects

now also add the following to complete the dependency between our projects :
in master-project/build.gradle :

[':bl', ':dao', ':rest'].each { pn ->
project(pn) {
dependencies {
compile 'org.springframework:spring-context:4.1.0.RELEASE'
compile project(':be') }
}
}

and in the bl/build.gradle:

dependencies {
compile project(':dao')
}
to add a local jar (not 3rd party and not in a Maven repo) we can do the following:
assume we want our library in the root project in folder called libs, for example I have put xpp3.jar in that folder and I want to reference it inside my projects

1- add flat directory repository :
repositories {
mavenCentral( )
flatDir {
    dirs "$rootDir/libs"
    }
}
$rootDir is a DSL variable that points to the root project base directory.

and in the dependencies add :

compile 'xpp3:xpp3:1.1.4'

it will now be resolved to the libs directory without the need to complex configuration like maven.

another way to do this is to use the files( ) method without declaring a flatDir repository:

compile files('../libs/commons-fileupload-1.3.1.jar')  //[assuming we are in a subproject depedency ]


see the master-proj build.gradle :




ok now the final step is prepare our application for deployment, I have took some time to add the required spring configurations and wire everything together I added few dependencies for junit in the master project build.gradle:

[':bl', ':dao', ':rest'].each { pn ->
project(pn) {
dependencies {
compile 'org.springframework:spring-context:4.1.0.RELEASE'
compile project(':be')
testCompile group: 'junit', name: 'junit', version: '4.+'
testCompile 'org.springframework:spring-test:4.1.0.RELEASE'
}
}
}
notice the scope of junit is for test compile only so it won't be packaged with the final war.

to deploy the project run :

gradle build and you will get a war from the rest project, drop that in your server and you're good to go

visit the final project setup here on git hub:
https://github.com/blabadi/hello-world/tree/dev/test-gradle/master-proj


Summary :
Gradle is simple, flexible and really powerful, the only thing took time is boilerplate required for the initial structure which I did manually on purpose to understand the very basics of gradle.

Gradle yet has more interesting features, and what I only covered is mainly the java plugin and maven in gradle, the possibilities are endless, since you are using groovy scripting for the build domain (DSL) which provides easy to change conventions.


refs :
1- http://www.gradle.org/docs/current/userguide/
2- http://spring.io/guides/gs/gradle/

Comments

Popular posts from this blog

Android RecyclerView - Adding Empty View

So RecyclerView was introduced to replace List view and it's optimized to reuse existing views and so it's faster and more efficient as stated in the documentation:

https://developer.android.com/training/material/lists-cards.html

While using it, I faced the issue of missing a useful functionality that is implemented in ListView.
that feature is setting an empty view in case there was no records.

In ListView it was as simple as this

View emptyView = findViewById(R.id.mylist_empty_view);
ListView  myList = ....
myList.setEmptyView(emptyView);

but this method doesn't exist for recycler view so we need a work around until android team fixes this.


and here are the screen shots of both list view and recycler view fix

List view :

Recycler view :



here is how I fixed it:



here is the content of empty_view, it can be anything.



Enjoy.

Creating your own OAuth2 server and clients using spring security - part 1

In this series of posts, I'll try to put together a simple working example on how to create your own OAuth2 server.

if you want to know more on OAuth2 and when to use it as authentication and authorization protocol then you can search about it on google and i'll put some URLs later.

Now I assume you are familiar with java web applications using Spring and maven.

to get started we need to create the server side with all dependencies required and i'll list them here, i'll use maven 2 to ease downloading dependencies for us.


Steps:

1- Create new maven project with arch type webapp:



2- Add the required depenedencies for spring, spring security, spring-oauth2, hibernate & other libraries (required for this tutorial only you can use other libraries if you like)

https://gist.github.com/anonymous/d33a31ddc3ba84375cf3

3- I used hibernate to automate the creation of the schema required by spring OAuth2 to manage tokens (it's required to have schema created in db if you a…

Android - Multiple themes for one application

Sometimes you want to have multiple themes for your app
one strong example is having the ability to switch between dark and light themes because during night, a white bright screen can really be annoying for users eyes

Android will do most of the work for you but it may be required to change icons between themes to fit colors
In this blog I'll show a simple app with both dark and light themes and how to change icons without having to do that from code and keep things clean and centralized.
first of all let's create our activity, it will look something like this :


In /rest/values/styles.xml, we inherit Theme.AppCompat
 <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="Theme.AppCompat">
        <!--
            Theme customizations available in newer API levels can go in
            res/values…