Posts Tagged Dependencies

Updating and Maintaining Gradle Project Dependencies

As a DevOps Consultant, I often encounter codebases that have not been properly kept up-to-date. Likewise, I’ve authored many open-source projects on GitHub, which I use for training, presentations, and articles. Those projects often sit dormant for months at a time, #myabandonware.

Poorly maintained and dormant projects often become brittle or break, as their dependencies and indirect dependencies continue to be updated. However, blindly updating project dependencies is often the quickest way to break, or further break an application. Ask me, I’ve given in to temptation and broken my fair share of applications as a result. Nonetheless, it is helpful to be able to quickly analyze a project’s dependencies and discover available updates. Defects, performance issues, and most importantly, security vulnerabilities, are often fixed with dependency updates.

For Node.js projects, I prefer David to discover dependency updates. I have other favorites for Ruby, .NET, and Python, including OWASP Dependency-Check, great for vulnerabilities. In a similar vein, for Gradle-based Java Spring projects, I recently discovered Ben Manes’ Gradle Versions Plugin, gradle-versions-plugin. The plugin is described as a ‘Gradle plugin to discover dependency updates’. The plugin’s GitHub project has over 1,350 stars! According to the plugin project’s README file, this plugin is similar to the Versions Maven Plugin. The project further indicates there are similar Gradle plugins available, including gradle-use-latest-versionsgradle-libraries-plugin, and gradle-update-notifier.

To try the Gradle Versions Plugin, I chose a recent Gradle-based Java Spring Boot API project. I added the plugin to the gradle.build file with a single line of code.

plugins {
  id 'com.github.ben-manes.versions' version '0.17.0'
}

By executing the single Gradle task, dependencyUpdates, the plugin generates a report detailing the status of all project’s dependencies, including plugins. The plugin includes a revision task property, which controls the resolution strategy of determining what constitutes the latest version of a dependency. The property supports three strategies: release, milestone (default), and integration (i.e. SNAPSHOT), which are detailed in the plugin project’s README file.

As expected, the plugin will properly resolve any variables. Using a variable is an efficient practice for setting the Spring Boot versions for multiple dependencies (i.e. springBootVersion).

ext {
    springBootVersion = '2.0.1.RELEASE'
}

dependencies {
    compile('com.h2database:h2:1.4.197')
    compile("io.springfox:springfox-swagger-ui:2.8.0")
    compile("io.springfox:springfox-swagger2:2.8.0")
    compile("org.liquibase:liquibase-core:3.5.5")
    compile("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2")
    compile("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-data-rest:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-hateoas:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
    compileOnly('org.projectlombok:lombok:1.16.20')
    runtime("org.postgresql:postgresql:42.2.2")
    testCompile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}")
}

My first run, using the default revision level, resulted in the following output. The report indicated three of my project’s dependencies were slightly out of date:

> Configure project :
Inferred project: spring-postgresql-demo, version: 4.3.0-dev.2.uncommitted+929c56e

> Task :dependencyUpdates
Failed to resolve ::apiElements
Failed to resolve ::implementation
Failed to resolve ::runtimeElements
Failed to resolve ::runtimeOnly
Failed to resolve ::testImplementation
Failed to resolve ::testRuntimeOnly

------------------------------------------------------------
: Project Dependency Updates (report to plain text file)
------------------------------------------------------------

The following dependencies are using the latest milestone version:
- com.github.ben-manes.versions:com.github.ben-manes.versions.gradle.plugin:0.17.0
- com.netflix.nebula:gradle-ospackage-plugin:4.9.0-rc.1
- com.h2database:h2:1.4.197
- io.spring.dependency-management:io.spring.dependency-management.gradle.plugin:1.0.5.RELEASE
- org.projectlombok:lombok:1.16.20
- com.netflix.nebula:nebula-release-plugin:6.3.3
- org.sonarqube:org.sonarqube.gradle.plugin:2.6.2
- org.springframework.boot:org.springframework.boot.gradle.plugin:2.0.1.RELEASE
- org.postgresql:postgresql:42.2.2
- org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2
- org.springframework.boot:spring-boot-starter-actuator:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-data-jpa:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-data-rest:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-hateoas:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-test:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-web:2.0.1.RELEASE

The following dependencies have later milestone versions:
- org.liquibase:liquibase-core [3.5.5 -> 3.6.1]
- io.springfox:springfox-swagger-ui [2.8.0 -> 2.9.0]
- io.springfox:springfox-swagger2 [2.8.0 -> 2.9.0]

Generated report file build/dependencyUpdates/report.txt

After reading the release notes for the three available updates, and confident I had sufficient unit, smoke, and integration tests to validate any project changes, I manually updated the dependencies. Re-running the Gradle task generated the following abridged output.

------------------------------------------------------------
: Project Dependency Updates (report to plain text file)
------------------------------------------------------------

The following dependencies are using the latest milestone version:
- com.github.ben-manes.versions:com.github.ben-manes.versions.gradle.plugin:0.17.0
- com.netflix.nebula:gradle-ospackage-plugin:4.9.0-rc.1
- com.h2database:h2:1.4.197
- io.spring.dependency-management:io.spring.dependency-management.gradle.plugin:1.0.5.RELEASE
- org.liquibase:liquibase-core:3.6.1
- org.projectlombok:lombok:1.16.20
- com.netflix.nebula:nebula-release-plugin:6.3.3
- org.sonarqube:org.sonarqube.gradle.plugin:2.6.2
- org.springframework.boot:org.springframework.boot.gradle.plugin:2.0.1.RELEASE
- org.postgresql:postgresql:42.2.2
- org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2
- org.springframework.boot:spring-boot-starter-actuator:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-data-jpa:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-data-rest:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-hateoas:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-test:2.0.1.RELEASE
- org.springframework.boot:spring-boot-starter-web:2.0.1.RELEASE
- io.springfox:springfox-swagger-ui:2.9.0
- io.springfox:springfox-swagger2:2.9.0

Generated report file build/dependencyUpdates/report.txt

BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed

After running a series of automated unit, smoke, and integration tests, to confirm no conflicts with the updates, I committed my changes to GitHub. The Gradle Versions Plugin is a simple and effective solution to Gradle dependency management.

All opinions expressed in this post are my own, and not necessarily the views of my current or past employers, or their clients.

Gradle logo courtesy Gradle.org, © Gradle Inc. 

, , , , , , ,

Leave a comment

Software Delivery: Evaluating Risk within the Enterprise

As software evolves from less-complex applications to enterprise platforms, how does increasing complexity raise the potential risk of delivering unreliable software?
  

Cover Drawing

 Introduction

Many vendor whitepapers, industry publications, blog posts, podcasts, and e-books, extol the best practices in software development and delivery. Best practices include industry-standard concepts, such as Agile, DevOps, TTD, continuous integration, and continuous delivery. Generally, these best practices all strive to improve the process of delivering software enhancements and bug fixes to customers.

Rapidly, reliably and repeatedly push out enhancements and bug fixes to customers at low risk and with minimal manual overhead. – Wikipedia

Most learning resources present one of two idealized environments, ‘applications as islands’ and ‘utopian enterprise’. I am also often guilty of tailoring my own materials to one of these two idealized environments. Neither ‘applications as islands’ or ‘utopian enterprise’, best model the typical enterprise software environments in which many of us work.

Applications as Islands

The ‘applications as islands’ environment is one of completely isolated application stacks. These types of environments have multiple application stacks, consisting of web, mobile, and desktop components, services, data sources, utilities and scripts, messaging and reporting components, and so forth. Unrealistically, each application stack is completely isolated from the other application stacks within the same environment.

The Utopian Enterprise

The ‘utopian enterprise’ environments have multiple application stacks with multiple shared components. However, they are built, unrealistically, using consistent and modern architectural patterns and compatible technology stacks. They are designed from the ground up to be compartmentalized, scalable, and highly risk-tolerant to changes. They often avoid the challenges of monolithic legacy applications. The closest things in the real world are probably industry trendsetters, such as Facebook, Etsy, Amazon, and Twitter. We all probably wish we could evolve our own software environments into one of these Utopias.

Complexity and Risk

As an organization continues to evolve their software, they naturally increase the overall complexity, and thereby the challenge of effectively delivering reliable and performant software. In this post, I will explore the challenges of software delivery, as a software environment grows in complexity. Specifically, I will focus on how to evaluate the level of risk based on software changes made to various components within the software environment.

Sensitivity and Impact

As we examine the level of risk introduced by software changes within the environment, two aspects of risk are inescapable, sensitivity and impact. Sensitivity will be defined as the potential degree of which one component, such as an application, service, or data source, is affected by changes to other components within the same software environment. How sensitive is ‘Application A’ to changes made to other components within the same software environment, on which ‘Application A’ is directly or indirectly dependent?

The impact will be defined as the potential effect a component’s changes have on other components within the software environment. Teams tend to only evaluate the impact of changes to the immediate component or application stack. They do not sufficiently consider how those changes impact those components that are directly and indirectly dependent on them. What level of impact do changes to ‘Service B’ have on all other components within the software environment that are directly and indirectly dependent on ‘Service B’?

Notice I use the word potential. Any change has the potential to introduce risk. The level of risk varies, based on the type and volume of changes. A few simple changes should have a low potential for impact, as opposed to a high number of changes, or more complex changes. For example, changing an internal error message logged by a particular service operation should present a very low risk. This, as opposed to rewriting that operation’s complex algorithm for calculating a customer’s creditworthiness. The potential impact of those two types’ changes to dependent components varies significantly.

Measuring Risk

For both sensitivity to change and impact of change, I will use a color-coded scale to subjectively assign a level of potential risk to each component within a given software environment. The scale ranges from ‘Low’, to ‘Moderate’, to ‘High’, to ‘Very High’. Using the scale, it is possible to ‘heat map’ a software environment, based on the level of risk from changes.

Independent Aspects of Risk

Sensitivity and impact are two independent aspects of risk. Changes to one component may have a ‘Low’ potential impact on all other components within the environment. While at the same time, that same component may have a ‘High’ sensitivity to changes made to other components within the environment. Alternatively, a component may have a ‘Very High’ risk for potential impact on multiple components within the environment. At the same time, that same component may have a ‘Low’ potential sensitivity to changes made to other components. Sensitivity and risk do not parallel each other.

Growing Complexity

Let’s look at how sensitivity and impact change as we increase the software environment’s complexity. In the first example, we will look at one of the two environments I described earlier, isolated applications. Applications may have their own web and mobile components, SOAP or RESTful services, data sources, utilities, scheduled tasks, and so forth. However, the applications do not depend on each other or components outside their own immediate application stack; the applications are self-contained.


When making changes in this type of environment, the real potential impact is to the overall stability, security, and performance of the individual applications, themselves. As long as they are in isolation, the applications will have no impact on each other. Therefore, applications potential sensitivity to changes and their impact on other applications is ‘Low’.

Shared Components

A slightly more complex example is a software environment in which one or more applications have a dependency on a component outside their immediate application stack. For example, a healthcare provider develops a Windows-based application to track their employee’s work schedules (Application A). In addition, they develop a web application to track patient appointments (Application B). Lastly, they offer a client-facing mobile application for patients to track personal fitness and nutrition goals (Application C). Applications B and C share a common set of services and a database for managing patient data.

Software changes made to Applications A, B, and C, should have no effect on other components within the software environment. However, Applications B and C are potentially impacted by changes made to either the Services Layer or Data Layer. The Services Layer has ‘High’ potential impact to the software environment. Lastly, the Data Layer should not be directly impacted by changes made to the Services Layer or Applications. However, the Data Layer has the potential to directly affect the Services Layer, and indirectly affect Applications B and C. Therefore, the Data Layer’s potential impact on other dependent components within the environment is ‘Very High’.

Multiple Shared Components

An even more complex example is a software environment in which multiple applications have one or more dependencies on multiple components outside their immediate application stack (many-to-many).

Take, for example, a small financial institution. They have a ‘legacy’ COBOL-based application for managing their commercial mortgage business (Application A). They also have an older J2EE-based application, they acquired through a business merger, for managing their commercial banking relationships (Application B). Next, they have a relatively new Java EE-based investment banking application to manage their retail customers (Application C). Lastly, they have web-based, client-facing application for secure, online retail banking.

Since both Application A and B serve commercial clients, it is necessary to send financial data between the two application stacks. Since both applications are built on different, older technologies, the development team built a Custom Messaging Middleware component to connect the two applications. The Custom Messaging Middleware component receives, transforms, and delivers messages between the two applications.

Changes made to Applications C and D should have no impact on other components within the software environment. However, changes made to either Application A or B has the potential to indirectly affect the ability to successfully communicate with the other application, via the Custom Messaging Middleware. Changes to the Custom Messaging Middleware have the potential to affect both Applications A and B. The Custom Messaging Middleware has a ‘Moderate’ potential sensitivity to risk, versus ‘Low’, because one could argue that changes to either Application A or Application B’s messaging format could impact the Custom Messaging Middleware’s ability to properly process that application’s messages and successfully deliver them to opposite application.

Applications B, C, and D have a direct dependency on the Services Layer, and indirectly on the Data Layer. Therefore, the potential impact of changes to the Services Layer on other components is arguably higher than in the last example. The Services Layer’s potential impact on other components is ‘Very High’.

Since Application B has a direct dependency on both the Messaging Middleware and the Services Layer, it has a higher sensitivity to changes then the other three applications. Application B’s potential sensitivity to changes by other components is ‘Very High’.

Changes made to the Services Layer or the Applications will not affect the Data Layer. However, the Data Layer has the potential to directly affect the Services Layer, and indirectly affect Applications B, C, and D. Therefore, the Data Layer’s potential impact on the software environment is ‘Very High’.

Small Enterprise

The last example of increasing complexity is an environment in which even more applications are dependent on even more components. Additionally, there may be different types of components, such as a common UI and third-party APIs, which only increase the complexity of the dependencies. Although this example is nowhere near as complex as many enterprise software environments, it does begin to reflect their intricate, inner-dependent structure.

Let’s use an example of a large web-based retailer. The retailer has a standalone ERM application for managing their wholesale purchasing and product distribution (Application A). Next, they have their primary client-facing storefront (Application B). They also have a separate application to handle customer accounts (Application C). Lastly, they have an application that manages their online media retail business and media storage (Application D).

In addition to the Common Services Layer, Common Data Layer, and Custom Messaging Middleware, as seen in earlier examples, the retailer has two other components in their environment, a Common Web User Interface (UI) and a Web API. The Web UI provides the customer with a seamless branded experience, no matter which application they use – Application B, C, or D. The customer enters the Common Web UI and has all three application’s features seamlessly available to them.

The retailer also exposes a RESTful Web API for its marketing affiliates. Third parties can develop a variety of applications that drive sales to the retailer, in return for a sales commission.

In the earlier examples, individual applications had separate points of entry. However, in this example, the Common Web UI provides a single point of entry for users of Applications B, C, and D. Having a single point of entry also introduces a single point of failure for all three applications. Thus, the potential risk to the retailer and their customers is much greater. The Common Web UI’s potential impact on other components is ‘Very High’.

A single point of entry also introduces a single point of failure.

The potential sensitivity of the Common Web UI to changes comes from its direct dependency on the Services Layer, and indirectly on the Data Layer. Additionally, one could argue, since the Common Web UI displays the three Applications, it is also sensitive to changes made by those applications. If one of those applications becomes impaired due to a bad change, that application would seem to affect the Web UI’s functionality. The Common UI’s potential sensitivity to change is ‘High’.

The Web API is similar to the Common Web UI, in terms of potential sensitivity and impact. The potential impact of changes to the Web API is ‘Very High’, since a defect there could result in the potential impairment of the retailer’s affiliate applications. The potential sensitivity of the Web API to changes comes from its direct dependency on the Services Layer, and indirectly on the Data Layer. The Web API’s potential sensitivity to change is ‘High’. There is very little chance of potential impact to the Web API from the retailer’s affiliate applications.

Impact of Key Components

Lastly, as systems grow in complexity, certain components often become so key, they have the potential to impact the entire environment, a true single point of failure. Below, note the potential impact of changes to the Common Services Layer on all other components. As the software environment has grown in complexity, the Common Services Layer sits at the heart of the system. The Services Layer has multiple components directly dependent on it (i.e. Application C), as well as other components indirectly dependent on it (i.e. Third-Party Applications). It is also the only point of access to and from the Common Data Layer.

There are steps organizations can take to mitigate the potential risk caused by changes to key components, like the Services Layer. Areas organizations commonly focus on to reduce risk are higher code quality, increased test coverage, and improved performance, fault tolerance, system redundancy, and rollback capabilities. Additionally, management should more thoroughly scrutinize proposed software changes to key components, balancing new features with the need for stability, availability, and performance.

Management must balance the need for new features with need for stability, availability, and performance.

Specific to services, organizations often look to decouple larger services, creating smaller, more focused services. Better separation of concerns increases the likelihood that potential impairments caused by code defects are isolated to a smaller subset of functionality.

Conclusion

In this brief post, we examined a potential risk to delivering reliable software, the impact of software changes. There are many risks to delivering reliable software. Once all sources of risk are identified and quantified, the overall level of risk to delivering reliable software can be assessed, and steps taken to reduce the potential impact.

, , , , , , , , , , , , ,

Leave a comment

Spring Integration with Eclipse Using Maven

Integrate the Spring Framework into your next Eclipse-based project using Apache Maven. Learn how to install, configure, and integrate these three leading Java development tools. All source code for this post is available on GitHub.

 

Introduction

Although there is a growing adoption of Java EE 6 and CDI in recent years, Spring is still a well-entrenched, open-source framework for professional Java development. According to GoPivotal’s website, “The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications. Spring focuses on the ‘plumbing’ of enterprise applications so that teams can focus on application-level business logic, without unnecessary ties to specific deployment environments.”

Similar to Spring in terms of wide-spread adoption, Eclipse is leading Java IDE, competing with Oracle’s NetBeans and JetBrain’s IntelliJ. The use of Spring within Eclipse is very common. In the following post, I will demonstrate the ease of integrating Spring with Eclipse, using Maven.

Maven is a marketed as a project management tool, centralizing a project’s build, reporting and documentation. Conveniently, Maven is tightly integrated with Eclipse. We will use Maven for one of its best known features, dependency management. Maven will take care of downloading and managing the required Spring artifacts into our Eclipse-based project.

Note there are alternatives to integrating Spring into Eclipse, using Maven. You can download and add the Spring artifacts yourself, or go full-bore with GoPivotal’s Spring Tool Suite (STS). According to their website, STS is an Eclipse-based development environment, customized for developing Spring applications.

The steps covered in this post are as follows:

  1. Download and install Maven
  2. Download and install the Eclipse IDE
  3. Linking the installed version of Maven to Eclipse
  4. Creating a new sample Maven Project
  5. Adding Spring dependencies to the project
  6. Demonstrate a simple example of Spring Beans and ApplicationContext
  7. Modify the project to allow execution from an external command prompt

Installing Maven

Installing Maven is simple process, requiring minimal configuration:

  1. Download the latest version of Maven from the Apache Maven Project website. At the time of this post, Maven is at version 3.1.1.
  2. Assuming you are Windows, unzip the ‘apache-maven-3.1.1’ folder and place in your ‘Program Files’ directory.
  3. Add the path to Maven’s bin directory to your system’s ‘PATH’ Environmental Variable.
Adding Maven bin Directory to PATH Environmental Variable

Adding Maven bin Directory to PATH Environmental Variable

We can test our Maven installation by opening a new Command Prompt and issuing the ‘mvn -version’ command. The command should display the installed version of Maven, Maven home directory, and other required variables, like your machine’s current version of Java and its location. To learn other Maven commands, try ‘mvn -help’.

Checking Maven is Installed Correctly

Checking Maven is Installed Correctly

Installing Eclipse IDE

Installing Eclipse is even easier:

  1. Download the latest version of Eclipse from The Eclipse Foundation website. There are several versions of Eclipse available. I chose ‘Eclipse IDE for Java EE Developers’, currently Kepler Service Release 1.
  2. Similar to Maven, unzip the ‘eclipse’ folder and place in your ‘Program Files’ directory.
  3. For ease of access, I recommend pinning the main eclispe.exe file to your Start Menu.
Downloading Eclipse IDE for Java EE Developers

Downloading Eclipse IDE for Java EE Developers

Linking Maven to Eclipse

The latest version of Eclipse comes pre-loaded with the ‘M2E – Maven Integration for Eclipse’ plug-in. There is no additional software installs required to use Maven from within Eclipse. Eclipse also includes an embedded runtime version of Maven (currently 3.04). According to the Eclipse website wiki, the M2E plug-in uses the embedded runtime version of Maven when running Maven builder, importing projects and updating project configuration.

Latest Version of Eclipse Kepler SR1 with M2E Installed

Latest Version of Eclipse Kepler SR1 with M2E Installed

Although Eclipse contains an embedded version of Maven, we can configure M2E to use our own external Maven installation when launching Maven using Run as… -> M2 Maven actions. To configure Maven to use the version of Maven we just installed:

  1. Go to Windows -> Preferences -> Maven -> Installations window. Note the embedded version of Maven is the only one listed and active.
  2. Click Add… and select the Maven folder we installed in your Program Files directory. Click OK.
  3. Check the box for new installation we just added instead of the embedded version. Click OK.
Adding Installed Version of Maven to Eclipse

Adding Installed Version of Maven to Eclipse

Adding Installed Version of Maven to Eclipse

Adding Installed Version of Maven to Eclipse

Adding Installed Version of Maven to Eclipse

Adding Installed Version of Maven to Eclipse

Sample Maven Project

To show how to integrate Spring into a project using Maven, we will create a Maven Project in Eclipse using the Maven Quickstart Archetype template. The basic project will show the use of Spring Beans and an ApplicationContext IoC container. On a scale of 1 to 10, with 10 being the most complex Spring example, this project is barely a 1! However, it will demonstrate that Spring is working in Eclipse, with minimal effort thanks to Maven.

To create the project:

  1. File -> New Project -> Other…
  2. Search on ‘maven’ in the Wizards text box and select ‘Maven Project’.
  3. Select the Maven Quickstart Archetype.
  4. Specify the Archetype parameters.
Creating a New Maven Project - Using Wizard

Creating a New Maven Project – Using Wizard

Creating a New Maven Project - Project Location

Creating a New Maven Project – Project Location

Creating a New Maven Project - Choosing Archetype

Creating a New Maven Project – Choosing Archetype

Creating a New Maven Project - Archetype Parameters

Creating a New Maven Project – Archetype Parameters

Spring Dependencies

Once the Maven Quickstart project is created, we will add the required Spring dependencies using Maven:

  1. Open the Maven Project Object Model (POM) file and select the Dependencies tab.
  2. Use the The Central Repository website to find the Dependency Information for spring-core and Spring-context artifacts (jar files).
  3. Add… both Spring Dependencies to the pom.xml file.
  4. Right-click on the project and click Maven -> Update Project…
Adding Spring Dependencies to pom.xml - Dependencies Tab

Adding Spring Dependencies to pom.xml – Dependencies Tab

Adding Spring Dependencies to pom.xml - Artifact Details for spring-core

Adding Spring Dependencies to pom.xml – Artifact Details for spring-core

Adding Spring Dependencies to pom.xml - Adding spring-context

Adding Spring Dependencies to pom.xml – Adding spring-context

Adding Spring Dependencies to pom.xml - Spring Dependencies Added

Adding Spring Dependencies to pom.xml – Spring Dependencies Added

Adding Spring Dependencies to pom.xml - Dependencies Added to Project

Adding Spring Dependencies to pom.xml – Dependencies Added to Project

We now have a Maven-managed Eclipse project with our Spring dependencies included. Note the root of the file paths to the jar files in the Maven Dependencies project folder is the location of our Maven Repository. This is where all the dependent artifacts (jar files) are stored. In my case, the root is ‘C:\Users\{user}\.m2\repository’. The repository location is stored in Eclipse’s Maven User Setting’s Preferences (see below).

Project Object Model File (pom.xml):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.blogpost.maven</groupId>
<artifactId>maven-spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>maven-spring</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
</dependencies>
<description>Project for blog post about the use of Spring with Eclipse and Maven.</description>
</project>
view raw pom.xml hosted with ❤ by GitHub

Location of Local Maven Repository

Local Maven Repository Location

Sample Code

Next add the supplied Code to the project. We will add two new java classes and a Spring configuration file. We will replace the contents of main App class with our sample code. Steps are as follows:

  1. Add the supplied Vehicle.java and MaintainVehicle.java class files to the project, in the same classpath as the App.java class.
  2. Add the supplied Beans.xml Spring configuration file to the project at the ‘src/main/java’ folder.
  3. Open the App.java class file and replace the contents with the supplied App.java class file.

The sample Spring application is based on vehicles. There are three Spring Beans defined in the xml-based Spring configuration file, representing three different vehicles. The main App class uses an ApplicationContext IoC Container to instantiate three Vehicle POJOs from the Spring Beans defined in the Beans.xml Spring configuration. The main class then instantiates an instance of the MaintainVehicle class, passes in the Vehicle objects and calls MaintainVehicle’s two methods.

Location of New Files in Project Explorer

Location of New Files in Project Explorer

Spring Configuration File (Beans.xml):

<?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-3.0.xsd">
<bean id="vehicle1" class="com.blogpost.maven.maven_spring.Vehicle">
<property name="make" value="Mercedes-Benz" />
<property name="model" value="ML550" />
<property name="year" value="2010" />
<property name="color" value="Silver" />
<property name="type" value="SUV" />
</bean>
<bean id="vehicle2" class="com.blogpost.maven.maven_spring.Vehicle">
<property name="make" value="Jaguar" />
<property name="model" value="F-Type" />
<property name="year" value="2013" />
<property name="color" value="Red" />
<property name="type" value="Convertible" />
</bean>
<bean id="vehicle3" class="com.blogpost.maven.maven_spring.Vehicle">
<property name="make" value="Suzuki" />
<property name="model" value="SVF 650" />
<property name="year" value="2012" />
<property name="color" value="Black" />
<property name="type" value="Motorcycle" />
</bean>
</beans>
view raw Beans.xml hosted with ❤ by GitHub

Main Method Class (App.java)

package com.blogpost.maven.maven_spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext(
"Beans.xml");
MaintainVehicle maintain = new MaintainVehicle();
// vehicle1 bean
Vehicle obj1 = (Vehicle) context.getBean("vehicle1");
System.out.printf("I drive a %s.\n", obj1.getLongDescription());
System.out.printf("Is my %s tuned up? %s\n",
obj1.getShortDescription(), obj1.getServiced());
maintain.serviceVehicle(obj1);
System.out.printf("Is my %s tuned up, yet? %s\n\n", obj1.getMake(),
obj1.getServiced());
// vehicle2 bean
Vehicle obj2 = (Vehicle) context.getBean("vehicle2");
System.out.printf("My wife drives a %s.\n", obj2.getLongDescription());
System.out.printf("Is her %s clean? %s\n", obj2.getShortDescription(),
obj2.getWashed());
maintain.washVehicle(obj2);
System.out.printf("Is her %s clean, now? %s\n\n", obj2.getMake(),
obj2.getWashed());
// vehicle3 bean
Vehicle obj3 = (Vehicle) context.getBean("vehicle3");
System.out.printf("Our son drives his %s too fast!\n", obj3.getType()
.toLowerCase());
}
}
view raw App.java hosted with ❤ by GitHub

Running the Application

If successful, the application will output a series of messages to the Console. The first few messages in red are Spring-related messages, signifying Spring is working. The next messages in black are output by the application. The messages show that the three Spring Beans are successfully instantiated and passed to the MaintainVehicle object, where it’s methods were called. If the application would only buy me that Silver Mercedes!

Successful Console Output of Java Application

Successful Console Output of Java Application

Running the Application from a Command Prompt

All the source code for this project is available on GitHub. Note the pom.xml contains a some extra configuration information not shown above. The extra configuration information is not necessary for running the application from within Eclipse. However, if you want to run the application from an external Command Prompt, you will need the added configuration. This extra configuration ensures that the project is correctly packaged into a jar file, with all the necessary dependencies to run. Extra configuration includes an additional logging dependency, a resource reference to the Spring configuration file, one additional property, and three maven plug-in references for compiling and packaging the jar.

To run the java application from an external Command Prompt:

  1. Open a new Command Prompt
  2. Change current directory to the project’s root directory (local GitHub repository in my case)
  3. Run a ‘mvn compile’ command
  4. Run a ‘mvn package’ command (downloads dependencies and creates jar)
  5. Change the current directory to the project’s target sub-directory
  6. Run a ‘dir’ command. You should see the project’s jar file
  7. Run a ‘java -jar {name-of-jar-file.jar}’ command.

You should see the same messages output in Eclipse, earlier.

Running Application from External Command Prompt

Running Application from External Command Prompt

, , , , , , , , , , ,

10 Comments