MathJax

SyntaxHighlighter

Highlight

Custom CSS

Sunday, April 30, 2006

Yikes! More Hibernate type gotchas!

Suppose your mapping file contains this:

<id name="id" column="uid" type="long" unsaved-value="null">

Then you write this code:

Event e = (Event) session.load(Event.class, 1);

Result:

01:46:14,375 DEBUG LongType:79 - binding '1' to parameter: 1
01:46:14,375  INFO LongType:89 - could not bind value '1' to parameter: 1
java.sql.SQLException: Statement parameter 1 not set.

How sneaky! The type is long, but the literal 1 is an int and will be boxed into an Integer. Darn. Write this and things will work:

Event e = (Event) session.load(Event.class, 1L);

Hibernate: Wrapper classes (revisited)

As an additional note to the previous entry about Hibernate and using object wrapper classes, I found this another good example in the Hibernate Quickly book:

Suppose your persistent class has a boolean property, and the property can be null in the database. You will get a PropertyAccessException when you work with a row that has a null value for that column. If your class uses java.lang.Boolean instead, you won't have this problem.

Tuesday, April 25, 2006

SQL Maps for PHP

I've always hated programming in PHP4.x - especally database programming. Unfortunately, even now, not everybody has made the jump to PHP5. In the office, there are still several websites that run off PHP4, and my webhost unfortunately uses PHP4 as well.

One of the most annoyings things about PHP4 is that there aren't any good database tools available. With PHP5, I at least have a sprawling list of frameworks which, as a whole, have all the features that I want and have become used to (I'm sure), but individually are still lacking. But enough about that. I'm using PHP4. That means no data mappers and no ORM tools.

It got me so upset that I wrote Mapsicle, a data mapper for PHP. It works similar to iBATIS, but with a lot less features (due to being a one man project). However, it's at least got the core functionality there.

Tuesday, April 18, 2006

Hibernate: Wrapper classes and unsaved-values

It's a good idea for your domain model objects in Java to make use of wrapper classes such as Integer and Double instead of using regular old int or double. With Java 5.0's auto boxing and unboxing features, you can use wrapper classes pretty much the same way you could use primitives.

So what's the big deal about using wrapper classes in your domain model objects? Consider the following code:
// Message.java
public class Message {
    private int id;
    private MessageType type;
    // Getters and setters omitted
}

// MessageType.java
public class MessageType {
    private int id;
    private String value;
    // Getters and setters omitted
}

Your database schema:

create table Message (
    id int(11) not null auto_increment,
    type_id int(11) not null,
    primary key(id)
)

create table MessageType (
    id int(11) not null auto_increment,
    value varchar(255) not null,
    primary key(id)
)

insert into MessageType values (0, 'Important Message');

If you try to innocently persist a Message with the following code, you will likely receive a HibernateException.

Message msg = new Message();
MessageType type = new MessageType();
type.setId(0);   // This is an Important Message!
msg.setType(type);
session.save(msg);

The code gives this exception:
org.hibernate.TransientObjectException: object references an unsaved 
transient instance - save the transient instance before flushing: 
MessageType

So what happened here? Hibernate uses an attribute called unsaved-value in your mapping definition to determine whether or not an object was freshly created (unsaved), or a transient instance that was loaded or saved in a previous session. In this case, because that value wasn't set in the mapping definition, the default of 0 was used. If you couple that with the fact that the default initialization of an int value is also 0, Hibernate will always assume that MessageType is unsaved.

Unfortunately, the value of 0 really means something in the database! It's the id of a record with the type name "Important Message". There are two solutions to this problem. The first is to use wrapper classes like so:

// In MessageType.java:
public class MessageType {
  private Integer id;
  private String value;
  // Getters and setters omitted
}

<!-- In MessageType.hbm.xml: -->
<id name="id" column="id" unsaved-value="null">
...
</id>

The default initialization of an object is null, so the unsaved-value should be null as well. The previous code will work without a problem. The other solution is to initialize the id to some value other than 0 (and has no meaning), so as -1. Then set the unsaved-value as such.

Thursday, April 13, 2006

No CSS with CakePHP?

CakePHP is a web development framework that is structured very much like Ruby's Rails. I've worked on an in-house low risk project using a pre-beta version of CakePHP, and from what I've seen, I'm quite impressed. It was a non-trivial website, but CakePHP made the development go much smoother.

It works with PHP4 and PHP5, but I had been having trouble with it lately on my machine that runs PHP5. When I installed Cake, none of the CSS files I had would show up. After poking around a bit and scratching my head for a bit, I found that it was a problem with mod_rewrite for Apache not being enabled. Basically you have to uncomment /cake/app/config/core.php line 42 and everything should work like a charm:

// Uncomment the line below!
define ('BASE_URL', env('SCRIPT_NAME'));

There's a hidden dev gotchas page in the CakePHP Wiki that documents all this.

Wednesday, April 12, 2006

Apache Axis admin client gotchas

I noticed today that the Axis admin client utility (org.apache.axis.client.AdminClient) can be tricky when you want to deploy a web service with a WSDD. The following things must be true before the admin client will actually do what you want.

First of all, when you use the WSDL2Java tool to generate your deploy.wsdd and undeploy.wsdd files, the tool just places them in your src tree. You can run the admin client and feed it deploy.wsdd, and it will happily run, probably saying OK, and deploy nothing. When you check Axis's list, you'll get a fault saying so-and-so web service you tried to deploy couldn't be found.

That's because the admin client expects your .class files to be in the class path! Obviously this isn't the case if you are running the client from your source directory. Copy the deploy.wsdd file to your build directory and run the client again. It still doesn't work.

Excellent.

However, try copying everything in your build directory into the WEB-INF/classes where Axis is deployed, then run the client from that directory. Everything works! Don't ask me why.

SSL with Tomcat

The Tomcat documentation for SSL setup is not entirely correct. The How-to on the Jakarta website is accurate about keystore creation, but the snippet of XML for your server.xml file is outdated.

I suppose it's because they keep changing the format of that file and the documentation is having trouble keeping up. If you include the className attribute in your Connector element, it is likely that Tomcat will start, and then promptly throw an InvocationTargetException, which you will see if you look at your stdoutXXX.log file (or your catalina.out file if you've opted for the huge monolithic catalina.out logging solution).

Instead, you should use the following snippet without the className attribute. Name sure you declare it within the you want to use (typically it is Catalina).

<Connector port="8443"
        maxHttpHeaderSize="8192"
        maxThreads="150"
        minSpareThreads="25"
        maxSpareThreads="75"
        enableLookups="false"
        disableUploadTimeout="true"
        acceptCount="100"
        scheme="https"
        secure="true"
        clientAuth="false"
        keypass="password"
        sslProtocol="TLS"/>

Make sure you follow the rest of the instructions for setting up your keystore, and place the keystoreFile attribute within the Connector element (there's no Factory element for Tomcat 5) if your keystore isn't located in the same directory as your home directory, or you're not running Tomcat as yourself (highly likely if you're running Linux).

Note: Generate your keystore file with this command:

$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA