Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kenneth A. Kousen - Making Java Groovy - 2014.pdf
Скачиваний:
55
Добавлен:
19.03.2016
Размер:
15 Мб
Скачать
☆

The Java approach, part 2: Maven

105

(continued)

The built-in Ant tasks are very low level. As a result, Ant build files quickly grow long and complex and involve a lot of repetition.

For all these reasons and others Ant was ripe for a higher-level replacement. That role was filled by the Maven project, which is either a blessing or a curse depending on your experiences with it.

5.4The Java approach, part 2: Maven

I’m going to confess up front that Maven is hard to talk about rationally. Its best features (establishing a conventional project layout, managing dependencies, providing a rich plugin architecture) are also considered some of its worst features (difficult to work outside its conventions, hard to manage transitive dependencies, the whole “download the internet” problem). I can honestly say I’ve never encountered a technology that’s both common in the industry and yet loathed with the white-hot intensity of a thousand suns.6 Bring up Maven in a group of developers, and someone will refuse to discuss “the M word.” Yet, at the same time, somebody else will quietly say that they can make it do anything and don’t understand what all the fuss is about.

My own experience isn’t so black-and-white. I find that if a project was designed using Maven from the beginning, it tends to work well with the system. It’s also hard to use that system without Maven. On the other hand, adding Maven to a system that wasn’t started with it can be quite painful. In addition, friends have also assured me that once a system gets above a certain size, the whole process becomes an unmanageable mess.

Perhaps the best way to stay above the fray is to say that Maven has a highly opinionated API. To be successful you have to do things the Maven way. Plus, like Ant, you’re coding your build in XML, which is never easy. The multi-project build capabilities are awkward, too.7

I will note that the standard Maven project layout (shown in figure 5.2) has become common throughout the industry. Also, people may complain about Maven’s approach to dependency management, but I haven’t seen anything dramatically better. Gradle (the proposed replacement, discussed later in this chapter) uses Maven repositories and Ivy dependency management and suffers from the same “download the internet” problem. Dependency management is just hard, no matter how you approach it.

Returning (at last) to the core theme of this book, the goal of this section is to show you how to incorporate Groovy into Maven builds. There are two ways to do that. I’ll start with the Groovy-Eclipse plugin and then build the same application using the GMaven project.

6Except possibly for every Microsoft technology ever.

7Admittedly that doesn’t sound terribly “above the fray,” but at least I’m trying.

www.it-ebooks.info

106

CHAPTER 5 Build processes

Figure 5.2 Standard Maven project structure used for the application in this section. Compiled sources are in src/main/ java, and tests reside in src/test/java.

5.4.1The Groovy-Eclipse plugin for Maven

The Groovy-Eclipse compiler plugin (http://mng.bz/2rHY) is a standard compiler plugin for Maven. It emerged from the effort to build a good Eclipse plugin for Groovy that worked with combined Groovy and Java projects. The Maven plugin is a way to take advantage of that effort, whether you plan to use the Eclipse IDE or not.

To demonstrate its use I’ll build a small project that accesses the Yahoo! Weather web service and reports on the current conditions. This is easy enough to do in Java but becomes particularly simple in Groovy.

The Yahoo! Weather web service (http://developer.yahoo.com/weather/) provides weather information in the form of an RSS feed. The web service is accessed from a URL of the form

http://weather.yahooapis.com/forecastrss

The URL has two parameters, one required and one optional. The required parameter is w, a so-called WOEID (Where On Earth ID), that Yahoo uses to identify a location. The other parameter is u, which is used to specify the temperature units in Fahrenheit (f, the default) or Celsius (c). For unknown reasons, there’s no way to programmatically look up a WOEID. Instead Yahoo! directs you to its own weather page and suggests you search for your city.

A simple HTTP GET request to the proper URL returns an XML response in RSS form. A sample is included on Yahoo!’s web page.

Suppose I decided to build a simple application to retrieve the current weather conditions based on this service. Maven recommends that you specify a particular artifact to begin the project, so I’ll start with the classic maven-archetype-quickstart:

> mvn archetype:generate –DgroupId=mjg –DartifactId=weather –DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0-SNAPSHOT –Dpackage=mjg

MAVEN ARCHETYPES The Groovy-Eclipse plugin uses regular Java archetypes and adds Groovy functionality. The GMaven approach in the next section includes a basic archetype to get started.

www.it-ebooks.info

The Java approach, part 2: Maven

107

This generates a Java project with the standard layout, meaning the source code directory is src/main/java and the testing directory is src/test/java. The quick start archetype includes a trivial App.java and AppTest.java in those directories, respectively. The generator also adds a standard Maven POM file in the root directory, whose only dependency is on JUnit, as shown in the next listing.

Listing 5.8 The Maven pom.xml file for a standard Java project

<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>

<groupId>mjg</groupId>

<artifactId>weather</artifactId>

<packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>weather</name> <url>http://maven.apache.org</url> <dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.10</version>

<scope>test</scope>

</dependency>

</dependencies>

</project>

The only change I’ve made so far from the standard is to upgrade the JUnit dependency to 4.10 from 3.8.1.

To do the actual work I need a class to send the request to Yahoo and parse the response, and a POJO to hold the resulting weather information. Starting with the POJO, for a given city, region, and country I want to store the condition, temperature, wind chill, and humidity. The web service returns a lot more information than this, but this will suffice to get started.

POJOs are simple containers for data, so the constructors, getter and setter methods, and any necessary overrides are mostly clutter. I can therefore simplify my life if I use a POGO instead, as shown in the following listing.

Listing 5.9 Weather.groovy, a POGO to hold weather results from the web service

package mjg

class Weather { String city String region String country String condition String temp

www.it-ebooks.info

108

CHAPTER 5 Build processes

String chill

String humidity

String toString() {

"""

Weather for $city, $region, $country: Condition : $condition

Temperature: $temp

Wind Chill : $chill Humidity : $humidity

"""

}

}

The toString method is a way to produce formatted output. Groovy’s multiline string makes it particularly easy.

The other class I need is a parser for the web service. Because all I need is a GET request I can use the parse method in the XmlSlurper class as usual and drill down the resulting DOM tree to get the results I want. That’s pretty simple, too, as shown in the following listing.

Listing 5.10 YahooParser.groovy, which accesses and parses the weather service

package mjg

class YahooParser {

final static String BASE = 'http://weather.yahooapis.com/forecastrss?'

Weather getWeather(String woeid) {

def root = new XmlSlurper().parse(BASE + "w=$woeid") Weather w = new Weather(

city:root.channel.location.@city,

region:root.channel.location.@region,

country:root.channel.location.@country,

condition:root.channel.item.condition.@text,

temp:root.channel.item.condition.@temp,

chill:root.channel.wind.@chill,

humidity:root.channel.atmosphere.@humidity

)

}

}

Given a WOEID, the service builds the URL and accesses the web service, parses the resulting RSS, and returns an instance of the Weather class with all the relevant fields populated.

To complete the program I need a driver, which I can write as a Groovy script. That’s a one-liner, unless I want to allow the client to specify a WOEID on the command line:

def woeid = args.size() ? args[0] : '2367105' println new YahooParser().getWeather(woeid)

www.it-ebooks.info

The Java approach, part 2: Maven

109

The default WOEID in the script is for Boston, MA, and it’s stored in RunDemo.groovy. In order to demonstrate the differences when both Java and Groovy sources are present together, I also added a Java class to access the web service in the file RunInJava.java:

public class RunInJava {

public static void main(String[] args) { String woeid = "2367105";

if (args.length > 0) woeid = args[0]; YahooParser yp = new YahooParser(); System.out.println(yp.getWeather(woeid));

}

}

Now comes the interesting part: how do I get Maven to handle all the Groovy code? The Groovy-Eclipse plugin requires two additions to the POM file. First I need to add Groovy as a dependency:

<dependencies>

...

<dependency>

<groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.1.5</version>

</dependency>

</dependencies>

Next I need to add the Groovy-Eclipse plugin in a build section below the dependencies:

<build>

<plugins>

<plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version>

<configuration> <compilerId>groovy-eclipse-compiler</compilerId>

</configuration>

<dependencies>

<dependency>

<groupId>org.codehaus.groovy</groupId> <artifactId>groovy-eclipse-compiler</artifactId> <version>2.7.0-01</version>

</dependency>

</dependencies>

</plugin>

</plugins>

</build>

With both of these additions Maven will compile and use Groovy code appropriately, except for one rather strange oddity. Normally I would add my Groovy classes to src/ main/groovy and any Groovy tests to src/test/groovy. According to the plugin documentation, I can do that only if (1) there’s at least one Java class in src/main/java or

(2) I add a lot more XML to specify the additional source directories.

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]