A few tips for aspiring java developers out there.
Let's say I write you a specification and I say that I need a method, public Foo write(Foo f). This means that I want you to write a method that persists a Foo object, f, to the database, and returns me the same object, only with the id set.
Here is how NOT to write it:
First, you're giving me a boolean response. True or false. That's not what I asked for. The reason I want the Foo object back is so that I can reference its ID later in the game.
Second, if the lack of the "Name" field is going to cause the write to fail, TELL ME THIS. Throw an exception. Do not silently simply choose not to work.
Third, if it fails, and you still can't send me the Foo object back, at least return false! In this case, I will *always* think it works. Always.
A better way to do this method is this:
Let's say I write you a specification and I say that I need a method, public Foo write(Foo f). This means that I want you to write a method that persists a Foo object, f, to the database, and returns me the same object, only with the id set.
Here is how NOT to write it:
public boolean write(Foo f) {
if (f.getName() != null) {
// write
}
return true;
}Let's go through what's wrong here, step by step.First, you're giving me a boolean response. True or false. That's not what I asked for. The reason I want the Foo object back is so that I can reference its ID later in the game.
Second, if the lack of the "Name" field is going to cause the write to fail, TELL ME THIS. Throw an exception. Do not silently simply choose not to work.
Third, if it fails, and you still can't send me the Foo object back, at least return false! In this case, I will *always* think it works. Always.
A better way to do this method is this:
public Foo write(Foo f) throws Exception {
if (f.getName() == null) {
throw new Exception("Name is null");
}
try {
// do the write, throw an exception on error.
} catch (Exception e) {
e.printStacktrace();
return null;
}
return f;
}Do it this way, and I'll be far less likely to stab you.Those of you who don't know dick (or care) about Java, Spring, or Hibernate may feel free to skip this.
(It should be pointed out that the Set of people who don't know dick about Java, Spring, or Hibernate seems to include every Java, Spring, and Hibernate developer I know.)
( nerd-ranty-goodness )
(It should be pointed out that the Set of people who don't know dick about Java, Spring, or Hibernate seems to include every Java, Spring, and Hibernate developer I know.)
( nerd-ranty-goodness )
private Map<Long, SexTool> sexToolCache = new HashMap<Long, SexTool>();
Now that I've gotten my head wrapped around hibernate a bit more the process is going smoother. There are still some clunky spots - mostly having to do with the documentation (or lack thereof).
( Code Hackery )
( Code Hackery )
[BEGIN nerdity]
I think I'm gonna keep ranting on Hibernate's claim of "removing metadata hell" until I die.
Let's say I create a class, a ListEntry. It's very simple. Dutifully, I create an ORM mapping file for it. Fields of entryID, addTime, completedTime, userID, and entryText (for now). These map fine.
I also create a class, User. I dutifully create an ORM mapping file for User.class, too (userID, email, registrationTime, cryptPW, firstName, lastName, registrationKey).
Now, the User objects have a one-to-many relationship to ListEntry. Several ListEntries on a User. So there is a method/field on the User: Map[Long,ListEntry] entryMap.
Hibernate, in theory, has this bad-ass thing. I just add to the User.class mapping a couple of lines saying, "it has a field, entryMap, and it gets filled with ListEntry objects from the DB that have the same userID as the user."
Now, you would think that it would know that when I say "this map contains ListEntry objects" that it would do something intelligent. Like, oh, maybe go to the ListEntry ORM map and get the mapping from there.
But no! It doesn't do that. I have to *replicate* almost verbatim the information in the ListEntry ORM file into the User ORM file - thus *doubling* the amount of metadata I need to keep track of for one class (and correspondingly increasing the likelihood of version drift).
Irritating.
[TANGENT]
Astute readers may notice that the fields above are things like "addTime" and not "addDate". This, too, is a nice irritating thing about Hibernate. I, like any reasonable nerd (and I haven't met a Java programmer who thinks different), store dates in the database as longs/BIGINTS and turn them into Dates on the way out (setAddDate(new Date(rs.getLong("addDate")))).
However, Hibernate will only automagically map Date objects into DATE or TIMESTAMP datatypes. Thus, I must create separate fields for those (addTime()) and then convert to Dates on demand.
Seriously. Who the fuck stores Date objects in what could be non-portable datatypes? For that matter, what idiot actually uses java.sql.Date? Too many heartaches and broken bones with that lot, mate. You can play with Calendar all you want and God have mercy on your soul as you do.
[/TANGENT]
[END nerdity]
I think I'm gonna keep ranting on Hibernate's claim of "removing metadata hell" until I die.
Let's say I create a class, a ListEntry. It's very simple. Dutifully, I create an ORM mapping file for it. Fields of entryID, addTime, completedTime, userID, and entryText (for now). These map fine.
I also create a class, User. I dutifully create an ORM mapping file for User.class, too (userID, email, registrationTime, cryptPW, firstName, lastName, registrationKey).
Now, the User objects have a one-to-many relationship to ListEntry. Several ListEntries on a User. So there is a method/field on the User: Map[Long,ListEntry] entryMap.
Hibernate, in theory, has this bad-ass thing. I just add to the User.class mapping a couple of lines saying, "it has a field, entryMap, and it gets filled with ListEntry objects from the DB that have the same userID as the user."
Now, you would think that it would know that when I say "this map contains ListEntry objects" that it would do something intelligent. Like, oh, maybe go to the ListEntry ORM map and get the mapping from there.
But no! It doesn't do that. I have to *replicate* almost verbatim the information in the ListEntry ORM file into the User ORM file - thus *doubling* the amount of metadata I need to keep track of for one class (and correspondingly increasing the likelihood of version drift).
Irritating.
[TANGENT]
Astute readers may notice that the fields above are things like "addTime" and not "addDate". This, too, is a nice irritating thing about Hibernate. I, like any reasonable nerd (and I haven't met a Java programmer who thinks different), store dates in the database as longs/BIGINTS and turn them into Dates on the way out (setAddDate(new Date(rs.getLong("addDate")))).
However, Hibernate will only automagically map Date objects into DATE or TIMESTAMP datatypes. Thus, I must create separate fields for those (addTime()) and then convert to Dates on demand.
Seriously. Who the fuck stores Date objects in what could be non-portable datatypes? For that matter, what idiot actually uses java.sql.Date? Too many heartaches and broken bones with that lot, mate. You can play with Calendar all you want and God have mercy on your soul as you do.
[/TANGENT]
[END nerdity]
So, now that Nexus Wars' Straylight version has landed, and things have started to calm down, I have decided to begin thinking about the next level of optimizations and so forth.
This means, really, the use of Hibernate. And since I don't feel it is wise to just "drop in" a radical change in datasource management to a hundred-thousand-line codebase, I'm starting a new, small, toy project (a "to-do" list web-app that I can use through the iPhone).
( Nerd Wankery and Bitching )
Anyways. At least it's not Perl.
This means, really, the use of Hibernate. And since I don't feel it is wise to just "drop in" a radical change in datasource management to a hundred-thousand-line codebase, I'm starting a new, small, toy project (a "to-do" list web-app that I can use through the iPhone).
( Nerd Wankery and Bitching )
Anyways. At least it's not Perl.
I need/want to create an ant task that will do something like flatten a database and reload some stub SQL (so that test builds can just use ant and only ant). The problem is that the ant sql task totally chokes on comments in the sql - stuff that the command line thinger won't care about.
The code it chokes on is something like this:
And it hates the "; #" bit, apparently treating the # as a new command.
Here is my ant task:
(Another problem is using relative paths with "SOURCE filename", but that's a totally different problem).
Anyone ever seen or dealt with this before?
The code it chokes on is something like this:
INSERT INTO foo SET id=1, bar=2, name="foofa"; # here is a comment
And it hates the "; #" bit, apparently treating the # as a new command.
Here is my ant task:
<target name="db.loadstatic">
<sql driver="com.mysql.jdbc.Driver"
keepformat="true"
escapeprocessing="true"
url="jdbc:mysql://localhost:3306/steamfr ont?useUnicode=true&characterEncoding=UT F-8"
userid="root" password="PASSWORD" >
<classpath>
<pathelement path="${classpathroot}/mysql-connector-j ava-3.1.10-bin.jar"/>
</classpath>
<path>
<fileset dir="./sql/entity">
<include name="species.sql"/>
</fileset>
</path>
</sql>
</target>
(Another problem is using relative paths with "SOURCE filename", but that's a totally different problem).
Anyone ever seen or dealt with this before?
Remember back when you started on a bunch of code, using Java 1.4, and you thought you were oh-so-clever by including Comparators inside the object class?
Well, you were, kind of. But in the future, remember the total pain in the ass it is to go and change all those Comparators in 23423423 class files to work with java 1.5 generics.
/**
* Sorts by name.
*/
public static final Comparator NAME_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
String o1Name = ( (StoreType) o1).getName();
String o2Name = ( (StoreType) o2).getName();
return o1Name.compareToIgnoreCase(o2Name);
}
};
Well, you were, kind of. But in the future, remember the total pain in the ass it is to go and change all those Comparators in 23423423 class files to work with java 1.5 generics.
/**
* Sorts by name.
*/
public static final Comparator<StoreType> NAME_COMPARATOR = new Comparator<StoreType>() {
public int compare(StoreType o1, StoreType o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
};