Monday, March 7, 2011

Dynamically positioning a signature in iText

After much tinkering, I've been able to find a way to dynamically populate a signature image to the bottom of a PDF as follows:


            PdfReader reader = new PdfReader(...);

            PdfStamper stp = PdfStamper.createSignature(reader, os, '\0'); 
            PdfSignatureAppearance sap = stp.getSignatureAppearance();
            sap.setCrypto(key, chain, null, PdfSignatureAppearance.SELF_SIGNED);
            sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
                
            
            Image image = Image.getInstance(imageBytes);
            sap.setRender(PdfSignatureAppearance.SignatureRenderGraphicAndDescription);
            sap.setSignatureGraphic(image);
            sap.setAcro6Layers(true);
            sap.setImage(null);
            
            int page = reader.getNumberOfPages();

            Rectangle pageSize = reader.getPageSize(page);

            int verticalPosition = (int)(pageSize.getBottom() + 70);
            int signatureEnd = (int) verticalPosition + 50;
            position = new Rectangle(50, verticalPosition, 250, signatureEnd);                        
            
            sap.setVisibleSignature(position, page, null);

Turning Spring MVC + Hibernate lazy=true causes ClassCastException

I started getting java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
 after I had changed the default fetching strategy to be lazy to give me better loading performance.

<hibernate-mapping auto-import="true" default-lazy="true" default-cascade="save-update">

This worked to improve performance, but what I couldn't understand was why I was getting the dreaded ClassCastException. To understand why, I had to dig deeper into Hibernate and Spring MVC and learn more about what was happening underneath the hood.

Here is the shortened class definition of the entity:

public class Entity {
    
    private transient Set<Long> selectedMice = new HashSet<Long>();

What's important to note is that the field called "selectedMice" is not mapped in Hibernate to be persisted to the database. Rather this field is used to temporarily store data to be processed and hence it is labelled as being "transient".

Now when combined with the Spring MVC framework, binding occurs where  form submission values destined for the selectedMice field are converted into their appropriate value of Long.


                                    <spring:bind path="model.selectedMice">
                                        <input type="checkbox" name="${status.expression}" value="${mouse.id}" />                                        
                                    </spring:bind>

When lazy loading is turned on, the Entity class is subclassed by Hibernate using CGLIB to create a proxy. The problem is that CGLIB does not recognize Generics. So when CGLIB goes to create the proxy class, rather than keeping the parameterized type of Set, it simply becomes Set.

Since Spring MVC is now populating a proxy class instead of the direct Entity class, it doesn't know the parameterized type of Set collection for selectedMice field, and does no automatic conversion of String to Long. The selectedMice field becomes populated with Strings instead of Longs. Thus when I go to fetch the selectedMice and cast it to Long, I get the ClassCastException.

Solution

The solution is quite simple and is probably better for clearer separation of application layers. I've moved all transient fields out of the entity and into a model class as follows:

public class Model {
    /**
     * A proxied instance generated by Hibernate/CGLIB
     */
    private Entity entity;

    /**
     * The non-persistent field
     */
    private transient Set<Long> selectedMice = new HashSet<Long>();


The Model class wraps around the Entity class (which is proxied) and also contains the selectedMice field. This way Spring MVC binds to the Model class rather than to the proxy.

References:

http://blog.anthonychaves.net/2007/03/12/howd-this-string-get-into-my-list/
http://andykayley.blogspot.com/2009/05/how-to-avoid-classcastexceptions-when.html
http://download.oracle.com/javase/tutorial/extra/generics/intro.html

Tuesday, March 1, 2011

I had this unusual problem with Data Tables (http://datatables.net) where the table was being pushed down leaving a blank space above the table. I've shown the problem below:

I've highlighted the blank space in red to make it more visible.

After spending some time and using the webdeveloper firefox plugin, I narrowed it down to a CSS properties called float and clear

To see these properties in action, here is a simple website demonstrating how these properties work:
http://www.quackit.com/css/properties/css_clear.cfm

Looking back at the image above, you can see that the tables were being pushed down to the bottom of menus on the left hand side. Its important to notice this as we shall soon see why. This is the CSS definition for the menus:

#sidebar {
    float: left;    width: 150px;
    margin-right: 0px;
    margin-bottom: 20px;
    margin-left: 0px;
    /*padding-top: 20px;*/
    
    background-image: url(../images/menutop_owr3.gif);
    background-repeat: no-repeat;
    background-position: top;
}

The important property to note, is that the menus are being floated to the left.

Now looking at the CSS applied to Data Tables I was using the demo_table_jui.css which had the following definitions:

.dataTables_wrapper {
    position: relative;
    min-height: 302px;
    _height: 302px;
    clear: both;}
table.display {
 margin: 0 auto;
 width: 100%;
 clear: both;
 border-collapse: collapse;
} 

The clear property meant that any floating elements on either the right or left should be cleared, resulting in the tables being pushed down. To resolve the issue, I simply had to remove this property from the definitions as follows:


.dataTables_wrapper {
    position: relative;
    min-height: 302px;
    _height: 302px;
    /*clear: both;*/
table.display {
 margin: 0 auto;
 width: 100%;
 /*clear: both;*/
 border-collapse: collapse;
} 

And now the tables are displayed without the ugly gap: