Wednesday, March 9, 2011

Delazifying Hibernate Entitities.

Not everything Hibernate promises you, when it handles you an object, and that may be virtually the entire object graph for your application, is available immediately. Sometimes what you got is not the object itself but just a promise to deliver it, when needed. A.k.a a proxy. And as long as the Hibernate session is not closed and available, at the place/scope where objects are used the promises are meet and the values are delivered.

Still, sometimes, the persisted and then retrieved objects leave the scope where the Hibernate sessions live. And some carry with them the "unrealized" proxies. And if such are objects handled over to some other framework, blissfully unaware of Hibernate proxies, then there would be some clash of opinions and throwing of exceptions. Take BlazeDS...

So?

public Object stripLazyProxies(Object object) {
  if (object instanceof Collection<?>) {
   Collection<?> list = (Collection<?>) object;
   for (Object inner : list) {
    stripLazyProxies(inner);
   }
  } else {
   Class<? extends Object> cls = object.getClass();
   Field[] fields = cls.getDeclaredFields();
   for (Field field : fields) {
    // Skip static fields
    if (Modifier.isStatic(field.getModifiers())) {
     continue;
    }
    OneToMany oneToMany = field.getAnnotation(OneToMany.class);
    if (oneToMany != null && oneToMany.fetch() == FetchType.LAZY) {
     field.setAccessible(true);
     try {
      field.set(object, null);
     } catch (Exception e) {
      throw new RuntimeException(e);
     }
     continue;
    }
    ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
    if (manyToOne != null && manyToOne.fetch() == FetchType.LAZY) {
     field.setAccessible(true);
     try {
      field.set(object, null);
     } catch (Exception e) {
      throw new RuntimeException(e);
     }
     continue;
    }
    ManyToMany manyToMany = field.getAnnotation(ManyToMany.class);
    if (manyToMany != null && manyToMany.fetch() == FetchType.LAZY) {
     field.setAccessible(true);
     try {
      field.set(object, null);
     } catch (Exception e) {
      throw new RuntimeException(e);
     }
     continue;
    }
    OneToOne oneToOne = field.getAnnotation(OneToOne.class);
    if (oneToOne != null && oneToOne.fetch() == FetchType.LAZY) {
     field.setAccessible(true);
     try {
      field.set(object, null);
     } catch (Exception e) {
      throw new RuntimeException(e);
     }
     continue;
    }

    // Any other annotations with FetchType.LAZY ??

    // Check for inner entities
    Entity entity = field.getType().getAnnotation(Entity.class);
    if (entity != null) {
     field.setAccessible(true);
     try {
      Object value = field.get(object);
      if (value != null) {
       field.set(object, stripLazyProxies(value));
      }
     } catch (Exception e) {
      throw new RuntimeException(e);
     }
    }
   }
  }
  return object;
 }

The method above will set recursively set every "lazy" field to null. I used it, in order to avoid doing the same by hand. If setting every field to null is too much for you, then obviously you need some other method.

Tuesday, March 8, 2011

JPUI - Simply useful

JPUI is a rather simple java properties viewer and editor. It allows you to see and modify the properties persisted by Java applications. Here's a screenshot to save me some breadth



And now about a rather unusual use of this tool.

Font rendering is a lot better now on Linux than it was few years ago. Unfortunately font rendering in/for Swing applications still looks poor. In order to improve things people launch such applications using special flags, like:

java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=on .... 
But doing that for each application in part is booooooring! If only there would have been a way to set those properties system-wide... Well there is!

sudo java -jar jpui.jar 
then create under System a new node swing and then create under swing a new attribute aatext and set it to true. And then do the same for -Dawt.useSystemAAFontSettings=on
 

You need to be root because (at least on Ubuntu and for latest, straight from Oracle, Java) the preferences are saved under /etc/.java/.systemPrefs/.


Enjoy!

Starting H2 database

As of last, I'm using H2 database quite often and while opening a terminal and navigating to the `/bin` folder of H2 distribution is hardly a problem, it may become tedious after a while. So, without further, further, further, further... Damn it, here's the modified h2.sh with stuff taken from standard prologue of Racket scripts.
#!/bin/sh

# Remember current directory
saveD=`pwd`

# Find absolute path to this script,
# resolving symbolic references to the end
# (changes the current directory):
D=`dirname "$0"`
F=`basename "$0"`
cd "$D"
while test -L "$F"; do
  P=`readlink "$F"`
  D=`dirname "$P"`
  F=`basename "$P"`
  cd "$D"
done
D=`pwd`

cp=$D/h2-1.3.152.jar
if [ -n "$H2DRIVERS" ] ; then
  cp="$cp:$H2DRIVERS"
fi
if [ -n "$CLASSPATH" ] ; then
  cp="$cp:$CLASSPATH"
fi

cd $saveD
exec java -cp "$cp" org.h2.tools.Console $@

Now you just have to make a symbolic link to h2.sh (I called mine h2db) somewhere where your path is and make it executable. Yes, this assumes some kind of Unix.