Thursday, February 23, 2012

A maven trick

I was playing around with STS, adding Grails to it for my own purposes. I don't know if this messed things up or not, but when I went to run one of my other spring projects, it came up with this error:

java.lang.NoClassDefFoundError: org/junit/runner/notification/StoppedByUserException


I removed the Grails plug-in, but still got the same error. A clean didn't help either.

Here's what did:

Open a terminal window, navigate to the top level of the directory of your project, and type:

mvn eclipse:clean
mvn clean
mvn eclipse:eclipse

Then refresh the project STS, navigate to your junit test and run as such, and you're back in business.

Monday, February 20, 2012

Hibernate - getting started

In this blog, we'll explore how to run some hibernate from the source - hibernate.org. It has a nice tutorial, which is also short and sweet.

In order to get the tutorials up and running, download the code from here:

http://docs.jboss.org/hibernate/core/4.0/quickstart/en-US/html_single/#d0e127

and click on the files/hibernate-tutorials.zip link. Once the file is downloaded and unzipped, copy it into your STS workspace. (I'm assuming you have STS and maven installed - if not, you may need to research downloading maven/eclipse or just STS).

Once that's done, bring up a terminal window and navigate to hibernate-tutorials directory you just copied into the workspace. For each of the four tutorial projects (hbm, entitymanager, annotations and envers), navigate into the directory and type "mvn eclipse:eclipse". That creates an eclipse project file. That allows you import the four projects into STS. Use file, import, select "existing projects into workspace", and find one of the folders (e.g. hibernate-tutorial-hbm) and import it. Do this for all of the projects.

You can run them by right-clicking and select "junit test".

I won't rehash what's done in each of them. Here's the url for the very short, but very clear and easy to follow tutorial: http://docs.jboss.org/hibernate/core/4.0/quickstart/en-US/html/

The basics of are this:

Chapter 2 - Tutorial Using Native Hibernate APIs and hbm.xml Mappings

hibernate-tutorial-hbm:

- uses Hibernate mapping files (hbm.xml) to provide mapping information
- uses the native Hibernate APIs

The hibernate.cfg.xml file contains info like database driver, username, password, connection url, etc.
The Event.hbm.xml file contains the mapping of the field.


The next tutorial, chapter 3:

hibernate-tutorial-annotations

Tutorial Using Native Hibernate APIs and Annotation Mappings

Objectives

Use annotations to provide mapping information

Use the native Hibernate APIs

The event.hbm.xml file, which maps the class fields to the database fields, is gone. Annotations within the source code give the same information. The hibernate.hbm.xml file reflects the change with a declaration of the mapping class, "mapping class="org.hibernate.tutorial.annotations.Event".

Here's what event looks like with annotations:


import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table( name = "EVENTS" )
public class Event {
private Long id;

private String title;
private Date date;

public Event() {
// this form used by Hibernate
}

public Event(String title, Date date) {
// for application use, to create new events
this.title = title;
this.date = date;
}

@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public Long getId() {
return id;
}

private void setId(Long id) {
this.id = id;
}

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}



Chapter 4. Tutorial Using the Java Persistence API (JPA)

Objectives

Use annotations to provide mapping information.

Use JPA.

This chapter shows utilizes the Java persistence API instead of the native hibernate API. Here, the hibernate.hbm.xml is replaced by persistence.xml. persistence.xml, like the hibernate.hbm.xml file, shows the configuration information, such as jdbc driver, url, name password, plus a couple of hibernate-specific values which as a result begin with "hibernate-". The programmatic API is slightly different, using "persist" instead of "save.", but looks very similar

The final chapter adds some auditing capability via the @org.hibernate.envers.Audited annotation.

Saturday, February 18, 2012

Autowiring and Component scans

In our last blog entry, we took the "Hello World" program from the Spring 2.5 Recipes book and incorporated it into a Spring template utility project.

One if the interesting facts about the generated template test is that it includes the service as an "@Autowired" annotation:


@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class ExampleConfigurationTests {

@Autowired
private Service service;

@Test
public void testSimpleProperties() throws Exception {
assertNotNull(service);
}

}



A component scan statement in the bean configuration file apparently tells the Spring container to search for the @Component annotation in the specified package and subpackages:


<context:component-scan base-package="com.apress.springrecipes.hello" />


It's specified in the ExampleService bean:


@Component
public class ExampleService implements Service {



So, although the test class that uses it doesn't specify "ExampleService", but rather just "Service", since ExampleService is the only component in the package that matches the @Autowired annotation (it's a Service), Spring selects that as the class to be instantiated.

Our experiment today, though, is to first just implement @Autowired in a regular (not used for testing) class. If that works out, we'll try to see if we can use the component scan to avoid coding the beans.

We'll base our logic on this tutorial:

http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/

So, first let's generate a spring utility project. We'll call it "SpringTestAutowireAnnotation", and give it the same package name as the tutorial: "com.mkyong.common".

We can download the source code, and drag and drop the java source files into that package in the generated project. Also, we'll copy these bean configuration statements from the configuration file into our own project's configuration file (src/main/resources/META-INF/spring/app-context.xml):

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

<bean id="customer" class="com.mkyong.common.Customer" >
<property name="action" value="buy" />
<property name="type" value="1" />
</bean>

<bean id="personA" class="com.mkyong.common.Person" >
<property name="name" value="mkyongA" />
</bean>



So, now here's our app-context.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<description>Example configuration to get you started.</description>

<context:component-scan base-package="com.mkyong.common" />

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

<bean id="customer" class="com.mkyong.common.Customer" >
<property name="action" value="buy" />
<property name="type" value="1" />
</bean>

<bean id="personA" class="com.mkyong.common.Person" >
<property name="name" value="mkyongA" />
</bean>

</beans>



We'll have to change the means of retrieving the application context in the "App" class from this:

ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"SpringBeans.xml"});


to this:

ApplicationContext context =
new ClassPathXmlApplicationContext("app-context.xml");



And, also, add the classpath app-context to the new run configuration for the project:

To do this, right click on App.java, select "Run As", "Run Configuration", click the new icon, give it a name like "SpringAutoWiredTest", click on the "Classpath" tab, select "User Entries", click the "Advanced" button on the right, select "Add External Folder", then navigate to the current project and then down to "src/main/resources/META-INF/spring", and then press "Choose".

Apply the changes and run.

Here's the output:

Customer [person=Person [name=mkyongA], type=1, action=buy]



Ok, now the ultimate test. Can we get delete the beans from the configuration file, add the @Component annotation to the beans, and get the same results? Let's try it.

Here's the new app-context.xml, with the beans deleted:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<description>Example configuration to get you started.</description>

<context:component-scan base-package="com.mkyong.common" />

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

</beans>



Let's add the @Component annotations:

import org.springframework.stereotype.Component;

@Component
public class Customer {


and

import org.springframework.stereotype.Component;

@Component
public class Person {



Here's the output:


Customer [person=Person [name=null], type=0, action=null]


The name and action are null, because these were specified in the beans which we deleted. That's something to keep in mind when considering when and how to use the @Component tag.

Friday, February 17, 2012

Spring utilty template - merging with Hello Word

I had previously meant to do a blog on using a spring template utility to do the hello world example in chapter 2 from the Spring 2.5 Recipe book, but got sidetracked. So, let's give it another go.

The basics of it are, when you create a Simple Spring Utility project from STS (new, Spring Template Project, Simple Spring Utility Project), you get an ExampleService and a Service interface generated for you. The Service interface is just this:


package com.apress.springrecipes.hello;

public interface Service {

String getMessage();

}



And the ExampleService implements the Service interface and returns "hello, World":



package com.apress.springrecipes.hello;

import org.springframework.stereotype.Component;


/**
* {@link Service} with hard-coded input data.
*/
@Component
public class ExampleService implements Service {

/**
* Reads next record from input
*/
public String getMessage() {
return "Hello world!";
}

}


The above example includes an example of using the @Component annotation, which means you don't have to specify the bean in the spring xml file. If we look in there (in "src/main/resources/META-INF/spring/app-context.xml"), we'll see the following declaration:


<context:component-scan base-package="com.apress.springrecipes.hello" />


This tells the Spring container to look through the specified package and subpackages for any class with the "@Component" annotation and make it a bean. (There are also subclasses of @Component, but that's the gist of it).

Getting back to the main point, to see this in action, you need to run the unit tests that get generated from the template. For example, if you drill down into "src/test/java", you'll find a class called "ExampleServiceTests.java", that looks like this:



package com.apress.springrecipes.hello;

import com.apress.springrecipes.hello.ExampleService;
import junit.framework.TestCase;

public class ExampleServiceTests extends TestCase {

private ExampleService service = new ExampleService();

public void testReadOnce() throws Exception {
assertEquals("Hello world!", service.getMessage());
}

}


If you right-click and run that as a junit test, you'll see the green bar indicating it passed the test.

However, we'd like to run the code from the Spring Recipe book:



package com.apress.springrecipes.hello;

public class HelloWorld {

public void hello() {
System.out.println("Hello world!");
}
}




Based on the book, the main class should look (roughly) like this:



public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("app-context.xml"); // why would expect to find beans.xml?

HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
helloWorld.hello();
}



Note that I changed the name of the spring beans file to "app-context.xml". It's in "src/main/resources/META-INF/spring/app-context.xml".

Let's add the entry for HelloWorld into it:


<bean id="helloWorld" class="com.apress.springrecipes.hello.HelloWorld">
</bean>


Now, if you just run main like this, it will crash, because app-context.xml (the bean configuration file) isn't in the classpath. It's in "src/main/resources/META-INF/spring/app-context.xml.


So, how to we get it that into the class path?

Here's how:

In the STS, select Run > Run Configurations. Click on the user entries item in the dialog box, then advanced > add external folder, then drill down to the path leading up to the configurations file. Also, obviously, use the main class above as the main class. When you run it, you should see "hello world!" in your console output.

Hibernate in Spring 3

Hibernate is something that I've done a couple of tutorials on in the past. Basically, to me it's been something that lets you map in XML what fields in the object correspond to what fields in the db, so you don't have to code JDBC statements.

But, I ran the hibernate wizard on spring 3 templates, and it actually seems as if it's close to the Groovy version, which means there aren't any mappings to be done at all. Let's find out why.

Checking app-context.xml, we find the following 3 statements

<jdbc:embedded-database id="dataSource" type="H2"/>

<tx:annotation-driven transaction-manager="transactionManager" />

<context:component-scan base-package="xyz.sample.barehibernate" />

So, it looks like it's using an embedded HQL data source, supports transactions, and scans the package for components.

Next, let's look at the source code the template wizard create. First, there's a class called "Hibernate Configuration" which ought to be interesting:

I'll add comments to show my guesses as to what the code means:



package xyz.sample.barehibernate;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.dialect.H2Dialect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;

@Configuration // this is used for configuration - not sure what that exactly means, but it's a java configuration vs. xml
// configuration
public class HibernateConfiguration {

@Value("#{dataSource}") // clearly pulling in the data source from app-context.xml.
private DataSource dataSource;

@Bean // A bean which will be scanned by the container
public AnnotationSessionFactoryBean sessionFactoryBean() { // method to generate an annotation-based Hibernate
// session, used by the container
Properties props = new Properties();
props.put("hibernate.dialect", H2Dialect.class.getName()); // set up the HSQL dialect to be used
props.put("hibernate.format_sql", "true"); // we like SQL

AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean(); // private instantiation
bean.setAnnotatedClasses(new Class[]{Item.class, Order.class}); // give it the classes to be "hibernated"
// this is the "magic" that saves mapping
bean.setHibernateProperties(props); // set the props
bean.setDataSource(this.dataSource); // set the data source
bean.setSchemaUpdate(true); // allow updates/
return bean;
}


// Give whoever needs the transaction manager the session factory bean decorated with the
// Hibernate transaction manager

@Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager( sessionFactoryBean().getObject() );
}

}




Now the domain classes, again with comments:

package xyz.sample.barehibernate;


import java.util.Collection;
import java.util.LinkedHashSet;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;


/**
* An order.
*/
@Entity // It's a domain object
@Table(name="T_ORDER") // here's the table name
public class Order {

@Id // this is the id
@GeneratedValue(strategy=GenerationType.AUTO) // and it should be auto-generated
private Long id; // make it a long

private String customer;

@OneToMany(cascade=CascadeType.ALL) // it can have many items
@JoinColumn(name="ORDER_ID") // here's the column name to join it on
private Collection items = new LinkedHashSet(); // and the list of items

// getters and setters

/**
* @return the customer
*/
public String getCustomer() {
return customer;
}

/**
* @param customer the customer to set
*/
public void setCustomer(String customer) {
this.customer = customer;
}

/**
* @return the items
*/
public Collection getItems() {
return items;
}

/**
* @param items the items to set
*/
public void setItems(Collection items) {
this.items = items;
}

/**
* @return the id
*/
public Long getId() {
return id;
}

}

// this is the order header

package xyz.sample.barehibernate;


import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
* An item in an order
*/
@Entity // It's a domain object (persistable)
public class Item {

@Id // see above
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@ManyToOne // many of these to one order
private Order order;

// pojo variables, getters and setters

private String product;

private double price;

private int quantity;

/**
* @return the order
*/
public Order getOrder() {
return order;
}

/**
* @return the product
*/
public String getProduct() {
return product;
}

/**
* @param product
* the product to set
*/
public void setProduct(String product) {
this.product = product;
}

/**
* @return the price
*/
public double getPrice() {
return price;
}

/**
* @param price
* the price to set
*/
public void setPrice(double price) {
this.price = price;
}

/**
* @return the quantity
*/
public int getQuantity() {
return quantity;
}

/**
* @param quantity
* the quantity to set
*/
public void setQuantity(int quantity) {
this.quantity = quantity;
}

/**
* @return the id
*/
public Long getId() {
return id;
}
}




So by a magic combination of scanning (to avoid coding the beans (and configuration?) in the spring beans file, a variety of annotations (Entity, manytoone, onetomany, id, generated value, and a hibernation configuration java class which uses the magic of reflection to set the properties, we have a full-blown hibernate system without mapping of specific fields.

Below is an example of how to utilize the data via some unit tests, aslo generated:


@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class OrderPersistenceTests {

@Autowired
private SessionFactory sessionFactory;

@Test
@Transactional
public void testSaveOrderWithItems() throws Exception {
Session session = sessionFactory.getCurrentSession();
Order order = new Order();
order.getItems().add(new Item());
session.save(order);
session.flush();
assertNotNull(order.getId());
}

@Test
@Transactional
public void testSaveAndGet() throws Exception {
Session session = sessionFactory.getCurrentSession();
Order order = new Order();
order.getItems().add(new Item());
session.save(order);
session.flush();
// Otherwise the query returns the existing order (and we didn't set the
// parent in the item)...
session.clear();
Order other = (Order) session.get(Order.class, order.getId());
assertEquals(1, other.getItems().size());
assertEquals(other, other.getItems().iterator().next().getOrder());
}

@Test
@Transactional
public void testSaveAndFind() throws Exception {
Session session = sessionFactory.getCurrentSession();
Order order = new Order();
Item item = new Item();
item.setProduct("foo");
order.getItems().add(item);
session.save(order);
session.flush();
// Otherwise the query returns the existing order (and we didn't set the
// parent in the item)...
session.clear();
Order other = (Order) session
.createQuery( "select o from Order o join o.items i where i.product=:product")
.setString("product", "foo").uniqueResult();
assertEquals(1, other.getItems().size());
assertEquals(other, other.getItems().iterator().next().getOrder());
}

}

Saturday, February 11, 2012

Spring Recipes, for Spring 2.5 - Chapter 1

So, I know this is a little out of date, but I think Spring Recipes for 2. 5 is the best Spring book out there. It doesn't cover 3.0, but you will definitely get the fundamentals down. Plus, I saw a review of the 3.0 book that said it was *huge*, and I really would rather keep things as streamlined a possible. I really want to nail down the fundamentals of Spring.

I previously went through the first five chapters (see previous entries in this blog), but it was a while ago. Now, I'm coming back to it using STS and Spring 3, so it will be a little bit strange. I'm not sure this is the best route to go, but I'm tentatively starting out on it.

So, without further ado, here's a review on chapter one.

Using a Container

Chapter one talks about containers. You start out simply enough, with a "ReportGenerator" interface that has the method "generate". Generate accepts statistics and generates a report. There are a couple of implementing classes - PdfReportGenerate and HTMLReportGenerator. One of them will print a pdf report, the other will implement an HTML report. All the report service has to do is instantiate whichever of the two it needs, and call "generate" and pass the statistics.

The problem is that, say your product services a couple of different organizations, one likes pdf reports, the other HTML reports. That means you have to go in and muck with your report generator for each different organization. So, really for separation of concerns - you don't want your "what is this organizations type of report" logic mixed in with the "how do I gather statistics" logic, something needs to be done.

You might initially think, well, let's just create a separate class that instantiates the report service, instantiates the concrete report generator class and sets the report generator class on the report service. But, possibly as a scalability issue, they suggest setting up a "container" with a map that holds an instance of the report service, an also an instance of the report generator. So, this generator will hang around with an instance of the report service and the report generator that any old class can grab and use.

So, the report service grabs the report generator from the container whenever it needs it, confident that the correct version of it has been been put in place by the container. Later on, too keep from mucking with the container, you can have the container read a configuration file for the correct report generator class.

But what grabs the report service from the container? Well, the way you would *initially* handle that (we're working our way through all this), is to create the container from a *main* class. The main class then grabs the report generator from the container, and calls something like "createAnnualReport(2007)". The report service will have that method, and will scurry about putting together whatever data it needs to create the annual report. Then, as mentioned earlier, the report service will grab whatever report generator is provided by the container, and call "generate(collected data) on it.

One detail we skimmed over was that when container is created, it puts a static reference to itself (this) into a static variable. This allows the report service to grab the static instance of container from the Container class. Main doesn't need to bother with that when it gets the report service because it instantiated the container.

Whew! That's actually fairly complicated. Just think of the Container as a cupboard full of goodies, which loads itself when instantiated. The main class- the user of the service - happily grabs the reports service from the cupboard (Container) (after instantiating it), and then uses that service.

The service just uses the cupboard (Container) to get *whatever* report generator is there. It gets the that, then calls the report generator method.

Using a Service Locator.

That's all well and good - but what if the cupbard/container varies by organization? Some use one server, some use another, perhaps. If you're writing this framework, do you want to have the code to get the Container (from the report service) vary, depending on how the container is created? According to the book, this could be "complex, proprietary code." Actually, I wish they gave a better example of this problem. It probably has something to do with the fact that it wouldn't make sense for each use of the service to create it's own container - why have a bunch of cupboards (fleeting though they may be) when you can just have one? I'm kind of guessing here, it's a working hypotheses.

So, you've got to look up the cupboard - find it somewhere on the system. Probably that varies depending on the system. And we don't want random services, such as the report service, to have to be responsible for this. It doesn't want to change every time it's on a new system.

So, we separate out the container/cupboard lookup logic into a separate class - the service locator bunny class. This is all about separation of concerns, reducing dependencies, etc. So, instead of having the Report Service grab the report generator directly from the container, we have it do something like "ServiceLocator.getReportGenerator();" And inside the ServiceLocator bunny, it will have method like:

private static Container = Container.instance

and a method which returns the report generator after grabbing it from the cupboard. So, the Service Locator will handle all the work of figuring out where the container is.

Inversion of Control / Dependency Injection

Although we've gotten rid of a specific dependency by providing a container for the Report Service to grab its ReportGenerator from, and even removed the need of the Report Service be concerned about how to implement lookup by giving it a Resource Locater which handles that work - we can make Report Service even dumber. After all, all this was all about was getting the correct instance of the report generator to the report service. So, why not just give report service a setter method for the report generator? No lookup whatsoever in your Report Service! This is good stuff, right?

So, now the container becomes more than just a cupboard. She becomes old Mother Hubbard, giving little Report Service the right instance of the Report Generator and sending her off to school. Mother Hubbard / Container can also now reduce her exposure by no longer providing access to "this".

Note that there are several ways to do injection - setter (via a set method), construction (via - you guessed it - construction) and interface (not widely used).

Adding a Configuration File.

Ok, now that we've set up all these principals, we really ought to make the whole thing configurable. So, what can we configure, and how?

For sure, we can define the pdf or html instance of the report generator. We give it a name that the container can refer to it with, and also the actual class name:

reportGenerator=com.apress.springrecipes.report.PdfReportGenerator

Come to think of it, we can also specify the report service:

reportService=com.apress.springrecipes.report.ReportService

Anything else...hmmm,,,,

Ah - what about which classes get injected where? We gotta let old mother Hubbard, our container/cupboard, know this:

reportService.reportGenerator=reportGenerator

Nice.

Then, the book shows a slick implementation of the Container class. I *think* there might be typo on Dependency Injection part - it seems like "value" should be "parts[1]" on a certain line. I haven't tested it though.

Good tutorial on maven, spring

Well, our hopes for a quick attack on Spring 3.0 have been somewhat dashed by an apparent bug in the template generation for an MVC app - although we did luckily manage to get one up and running, which I've carefully preserved.
(note - this was fixed by just doing a "clean" on the project).

The tutorial did give a pom.xml file at the end - and I'm wondering if it's possible to use a war file generate from that successfully create multiple mvc apps.

Maven is something I've never really had a chance to get into, so I took this as an opportunity to learn a *little* bit about it.

This is a tutorial I landed upon:

http://pookey.co.uk/wordpress/archives/50-getting-started-with-maven-and-spring

I actually got the whole thing to work, start to finish.

The first thing your supposed to do is this command:

mvn archetype:generate --batch-mode \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DgroupId=uk.co.pookey.spring \
-DartifactId=spring-hello \
-Dversion=1.0-SNAPSHOT

When you run it from the command line, get rid of the backslashes and put it all on the same line. It turns out when you run it, because you're specifying the archetype, it's based on some kind of super-pom that specifies a lot of files.

It also creates a source and build file structure, and a program called App.java, which looks like this:


package uk.co.pookey.spring;

public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}


My theory is that the "hello world" app is part of the archetype template. So, you just get this nice vanilla directory structure with a hello world app built in.

The directory created gets its name from DartifactId=spring-hello

it also creates a file called pom.xml, as well as src and target directories.

Here's the path of the App.java: src/main/java/uk/co/pookey/spring/App.java

In order to get the App.java to work, you need to add this to your pom.xml:


<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>

<configuration>
<mainClass>uk.co.pookey.spring.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>

This makes this command possible:

mvn exec:java

which will execute the java class.

But first, you need to compile it:


$ mvn compile

Then run:

$ mvn exec:java


It you'll see the "Hello" message.


This is fine for creating a standard product structure, but we're trying to learn a little bit of spring too.

Well, this example does that for us. First it specifies in pom.xml a dependency on the spring container:


<dependencies>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.5</version>
</dependency>
</dependencies>


I turns out there's a huge, searchable archive of maven dependencies here:

http://www.mvnrepository.com/

But, this is the one where we are getting our version from:

http://www.mvnrepository.com/artifact/org.springframework/spring


This is the strength of maven - it just knows what the version numbers of the jar files you need are, automatically - since you specified them in the first place. It also pulls down any spring dependencies.

Next we create a new pojo in src/main/java/uk/co/pookey/SayHello.java:

package uk.co.pookey;

public class SayHello
{

private String name;

public void setName(String name)
{
this.name = name;
}

public String getName()
{
return name;
}

public void greet()
{
System.out.println("Hello " + getName());
}

}

This can accept a dependency injection of name, which is printed out later on.

Next we create the famed bean configuration file:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="hello" class="uk.co.pookey.SayHello">
<property name="name" value="Pookey" />
</bean>
</beans>


This is going to be placed in src/main/resources/application-context.xml. You need to create the resources directory.

Finally, we see an example of dependency injection:



package uk.co.pookey.spring;

import uk.co.pookey.SayHello;

import org.springframework.core.io.ClassPathResource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;

public class App
{
public static void main( String[] args )
{
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("application-context.xml"));

SayHello hello = (SayHello) factory.getBean("hello");
hello.greet();
}
}



The app class pulls the hello bean from the XMLBeanFactory and calls "greet" on it. The factory has already taken care of setting the name to "Pookey" based on the configuration.

Just type "mvn clean compile exec:java" from the directory level of the pom.xml, and you see the "hello, Pookey" result.

To summarize, we've figured out how to create a simple hello world app using maven and spring, even bringing in some dependency injection. You can create a project from out of nowhere using maven from the command line. It uses an archetype that it finds in the cloud and downloads a bunch of jars and creates your directory structure. We added a couple of entries to allow us to execute the program, as well as introduce a dependency on Spring 2.5. We also added the bean configuration file to specify the dependency.

The next question is, how to we import the into an IDE like STS? We'll tackle that in a subsequent post.