Thursday, July 10, 2008

Errata for Hibernate Made Easy: Simplified Data Persistence with Hibernate and JPA Annotations

So, I've got some great feedback from readers over the past month or so with regards to my Hibernate3 book. Not too many errors, a few typos, and lots of great suggestions. Seriously, the Java community is so awesome with regards to helping each other out. It makes the whole process very rewarding!

I'm going to just post some of the feedback here, in no particular order for now, just so I can get it out there. So, here goes!



**********************
(From TUN)
Book: Hibernate Made Easy
Page: 137
In chapter 5, the code for the improved version of the User class using HibernateUtil doesn't compile. I had to add the following line of code to work.

import

com.examscam.HibernateUtil;

Tun.

(I believe this was fixed in the second printing)


***********************************

More from Tun

Hi,
There was something in the book that made me scratch my head. I had to spend about 40 minutes to figure this out. (I am talking about the very first printing edition of Hibernate Made Easy book.)
On page 41, you recommended to install JDK 1.5 or higher. On page 75, you gave an example on compiling the User.java class using "javac -classpath "c:\_hiblib\*" User.java". What I found was that the wildcarding "*" the classpath is JDK 1.6 feature. It's not supported on JDK 1.5. Since I had JDK 1.5, it wasn't working for me. After I upgraded to JDK 1.6, it all worked fine. Just wanted to let you know.
Tun.

I still haven't figured this out for Java5...Maybe someone can give me the right compiler syntax?

***********************************
Book: Hibernate Made Easy
Edition: Very First Printing
On page 223, the code for the abstract ExamScamDAO class has the "import com.examscam.ExamScamException;" statement. Up to page 223, I couldn't find any reference or definition of com.examscam.ExamScamException. Also, the code works fine without the import statement. So I assume it's a typo.

Yup...Again, I believe I fixed this for the second printing. :( See what happens when you play around with ideas when you're writing a book. This should just be a warning, not a compile error.

***********************************
From Tun - this guy rocks!

On page 257, the code for user.jsp, on line 3 it says
contentType="text/html;
It should be
contentType="text/html"
Semicolon should be replaced with double quotes.


***********************************
On the same page,on line 10, the code is instantiating the interface UserDAO.
Currently,
UserDAO userDAO = new UserDAO;
Should be
UserDAO userDAO = new HibernateUserDAO;

user.jsp is a pretty neat example. I learned a lot. Thanks.

This is actually a REAL code error. Tun wouldn't take the $100 reward. I am sending him some signed copies of the next update, not to mention a thank you in the print as well. Great guy!
***********************************

I never promised to help deploy a web app in my Hibernate Book. I leave that to the Sevlet and JSP books out there. But Tun did provide some guidance, saying:

"I really appreciate this user.jsp example. One other thing on the example. I had to copy standard.jar and jstl.jar files to my WEB-INF/lib directory. I am not sure what I did was the standard way. But I got it working."

So, you many need the standard.jar and jstl.jar files to deploy this application to Tomcat.

"Regarding the jstl issue I had, I am running Tomcat 5.5.26. When I tried to bring up user.jsp, Tomcat complained about not being able to resolve the uri=http://java.sun.com/jsp/jstl/core. I found my solution at http://forum.java.sun.com/thread.jspa?threadID=764807&messageID=4362177."

***********************************
Amit Anand saved my but on these ones...You need to make a few changes to actually get the Inheritance Mapping to run. It's not a compile error, but it is a showstopping runtime omission.

Working through the chapter on mapping inheritance

If you use
@Id
@GeneratedValue

With
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
On the Ancestor class

Throws the following error

Cannot use identity column key generation with mapping for: com.anand.hibernatesample.domain.Parent

I got around this as follows

public Class Ancestor
{
@Id
@org.hibernate.annotations.GenericGenerator(name = "hibernate-uuid",
strategy = "uuid")

@Column(name = "ancestor_id")
private Long id;

....

}

I am Using MySQL (maybe a different version from yours) Actually, the SchemaExport throws the error when you try to run it as is from the book and I have seen various people posting this error on hibernate forums - cannot use the native Id generator with the TABLE_PER_CLASS strategy. If you paste the actual error message I pasted below and do a google search - you will see what I mean (just do a google search on

Cannot use identity column key generation with mapping for
)


***********************************
Alex Fanti was kind enought to help me with some typos in the prose:

Pg 16-80 (even) header
Pg 17 Line 1
Pg 22 PP 2 Line 4
Pg 52 PP 3 Line 4
Pg 90 PP 3 Line 1

Pg 98 Line 1
Pg 158 PP 2 Line 6
Pg 193 Line 6
Pg 196 Line 2
Pg 215 Line 2

Pg 217 Line 3-4
Pg 293 PP 3 Line 4
Pg 314 PP 2 Line 3
Pg 323 Section Header
Pg 356 Section Header

***********************************
Jim Dewberry helped me here:

I found a small typo and thought I'd pass it along in case nobody else did already.
On the last line on page 54 you spelled "compiled" as "comiled".


***********************************
Robert de B├ęsche had this great find that nobody else noticed!

In the image on page 385 (showing the database structure for chapter 20 -Advanced Mappings) of your Hibernate book there is what seems to be a strangely named property in the ‘address’ table listing. The column of ‘address’ mapping addresses to clients is named “insider_id”. I would have expected this to be “client_id” as the @JoinColumn annotation specifies in the listing on page 379? Is it an error, or am I missing something?

No, you're not missing anything Robert....That was me who messed up. Thanks!
***********************************
Jim Dewberry added some more:

I found a few little typos you might want to fix. On page 90 right underneath the "Persistent Objects" header, the sentence says "Once a JavaBean has touched by the Hibernate Session," and I think you might want to add the word "been" so that it reads "Once a JavaBean has BEEN touched by the Hibernate Session".
Also, the first sentence on line 98 says "You will also notice that I have set they type attribute" and I think you probably meant to say "set THE type attribute" instead.

Also, page 106, line 2: "It is completely up to the you" should be "It is completely up to you"
Also, page 140, line 1 "one of the thing you might have noticed" should be "one of the thingS you might have noticed"
page 163, first line of 2nd paragraph: "Once you being a transaction" should be "Once you begin a transaction"
Also, I found a small coding error. There's a missing quote on page 257. On line 3 the contentType="text/html is missing the end quote.
Also, I didnt feel like typing out all the code for creating sample data for the Criteria examples, so I wrote a little class that generates sample data. Feel free to use it or to offer it to other readers if you could just give me credit. I attached a zip file with the java code.



***********************************
Andrej didn't like my naming of banks in my example. It's good, solid, feedbac:

On page 299 of your book towards the bottom of the " public classInterest", you have:
Long wayne=new Long(99); Long mario=new Long(88);
mario is not a bank name, and I think that is what you want to describe. Should have a bankname variable, e.g, firstNationalBank etc. Same correction needed on page 300.

Sometimes, when you're up late at night, you start doing things that keep your mind interested. 88 and 99 are obviously Mario Lemiuex and Wayne Gretzky's jersy numbers, but alsa, maybe it doesn't help the learning process. I'll mark that for an update.
***********************************
Ademiju also notice the mistake on the DAO, along with a few other errors in the prose. Thanks Ademiju!

1. The most important one is on page 256/257, the fact that you have instantiated an interface.

UserDAO userdao = new UserDAO();

2. Page 274. In the last past paragraph you mentioned that foo table is the primary mapping table and bar will be the secondary but it seem to have swapped around in your sample code below it.

3. Page 146, at the start of the first Paragraph, should this say “With our” instead of “With out”?

***********************************

Well, that's it for now!

***********************************





Jim's Sample Code Class for everyone:

package com.examscam;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Random;

import org.hibernate.Query;
import org.hibernate.Session;

import com.examscam.model.User;

public class SampleData {

private static final String alphanumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final String[] domains = {"@Yahoo.com", "@Hotmail.com", "@Gmail.com"};
private static final String[] names = {
"Mary", "Joe", "Tom", "Sally", "Sallie", "Jim", "Tim", "Bill", "Brad", "Damian",
"Katrina", "Shelley", "Shannon", "Amie", "Cathy", "Kathy", "Elizabeth", "Blake",
"Peggy", "Sabrina", "Samantha", "Chris", "Matt", "Vince", "Bran", "Megan", "Sean",
"Jillian", "Chrissi", "Mike", "Matthew", "David", "Jeff", "Shelly", "Sherra",
"Robin", "Curtis", "Lev", "Andrew", "Richard", "Derrick"
};

public static void main(String[] args){

deleteAll();
for (int i = 0; i < 20; i++){
createSampleData();
}
}

public static void deleteAll(){
Session session = HibernateUtil.beginTransaction();

List allUsers;
Query queryResult = session.createQuery("from User");
allUsers = queryResult.list();

for (int i = 0; i < allUsers.size(); i++){
User user = (User)allUsers.get(i);
session.delete(user);
}

HibernateUtil.commitTransaction();
}


public static void createSampleData(){

User u = new User();

u.setEncryptedPassword(createPassword());
u.setRegistrationDate(createDate());
u.setLastAccessTime(createDateTime(u));
u.setLoginName(createName());
u.setPassword(createPassword());
u.setVerified(createRandomBoolean());
u.setEmailAddress(createEmailAddress(u));

Session session = HibernateUtil.beginTransaction();
session.saveOrUpdate(u);
HibernateUtil.commitTransaction();
}

private static java.util.Date createDateTime(User u){

java.util.Date accDate = generateDateTime();
java.util.Date regDate = convertCalendarToDate(u.getRegistrationDate());

while (regDate.after(accDate)){
accDate = generateDateTime();
}
return accDate;
}

private static java.util.Date convertCalendarToDate(Calendar cal){

java.util.Date date = null;
date = new Date(cal.get(Calendar.YEAR)-1900, cal.get(Calendar.MONTH), cal.get(Calendar.DATE));
return date;
}

private static java.util.Date generateDateTime(){

Random generator = new Random();
java.util.Date date = null;

int month = generator.nextInt(12) + 1;
int day = generator.nextInt(30) + 1;
int year = generator.nextInt(3);
int hour = generator.nextInt(24);
int minute = generator.nextInt(60);
int second = generator.nextInt(60);

int[] yearChoices = {2006,2007,2008};

int dateYear = yearChoices[year]-1900;

while ( (month == 2) && (day > 28) ){
day = generator.nextInt(30) + 1;
}

date = new Date(dateYear, month, day, hour, minute, second);

return date;
}

private static java.util.GregorianCalendar createDate(){
Random generator = new Random();
int days = generator.nextInt(1000);

GregorianCalendar cal = new GregorianCalendar();
cal.add(Calendar.DATE, -days);
cal.getTime();

return cal;
}

private static String createPassword(){
StringBuffer result = new StringBuffer();
Random generator = new Random();
int pos = 0;

for (int i=0; i< 6; i++){
pos = generator.nextInt((alphanumeric.length()-1));
result.append( alphanumeric.charAt(pos) );
}

return result.toString();
}

private static String createEmailAddress(User u){

Random generator = new Random();
int pos = generator.nextInt(3);

String user = u.getLoginName();
String domain = domains[pos];

return user+domain;

}

private static String createName(){

Random generator = new Random();
int sizeOfNames = names.length;
int pos = generator.nextInt(sizeOfNames);
return names[pos];
}

private static Boolean createRandomBoolean(){
Random generator = new Random();
if (generator.nextInt() % 2 == 0){
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}

No comments: