Google
 
Web unafbapune.blogspot.com

Saturday, June 25, 2005

 

Why use beanlib with Hibernate ?

(This post is about Beanlib 2.x. Please go to the JavaBean Library home page for the latest and greatest.)

Put simply, in cloning a Hibernate entity bean, we want to specify how deep we want to go in the object graph. Is it a 100% deep clone, a skin deep shallow clone, or some other combinations ? How about beans that involve a one-to-many collection ? The answer to this question has a significant impact on both the performance and memory footprint of the cloning process.

The JavaBean Library provides the following options
  1. 100% deep clone which will result in eagerly fetching all related entites and populating the values into pure POJO's which therefore will get rid of all CGLIB enhanced instances;

  2. Shallow clone which will result in cloning the top level bean and the immediately contained member fields of Java primitive types, String, Date, etc., but will exclude instances of Collection and application specific types. The excluded member fields will be set to null;

  3. Partial deep clone that extends only to a specified set of classes and a specified set of "collection properties". A collection property can be specified via a class named CollectionPropertyName. This allows an arbitrary portion of the object graph to be deeply cloned;

  4. Provide your own customized "Vetoer" by implementing the BeanPopulatable interface to control the population decision of each bean property;

  5. Provide your own customized BeanPopulatable and/or DetailedBeanPopulatable to completely override the population decision of each bean property.

  6. A new enhancement can be found here.
The class used for the above cloning is named HibernateBeanReplicator. There exists one for Hibernate 2.x and one for Hibernate 3.x.

 

Reusable String Array in Spring's Application Context

There is often the need to instantiate a single bean instance in the spring config file such that the bean is an array of strings that can be referenced in multiple other places. I tried the following which wouldn't work:
<bean id="reusableStringArray" class="[Ljava.lang.String">
<list>
<value>a</value>
<value>b</value>
</list>
</bean>
A similar requirement is to create a single bean instance which is a java.util.Properties object in the application context. It turns out I can define a list instead of a string-array. It does not matter because spring can transform the list to a string-array if necessary. Example:
<bean id="strings" class="java.util.ArrayList">
<constructor-arg index="0">
<list>
<value>a</value>
<value>b</value>
</list>
</constructor-arg>
</bean>
Similarly one should be able to create a Properties instance via a map element. Thanks to Andreas on this.

Also, Carlos Sanchez has a nice blog on this subject.

http://static.springframework.org/spring/docs/1.2.x/reference/beans.html#d0e2331

Friday, June 24, 2005

 

Monkey business-sense

Economist has an interesting article on Monkey business-sense exploring human's irrational aversion to risks. The message I get from a provider perspective:
  1. if one over-promises and under-delivers, one runs the risk of loosing out in the long term;
  2. if one under-promises and over-delivers, one runs the risk of not getting the deal at all in the first place;
  3. if one delivers exactly as one promises, one still runs the risk of loosing out to (2) in the long term;
Implication from a strategy perspective:
  1. To try to win a bid for the short term, pick over-promise and under-deliver;
  2. To delight the clients/consumers without actually putting in extra effort, pick under-promise and over-deliver;
  3. The most sustainable long term strategy, however, is deliver exactly as you promise.

 

Hibernate 3.0.5 Returns Corrupted Object via N-1 Navigation involving Subtypes ?

Hibernate supports a nice feature called polymorphic query. Say we have a table BAR with a discriminator column of two values {1,2} signifying the mutually exclusive subtypes of Bar1 and Bar2. The Java classes:
public abstract class Bar {
private long barId;
public long getBarId() { return barId; }
public void setBarId(long barId) { this.barId = barId; }
....
}
public class Bar1 extends Bar {...}
public class Bar2 extends Bar {...}
The mapping files:
<class name="Bar" table="BAR">
<id name="barId" type="long" column="BAR_ID">
<generator class="native" />
</id>
<discriminator column="TYPE" type="string" not-null="true" />
<subclass name="Bar1" discriminator-value="1" />
<subclass name="Bar2" discriminator-value="2" />
...
</class>
Now the HQL:
FROM Bar
would return instances of either Bar1 or Bar2 depending on the discriminator value. This is all nice and cool.

However, say I have a FOO table with a foreign key to BAR:
public class Foo {
...
private Bar bar;
public Bar getBar() { return bar; }
public void setBar(Bar bar) { this.bar = bar; }
}
Mapping File:
<class name="Foo" table="FOO">
...
<many-to-one name="bar" class="Bar" update="false" insert="false" >
<column name="BAR_ID" />
</many-to-one>
...
</class>
I would expect the object navigation foo.getBar() would return an instance of either Bar1 or Bar2, never Bar per se which is abstract and cannot be instantiated. e.g.
Foo foo = session.load(Foo.class, 1234);
Bar bar = foo.getBar();
The sad news is that in Hibernate 3.0.5 at least, the bar object from foo.getBar() turns out to be a CGLIB enhanced class based on Bar, not Bar1 nor Bar2. In other words, the returned object from foo.getBar() is corrupted!

The good news is one can get around the problem using eager fetching:
<class name="Foo" table="FOO">
...
<many-to-one name="bar" class="Bar" update="false" insert="false" lazy="false">
<column name="BAR_ID" />
</many-to-one>
...
</class>
It's all nice and cool again.

Wednesday, June 22, 2005

 

Remove the Blogger's Header

Just add the following script to the bottom of your Template after the </body> and before the </html>:

... </body> <script> var a = ["b-navbar", "header"] for (var i=0; i < a.length; i++) { var e = document.getElementById(a[i]) e.style.visibility="hidden" e.style.display="none" } </script> </html>
Update in 2012: Apparently the template has been changed. So here is an update. Just add the following script right after the <body>:
... <body> <script> var a = ["navbar-iframe-container"] for (var i=0; i < a.length; i++) { var e = document.getElementById(a[i]) e.style.visibility="hidden" e.style.display="none" removeChild(e); } </script>

 

DSL-300 ADSL Modem + DI-604 Router

When I used to have broadband internet access via cable modem in the US, to set up my DL-604 router was just a simple matter of connecting them up.

Now in Australia I have a DSL-300 modem for ADSL internet access. DSL-300 can store at most one account configuration with a single MAC address. For direct connection to a PC, the MAC is automatically retrieved from the PC as at the time when the accunt configuration is created. If I need to switch to another PC, I actually need to delete the account configuration from the modem, and recreate a new account configuration via the new PC. Otherwise, the modem may show a connected status but I still will not be able to access the Internet.

To connect up my DI-604 router with the ADSL model, it gets a little bit more complicated. I need to
  1. Erase the existing account configuration from the DSL-300, if any;
  2. Set up my DI-604 with a WAN settings of PPPoE with my ISP username and password;
  3. Make sure that the WAN MAC Address used by the DI-604 is different from the MAC addresses of all the PC's connected to it.
The other little twist I had was I stupidly burnt the AC/DC adapter for the DI-604, and I couldn't find a substitute that will have the equivalent 5V 2A output. So I just hacked it by taking the adapter from my son's cassette player with a 6V 1A output. So far it just worked :)

Tuesday, June 21, 2005

 

Oracle Blob mapped to byte[] in Hibernate

I refer to Oracle 9i and Hibernate 2.1 to 3.0.5.

As found in the Hibernate forum, there is a problem of mapping a byte[] JavaBean property to "binary" in the Hibernate mapping file. Basically the byte array can be written to Oracle, but what's read back from Oracle is always 86 bytes which is the Oracle Blob locator itself!

Here is one solution I've found to get around this problem, assuming, say, the byte[] property name is "image",
  1. Keep an internal member field for the byte[] image, with the standard {get|set}Image methods;
  2. Add a pair of {get|set}ImageBlob methods for getting and setting the Blob datatype, without the repsective Blob member field. This pair of methods are intended to be invoked only by Hibernate;
  3. Change the property mapping from "image" to "imageBlob", and use "blob" instead of "binary" for the type in the Hibernate mapping file.
Now the blob can be written to and read back from Oracle as byte[] as expected.

Note, with this approach, you may need to use the Oracle 10.1.0.4+ JDBC thin driver regardless to get around a problem related to the blob size greater than 2K bytes (even if you are running the Oracle 9.2.0.x database). Apparently it's related to a bug in the 9.2.0.x JDBC driver.

Example:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.SQLException;

import org.hibernate.Hibernate;

public class Foo implements Serializable {
byte[] image;

public byte[] getImage() {
return image;
}

public void setImage(byte[] image) {
this.image = image;
}

/** Don't invoke this. Used by Hibernate only. */
public void setImageBlob(Blob imageBlob) {
this.image = this.toByteArray(imageBlob);
}

/** Don't invoke this. Used by Hibernate only. */
public Blob getImageBlob() {
return Hibernate.createBlob(this.image);
}

private byte[] toByteArray(Blob fromBlob) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
return toByteArrayImpl(fromBlob, baos);
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException ex) {
}
}
}
}

private byte[] toByteArrayImpl(Blob fromBlob, ByteArrayOutputStream baos)
throws SQLException, IOException {
byte[] buf = new byte[4000];
InputStream is = fromBlob.getBinaryStream();
try {
for (;;) {
int dataSize = is.read(buf);

if (dataSize == -1)
break;
baos.write(buf, 0, dataSize);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
}
}
}
return baos.toByteArray();
}
}

Sample property mapping:
<property name="imageBlob" type="blob" column="IMAGE" />

Saturday, June 18, 2005

 

Generic Deep Clone via XStream

One common technique to implement generic deep clone is to take advantage of Java Serialization. The trick is simply to serialize/deserialize the object graph. However, this has the limitation that it only works for the portions of an object graph that implement Serializable.

To remove this constraint, we can apply similar technique with XStream, which doesn't require a class to implement Serializable for serializing deeply to/from XML. The deep clone would then work for all classes. (Note XStream does not serialize transient fields.)

Friday, June 17, 2005

 

Nice fonts for IDE

I find the Bitstream Vera fonts make life so much better for developers. You can download them from here. Simply install the fonts and configure to use in your favorite IDE. I've been using it as my default font in Eclipse, NetBeans, and IntelliJ for months, and simply love it. Thanks Paul!

Wednesday, June 15, 2005

 

Controlling layout using CSS

Instead of using the traditional HTML table element, there is a really nice way to control the page layout via CSS. Check out the tutorial A simple introduction to 3 column layouts. Importantly, it can be applied to fluid layout.

Such technique can greatly simplify the page content. Bye bye to the nested tables within tables!

Monday, June 06, 2005

 

Integrating Jakarta Commons Logging with Websphere 5.x

I think Websphere 5.x makes life too hard for using Jakarta Commons Logging (See Here). What do you think ? How about using Log4j directly so the logger behavior is more predictable ?

Anyhow, at least for development purposes, adding the system property:
-Dorg.apache.commons.logging.LogFactory=
org.apache.commons.logging.impl.LogFactoryImpl
will force Websphere to use the normal commons logging implementation instead of it's own.

log4j and WSAD

Also, to configure log4j properly for EJB project in WSAD 5.x, not only does log4j.xml need to be in the Java Build Path of the EJB project, the folder containing the log4j.xml must also be under the EJB project. Interestingly this is not necessary for a non-EJB project.

For example, for a non-EJB project PA, I can reuse an existing folder PB/F containing log4j.xml of a different project PB by setting the folder PB/F as a class folder of PA. This works if and only if PA is a non-EJB project.

Just realized a better alternative to the build path approach is to set up an independent Java project with a log4j folder as a class folder in the Java project's build path. Include the Java project as part of the EAR of the EJB project, and set the jar file dependency of the EJB project to depend on the Java project.


This page is powered by Blogger. Isn't yours?