Saturday, January 25, 2014

Adding log4j to your Spring application

If you want to add log4j to your application, here's one way to do it:

First, add the log4j dependency. With gradle, it looks like this:

   compile 'log4j:log4j:1.2.16'

You can find the entries for maven, ivy etc. from this url:

http://mvnrepository.com/artifact/log4j/log4j/1.2.16

Then, you have to either add log4j.properties or log4j.xml to your src/resources folder.

For example, here's one created by the spring mvc project creation wizard in STS:

<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
</layout>
</appender>
<logger name="com.kanjisoft.mvcapp">
<level value="info" />
</logger>
<logger name="org.springframework.core">
<level value="info" />
</logger>
<logger name="org.springframework.beans">
<level value="info" />
</logger>
<logger name="org.springframework.context">
<level value="info" />
</logger>

<logger name="org.springframework.web">
<level value="info" />
</logger>

<root>
<priority value="warn" />
<appender-ref ref="console" />
</root>
</log4j:configuration>

Note how the spring packages are conveniently included. If you want to see them, simply change those ones to "debug". 

References: 
http://www.mkyong.com/spring-mvc/spring-mvc-log4j-integration-example/
http://mvnrepository.com/artifact/log4j/log4j/1.2.16xml version="1.0" encoding="UTF-8"?>



Java client for posting to a Spring restful service

In my last post, http://mcdspringblog.blogspot.com/2014/01/posting-to-restful-service-from-spring.html, I talked about a Java client for retrieving a JSON object from a Spring-based, restful web service In this post, let's discuss how to use the same approach to post a JSON object to the same service.  Again, the client code is based on this post:

http://www.mkyong.com/webservices/jax-rs/restfull-java-client-with-java-net-url/


First, here's the service:

@RequestMapping(value="person3", method=RequestMethod.POST)
@ResponseBody
public Person postPerson(@RequestBody Person person) {
System.out.println("posting " + person.toString());
personService.save(person);
return person;


}

Note how it returns an object in the body of the response (JSON format).

Now let's create the client:

package com.codetutr.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import com.codetutr.domain.Person;
import com.google.gson.Gson;

public class NetClientPost {

// http://localhost:8080/api/person/random
public static void main(String[] args) {

 try {


URL url = new URL("http://localhost:8081/spring-mvc-ajax-master/api/person3");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
Person person = new Person();
person.setName("John Smith");
person.setAge(33);


String input = new Gson().toJson(person, Person.class);

OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();


BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));

String output;
System.out.println("Output from Server .... \n");
StringBuilder sb = new StringBuilder();
while ((output = br.readLine()) != null) {
System.out.println(output);
sb.append(output);

}


   Gson gson = new Gson();
   Person returnedPerson = gson.fromJson(sb.toString(), Person.class);
   System.out.println("returned person.name: " + returnedPerson.getName() + ", returned person.age: " + returnedPerson.getAge());
 

conn.disconnect();


 } catch (Exception e) {

System.out.println(e.getMessage());
e.printStackTrace();

 }

}

}

And here's the output:

Output from Server .... 


{"name":"John Smith","age":33}


Notes:

I initially got a "415" message from the server, media type not supported. Again the TCP Monitor from eclipse/STS came to the rescue (see my previous post on this). It showed the content-type was getting posted as url-encoded, as opposed to application/json. So, I just added this line:

conn.setRequestProperty("Content-Type", "application/json");

to the client, and we're good.

Tuesday, January 21, 2014

Java client for retrieving a JSON object from a Spring restful service

I recently have been blogging about creating and using restful services in spring, e.g. "http://mcdspringblog.blogspot.com/2014/01/submitting-json-via-jquery-to-restful.html"

So, we know how to create the restful service, using the @RequestBody and @ResponsBody annotations, and how to call it from jQuery. But, what if we want to call it from inside some Java code?

To keep it as simple as possible, we'll use this service to call:

@RequestMapping("person/random")
@ResponseBody
public Person randomPerson() {
return personService.getRandom();

}

After some googling around, it seems that the simplest solution is to use java.net's HttpUrlConnection. We can use that to retrieve the json string from the request, and then convert it to a Person object using Google's Gson. Here's an modified version of a sample client found at http://www.mkyong.com/webservices/jax-rs/restfull-java-client-with-java-net-url/

package com.codetutr.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import com.codetutr.domain.Person;
import com.google.gson.Gson;

public class NetClientGet {

// http://localhost:8080/api/person/random
public static void main(String[] args) {

 try {

URL url = new URL("http://localhost:8080/spring-mvc-ajax-master/api/person/random");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");

if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}

BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));

String output;
System.out.println("Output from Server .... \n");
StringBuilder sb = new StringBuilder();
while ((output = br.readLine()) != null) {
System.out.println(output);
sb.append(output);
}

   Gson gson = new Gson();
   Person person = gson.fromJson(sb.toString(), Person.class);
   System.out.println("Person.name: " + person.getName() + ", person.age: " + person.getAge());
   
conn.disconnect();

 } catch (MalformedURLException e) {

e.printStackTrace();

 } catch (IOException e) {

e.printStackTrace();

 }

}

}

And the output:

Output from Server .... 

{"name":"Robert Ford","age":16}
Person.name: Robert Ford, person.age: 16


Btw, in order to add Gson to the project, I added this line to the gradle build:

   compile 'com.google.code.gson:gson:2.2.4'

Then from the command line, ran this command:

gradle eclipse

Then refreshed the project, then ran a clean and build from STS/Eclipse. Note that I had to do a clean before the build worked correctly.



Wednesday, January 15, 2014

Submitting JSON via jQuery to a restful Spring web service

In one of my recent posts, "Creating a restful JSON web service which sends and receive objects", I talked about a Spring web service which accepts and returns its response as JSON objects.

The Spring-based controller code looks like this:

@RequestMapping(value="person3", method=RequestMethod.POST)
@ResponseBody
public Person postPerson(@RequestBody Person person) {
personService.save(person);
return person;

}

As you can see, it uses both the @RequestBody and @ResponseBody tags to ensure data is both sent and received as JSON. 

This whole experiment was based on a tutorial I was reviewing, http://codetutr.com/2013/04/09/spring-mvc-easy-rest-based-json-services-with-responsebody/, which demonstrates how to use ajax in the client with restful spring services. However, the @ResponseBody example was only mentioned in the example section, and the client was tested using curl as opposed to a jQuery form.

I was curious about how to fill that gap (post JSON from a jQuery form). The ultimate goal was to submit a form which had JSON sent in the body instead of the url-encoded typical query string - i.e. 

{"name":"e","age":"4"}

and not: 

name=e&age=4

The form returned should reflect the name submitted, just as was done with the regular, non-json-encoded post:


So I experimented a little bit and here's the commented code:

// Save Person AJAX Form Submit
$('#newPersonForm').submit(function(e) {
var $this = $(this)  // convert the form to a regular variable (?) 
var obj = form_to_obj($this) // convert it to a javascript object 
var data = JSON.stringify(obj) // here's the magic;  convert the javacript object to JSON 

// I used a generic ajax post here - it was really to ensure the application type is JSON
// I'm sure there are other ways. But it is a nice way to ensure that a) you're posting in ajax and
// b) the block format is easy to follow

$.ajax({
    type: "POST",
    url: "${pageContext.request.contextPath}/api/person3",
    // The key needs to match your method's input parameter (case-sensitive).
    data: data,
    contentType: "application/json; charset=utf-8",
    dataType: "json",

    // the success function takes the response object, which is a person,
   // and writes it to the page
    success: function(person) {  // the response is returned as a javascript object
$('#personFormResponse').text(person.name + ", age: " + person.age);
},
    failure: function(errMsg) {
        alert(errMsg);
    }
});
e.preventDefault(); // prevent actual form submit and page reload
});
});

// function I grabbed from SO to convert to an object
function form_to_obj (selector) {
  var ary = $(selector).serializeArray();
  var obj = {};
  for (var a = 0; a < ary.length; a++) obj[ary[a].name] = ary[a].value;
  return obj;

}

That's about it. I should note that it was invaluable to use the TCP / IP Monitor to see what was being submitted. It helped me to figure out the following bugs:

1) I was submitting a url-encoded query string instead of JSON. 
2) I was getting 400 bad input error - it turned out I was using a function that didn't have the @RequestBody tag
3) I was getting an invalid media type - I had to set the content to application/JSON

You can see in the TCP/IP monitor output below how the submit is including the JSON object in the body. Also, in the response it receives data as JSON. Since the content type is JSON, its's automatically converted to a JSON object for the browser.  











Saturday, January 4, 2014

JQuery, JSON, restful services and Spring MVC - a simple introduction

Knowing how jQuery and css works in the context of a web page is a must-have skill for any web developer. I recently came across a tutorial which has a nice usage of jQuery in its page.  This is the link:

http://codetutr.com/2013/04/09/spring-mvc-easy-rest-based-json-services-with-responsebody/

The page looks like this: 




Here's the page source, with my comments, (I'll use a "//", although it's not valid for html - and supplements the author's own comments in the jQuery). 

// import the jstl taglib
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

// import spring form tag library
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE HTML>
<html>
  <head>
    <title>Spring MVC - Ajax</title>

// import jquery library
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <style>

// css - define the background / font for the body
    body { background-color: #eee; font: helvetica; }'

// define container properties
    #container { width: 500px; background-color: #fff; margin: 30px auto; padding: 30px; border-radius: 5px; box-shadow: 5px; }

// "green" class
    .green { font-weight: bold; color: green; }
    .message { margin-bottom: 10px; }

// set up error display
    label { width:70px; display:inline-block;}
    .hide { display: none; }
    .error { color: red; font-size: 0.8em; }
    </style>
  </head>
  <body>
<div id="container">
<h1>Person Page</h1>
<p>This page demonstrates Spring MVC's powerful Ajax functionality. Retrieve a
random person, retrieve a person by ID, or save a new person, all without page reload.
</p>
<h2>Random Person Generator</h2>

// submit to restful service at "person/random" - see jQuery script 
<input type="submit" id="randomPerson" value="Get Random Person" /><br/><br/>

// div to hold the person returned - written to by jQuery code below
<div id="personResponse"> </div>
<hr/>


<h2>Get By ID</h2>

// form to retrieve by id
<form id="idForm">
<div class="error hide" id="idError">Please enter a valid ID in range 0-3</div>
<label for="personId">ID (0-3): </label><input name="id" id="personId" value="0" type="number" />
<input type="submit" value="Get Person By ID" /> <br /><br/>

// area to show person retrieved
<div id="personIdResponse"> </div>
</form>
<hr/>

// new person form
<h2>Submit new Person</h2>
<form id="newPersonForm">
<label for="nameInput">Name: </label>
<input type="text" name="name" id="nameInput" />
<br/>
<label for="ageInput">Age: </label>
<input type="text" name="age" id="ageInput" />
<br/>
<input type="submit" value="Save Person" /><br/><br/>
<div id="personFormResponse" class="green"> </div>
</form>
</div>
<script type="text/javascript">
$(document).ready(function() {

// Random Person AJAX Request
$('#randomPerson').click(function() {

// this is an ajax call - will make a request like this:
// GET /spring-mvc-ajax-master/api/person/random
// Accept: application/json, text/javascript, */*; q=0.01

$.getJSON('${pageContext.request.contextPath}/api/person/random', function(person) {

// set the fields in the web page based on the response
$('#personResponse').text(person.name + ', age ' + person.age);
});
});

// Request Person by ID AJAX

// called on idForm click
$('#idForm').submit(function(e) {

// grab the person's id
var personId = +$('#personId').val();

// validate it
if(!validatePersonId(personId)) 

// invalid - don't propagate the submit and exit by returning false
return false;

// Get the person, this time doing  a ".get". It still receives JSON back,
// although the accept header doesn't specify JSON
// On the wire, it looks like this:

// GET /spring-mvc-ajax-master/api/person/3
// Accept: */*

// Apparently the Jackon handler defaults to JSON,
// Therefore the response can be parsed in the same
// manner as in the above method.
$.get('${pageContext.request.contextPath}/api/person/' + personId, function(person) {
$('#personIdResponse').text(person.name + ', age ' + person.age);
});
e.preventDefault(); // prevent actual form submit
});


// Save Person AJAX Form Submit
$('#randomPerson').click(function() {
$.getJSON('${pageContext.request.contextPath}/api/person/random', function(person) {
$('#personResponse').text(person.name + ', age ' + person.age);
});
});
$('#newPersonForm').submit(function(e) {
// will pass the form data using the jQuery serialize function
// Because it's a post, the data will be passed in the body.

// The serialize function creates a standard URL-encoded string:
// e.g: "name=Tom+Jones&age=57"
// The $(this) must refer to the form which was submitted by clicking on the submit button.

$.post('${pageContext.request.contextPath}/api/person', $(this).serialize(), function(response) {
$('#personFormResponse').text(response);
});
e.preventDefault(); // prevent actual form submit and page reload
});
});

// Neat function which uses label properties as a method to activate them, e.g. show/hide errors.
function validatePersonId(personId) {
console.log(personId);
if(personId === undefined || personId < 0 || personId > 3) {
$('#idError').show();
return false;
}
else {
$('#idError').hide();
return true;
}
}
</script>
  </body>
</html>



Thursday, January 2, 2014

Creating a restful JSON web service which sends and receive objects

I recently wanted to create a restful JSON web service which was able to both receive and return regular java objects.

I was curious how to do it using the @RequestBody and @ResponseBody annotations, since this seemed like the most straightforward approach. Luckily, I found a nice link which basically explains the whole process, and adds in some Javascript for good measure. Here's the link:

http://codetutr.com/2013/04/09/spring-mvc-easy-rest-based-json-services-with-responsebody/

Although the code posted doesn't include using both annotions in the same method, it is explained in the comments section. I implemented it as follows:

@RequestMapping(value="person", method=RequestMethod.POST)
@ResponseBody
public Person postPerson(@RequestBody Person person) {    
    System.out.println("posting " + person.toString());
    personService.save(person);
    return person;


}

Note how both the input and output parameters are Java objects. This serialization to and from JSON in made possible by the inclusion of a jackson-mapper jar file in the classpath. Also, annotations must be turned on, and the request from the application must include a header indicating it's expecting JSON. See the posted link for more details. 

Seeing what the spring container does without walking through the debugger.

If you're curious about what spring is doing, but don't want to walk through the source code as it's executing, one way to do it is to set the debug level for various spring components. For example, the Spring MVC template on STS creates a "log4j.xml" file under "src/main/resources".  All the default levels are set to "info".

However, you can change them to "debug" and you will see a lot more information from the console. For example, if you set the org.springframework.web to "debug", like so:

<logger name="org.springframework.web">
<level value="debug" />

</logger>

you can see the logic of the Spring MVC in action.

DEBUG: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/mvctest/]
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public java.lang.String com.acme.mvctest.HomeController.home(java.util.Locale,org.springframework.ui.Model)]
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'homeController'
DEBUG: org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/mvctest/] is: -1
INFO : com.acme.mvctest.HomeController - Welcome home! The client locale is en_US.
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'home'
DEBUG: org.springframework.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'home'; URL [/WEB-INF/views/home.jsp]] in DispatcherServlet with name 'appServlet'
DEBUG: org.springframework.web.servlet.view.JstlView - Added model object 'serverTime' of type [java.lang.String] to request in view with name 'home'
DEBUG: org.springframework.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/views/home.jsp] in InternalResourceView 'home'

DEBUG: org.springframework.web.servlet.DispatcherServlet - Successfully completed request


Wednesday, January 1, 2014

The incredibly useful TCP Monitor in STS/Eclipse

I was recently working on a project that posted JSON objects from a java client to PHP server. I really needed to see what the HTTP headers and data looked like. I know that you can use the browser debuggers to view the requests and responses, but these are formatted. I find it really helpful to see the data just as it appears.

To view the monitor in STS (and presumably Eclipse), select "window", "show view", "other", "debug", and choose "TCP/IP Monitor".

You'll see a display tab that says "TCP/IP Monitor".  Next click on the tiny, upside-down triangle off to the right, select "show header", and then and select "properties".  This brings up a display box where you add the normal server port on the left (e.g. localhost:8080), and the "proxy" local port on the right (e.g. localhost:9111). Start it by clicking the "start" button, and the TCP/IP monitor will now forward any requests to port 9111 on to port 8080 and show you the http request and response.

For example, if I enter this url:

http://localhost:9111/spring-mvc-ajax-master/

instead of the one I normally would use, "http://localhost:8080/spring-mvc-ajax-master/", I get the display below, which shows me the headers and data for both the request and response.






Tuesday, December 31, 2013

Another way to get around the Spring MVC 404 exception

A lot of applications are set up without a default for displaying a home page - even if they have one. This (excellent) tutorial is a case in point:

http://codetutr.com/2013/04/09/spring-mvc-easy-rest-based-json-services-with-responsebody/

I managed to get it running in eclipse, but of course I got the page not found, 404 exception. With my recent research, however, I didn't feel quite as helpless as I usually do when faced with this. After checking out my last post, I realized what was lacking in this application was a default request mapping - i.e.


@RequestMapping({"/","/home"})

Since it came with a "home.jsp" already, I just copied a method from the STS-generated springMVC app:

public String home(Locale locale, Model model) {

      return "home";

}

If there wasn't a home.jsp there already, I could have copied one into WEB-INF/views from the generated project. 

Here's the page:



How to debug STS's SpringMVCProject template

I've recently decided to get more into learning Spring again, this time from an MVC angle. From time to time, I've tried to create a spring mvc project from spring's IDE, STS.  For me,  it's been very unreliable, always coming up with "404" exceptions. 

So, I'm going to do it again, with the idea to debug any issues based on what I've learned. First, go to STS, click File > New > Spring Template Project, then choose "Spring MVC Project" as the template.  After that, give it a name like "mvcTest" and a package name like "com.acme.mvctest". Build it and run it on the server. 

Of course, when I try it now, it works perfectly. But, before I was having issues with it, I promise. Specifically. a 404 page not found message for "http://localhost:8080/mvctest/". 

Also, in the log would be a message something along the lines of: 
"WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/mvctest/] in DispatcherServlet with name 'appServlet".

To fix it, I had to be sure of a couple of things:

1) the url mapping in web.xml needs to be "/", e.g.

<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>


2. Check the @RequestMapping annotation in the controller.  

It should: 

"@RequestMapping({"/","/home"})," 

because, since "home" is returned, it's looking for {apppath}/home.jsp per the view resolver.  But the controller is defaulting to this: 

"@RequestMapping(value = "/", method = RequestMethod.GET)"

So it's not finding  a mapping to "home" unless you put it in, usually. In this case it did for some reason.

On a side note, I ran into a problem trying to debug the 404 message when I put in "/*" as the servlet url mapping.  After a lot of checking around, I found this post in stackOverflow:

http://stackoverflow.com/questions/1266303/no-mapping-found-for-http-request-with-uri-web-inf-pages-apiform-jsp

Basically, the view dispatcher was correctly retuning the jsp page requested, but the '/*' meant the forwarded view was captured by DispatcherServlet as if it were a request! Since there's no handler specified, it came up with "No mapping found" 404 error. 

Another problem I ran into was some code which didn't include a method with 
"@RequestMapping(value = "/", method = RequestMethod.GET)" annotation. So, I just added one, and it worked, defaulting to that page and avoiding a 404 issue when first deploying it.  

So, that's my takeaway lesson. Always have a

"@RequestMapping(value = "/", method = RequestMethod.GET)"

in then controller, and map the Dispatcher servlet to the url "/" in web.xml.  Or, at least map to a url which won't get confused with .jsp, such as "*.do" or "*.htm".







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.