Friday, May 30, 2008

MS Bugs - You mean they exist?

I have had the pleasure of playing with Microsoft Visual Studio 2008 to try a little Windows Mobile 6 development. This has been a great opportunity to learn more of C# and I have to admit that while I am learning .NET as I go, I am coming up to speed quite quickly. I decided the other night to provide some local storage for some of the values I am retrieving from my server. Microsoft provides a really light-weight version of their SQLServer which runs on the mobile platforms called SqlCe and I have been quite impressed with it so far. I read/watched some of the "How do I?" videos provided on the MSDN website and started using SqlCeResultSets. I wrote a simple loop in my code similiar to the following:
   ...
   SqlCeResultSet resultSet = _sqlController.getResultSet(ResultSetType.COUNTRIES);
   if (resultSet.HasRows)
   {
      foreach (SqlCeUpdatableRecord record in resultSet)
      {
          // do something with the result
      }
   }


However, evertime it hit the foreach statement the program would terminate. I suspected this was an infinite loop or some other issue. Well it turns out that indeed there is a bug in .NET 3.5 which causes the ResultSet to enter an infinite loop when the GetEnumerable( ) is called. An interesting article that outlines this is located Jim Wilson's Blog. Fortunately this issue only cost me a few minutes, but I was glad to see that this was a Microsoft issue and not my beginner C# programming skills at fault.

Friday, May 23, 2008

JPA Identity Interger/Long or String?

In my previous article JAXB and the nasty XmlID, I discussed how if you wanted to use @XmlID and @XmlIDREF as pointer references to XML serialized objects that the values had to be Strings. In some cases they might be fine, especially if your primary key is a compound key that you are serializing. However, the more common case for simple persisted objects is you have used some numeric identity value as the primary key. A short search will show almost all demos/tutorials and examples of JPA use either a Integer or Long wrapper. This of course is not a restriction of JPA. You can use anything you want as the primary key, but if you are going to leverage some of the @GenerateValue options, unless you are willing to define your own Alpha scheme, you will get a numeric value. Which leads me to my point: If I want to XML Serialize an object using JAXB (which is much easier than doing it by hand with a DOM Document) that contains foreign key references, surely I can do this in some way without having to convert my identities to Strings?

The simple answer is yes, but not by applying the JAXB annotations on the persisted property. Instead, you would need to create a proxy method that can convert your PK (Primary Key) into a string representation, and this method is tagged with the @XmlID annotation. In order to be used by JAXB you need at least a String property. Lets look at a simple code example.
   import javax.xml.bind.annotation.XmlID;
   import javax.xml.bind.annotation.XmlRootElement;
   import javax.xml.bind.annotation.XmlTransient;
   import javax.xml.bind.annotation.XmlAttribute;
   import javax.persistence.Entity;
   import javax.persistence.Id;
   import javax.persistence.GeneratedValue;
   import javax.persistence.Transient;

   @XmlRootElement
   @Entity
   public class PersistedObject {
       @Id
       @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
       @XmlTransient // we are not going to write out the id
       private Long id = null;

       @XmlTransient
       @Transient   // this is not an entity managed attribute
       private String identityString = null;

       @XmlTransient
       public Long getId( ) { return id; }

       public void setId( Long id ) { this.id = id; }

       @XmlID
       @XmlAttribute(name="id")
       public String getIdentityString( ) {
          return ( id != null ) ? id.toString() : "0";
       }
   }


In this manner, we can denote our JPA identity with the data-type which makes sense (either a Long or Integer) yet allow for easy XML Serialization through the use of the @XmlID field on the getIdentityString() method. This is certainly not ideal, and I would've preferred to put the annotation on a method only, however JAXB requires the XmlID tag on a property.

Unfortunately for me, I only thought of this after converted my persistent beans, services and unit tests over to String Ids. Fortunately SCM tools (subversion in this case) come to the rescue and I can easily back out my changes.

Monday, May 19, 2008

Smartphone Connectivity in Visual Studio 2008

Hooking up Microsoft Visual Studio 2008 and using the network on an emulated smartphone is a rather tricky business if you are not familiar with the procedure. Fortunately, a very good blog exists to capture this information at: Akhune's Weblog. The limitation of this of course is that you can not have your mobile device AND the emulator both connected to ActiveSync at the same time.

An Update (05/23/2008): Having used the emulator a little more, I think the key point that is often lost is the usage of the "cradle" option to dock the emulator with ActiveSync. Once you get in the habit of doing this per development session, you will find it is much easier. Also, I have not had very good results of having both my Smartphone and the Emulator cradled simultaneous and recommend using one or the other. This appears to be a pretty common issue.

Tuesday, May 13, 2008

Flexjson limitations

The old saying goes "If it sounds too good to be true, it is too good to be true". Well this applied to Flexjson. While this tool is very capable of externalizing an object to the JSON format, there are several shortcomings which make it difficult to use at the moment. The contributors have mentioned they are working to address these issues. Currently Flexjson only can process primitives, wrappers, Strings and Dates. Objects (that are not collections) are they themselves externalized into JSON. In complex data models, you may not wish to serialize the entire downstream object. You may wish to only serialize it's ID. This (and my gripping about the implementation) is shown in one of my previous posts on JAXB and XmlID. Currently Flexjson has no clean way of supporting this. The only was to attempt this would be through the usage of include() and exclude() on the JSONSerializer. The downside of this, is that you essentially need a specific handler for each object you want to serialize since the attributes/conditions of inclusion or exclusion will change. Lets look at an example:
@Entity
public class Stamp implements Serializable {
  private Long id;
  private String description;
  private Country country;
  // ... other attributes and methods
}

@Entity
public class Country implements Serializable {
   private Long id;
   private String name;
   // ...
}
So in this example, if we wanted to serialize all of the Stamps to JSON, by default the country would be serialized for each stamp. In a typical system, we might have 200 countries and 50,000 stamps. This means that our countries are fully serilized in a redundant fashion many times over. In this situation what we really want is the country id field. We can get this in the following way:
  Writer out = // ... some writer like a PrintWriter
  Collection stamps = stampService.getAll( );
  JSONSerializer serializer = new JSONSerializer( );
  serializer = serializer.include("id","description","country.id").exclude("*");
  for( Stamp s: stamps ) { 
     out.write( serializer.serialize( s ) );
  }

While this works, If your object has many properties and object relationships, this can get a little exhaustive setting up the include and exclude parameters. It also means you either (a) need a introspective tool to read this from your beans or (b) you need to provide some handler for each bean to setup the includes and excludes properly. I personally have great faith in the Open Source community, and will look forward to leveraging the next version of Flexjson to cleaner handle this situation with a Transformer (Transformers today only handle Strings, primitives and dates). Until then I suppose I'll have to come up with some solution that is tied to my object model.

Saturday, May 10, 2008

JSON Annotating of Java Beans

As I was working through a GWT Code Serializer for generating Java serialization code to serialize objects as XML or JSON, I started thinking about how nice it was to leverage JPA Annotations in documenting JSON serialization on persistent beans. Wouldn't it be nice to serialize objects to JSON as easily as we can do with JAXB? After searching the WEB for a solution, I was almost about ready to go ahead and develop an Annotation infrastructure for this very problem. That was when I came across Flexjson, which does exactly this. In fact, unlike JAXB's marshalling terminology, Flexjson actually calls it serialization. As of yet, I have not tried Flexjson, but from looking at the examples shown in the link above, it seems to do exactly what one would expect.

Thursday, May 8, 2008

The Engineers Approach to Baby Crying

I have had the fortunate gift of becoming a father recently to a beautiful little girl "Angela". However, as a first time parent, trying to deal with a crying baby was next to impossible. That was until we found out what all the sounds meant and what worked and didn't work. Now she is three weeks old and almost sleeping through the night. The kep principle is to feel confident and calm that you can take care of whatever the needs of the baby are. That being said, a little decision matrix can go a long way in assisting this. For that reason, I have put together this nice "binary flow chart" which will guide you through to happier parenting!

Saturday, May 3, 2008

Olympus and Poor Usability - Lesson 1

Today I was helping my father install a version of Olympus Master 2.0 on his Vista laptop. We were struck back when it asked him to enter the Country. The list seemed to include every country in the world, however they were in no particular order. In his case we has looking for "Canada", and hitting the letter "C" brought up "Cuba". Suffice it to say, we gave up trying to find Canada since finding it in two hundred odd items in no particular order was impossible and frustrating. We selected the first item "United States". Which makes me wonder. Does all software that prompts for a country put "United States" at the top? Is it because the software engineers feel the average American is too stupid to find their country in an alphabetical list? It is these little short cut techniques in software that really destroys to usability of a product.

Friday, May 2, 2008

JAXB and the nasty @XmlID

I wonder why the developers of JAXB decided to make the @XmlID annotations support Strings only? You would think that a String or any primitive type would've been acceptable. The Javadoc of XmlID states:
The usage is subject to the following constraints:
  • At most one field or property in a class can be annotated with @XmlID.
  • The JavaBean property's type must be java.lang.String.
  • The only other mapping annotations that can be used with @XmlID are:@XmlElement and @XmlAttribute
The other property annotations like XmlAttribute and XmlElement support primitives and wrappers. This of course means if you are using JAXB to XML Serialize a JPA Entity, your primary ID key needs to be a string instead of a Integer/Long value. JPA Persistence will still treat this as an integer in your datastore if you have the @GeneratedValue annotation set, so at least from this perspective your data model does not need to change. The advantage of using the @XmlID annotation is it allows you to use the @XmlIDREF tag in other Entities (meaning the entire entity is not XML Serialized only it's @XmlID value. Here is a simple example:
   @Entity @XmlRootElement
   public class Company implements Serializable {
      @Id @Column(name="company_id") @GeneratedValue
      @XmlAttribute @XmlID
      private String id;

      // ... setters, getters and other methods.
   }

   @Entity @XmlRootElement
   public class Employee implements Serializable {
      @Id @GeneratedValue
      @XmlAttribute @XmlID
      private String id;
   
      @JoinColumn(name="COMPANY_REF", referencedColumnName = "company_id")
      @ManyToOne(optional=false)
      @XmlIDREF
      private Company worksfor;

      // ... setters and other methods
   }

Now if we marshall an Employee with an id of "50" who works for a company with an id of "20", the resulting XML would look something like the following:

   <employee id="50">
      <worksfor>20</worksfor>
   <employee>

Thursday, May 1, 2008

Eclipse, Toplink, JPA and a Lost Evening

So I decided to put together a simple web-application using the dynamic web project in Eclipse. However, my recent workspace had become rather "corrupted" and so I had created a new one named "eclipse 3.3" (under my common \dev\workspace area). To my dismay, I simply could not get my web-application which was working in my old workspace to work. The crazy thing about this, is I know my persistence.xml and project was setup correct. The Tomcat log was producing the following:
INFO: The configured persistenceUnitName is: MileageTracker
[TopLink Config]: 2008.05.01 10:23:15.703--ServerSession(2165595)--Thread(Thread[main,5,main])--The alias name for the entity class [class org.javad.mileage.model.Vehicle] is being defaulted to: Vehicle.
javax.persistence.PersistenceException: No Persistence provider for EntityManager named MileageTracker: The following providers:
oracle.toplink.essentials.PersistenceProvider
oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
Returned null to createEntityManagerFactory.

at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:154)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
... 
Now what is curious about this, is Toplink was found, and it determined some information about my EntityBean. I spent a lot of time trying to discover what was wrong here, checking my other projects from the previous workspace etc. It turns out the problem was an Eclipse bug in which you have workspaces with spaces (" ") it will fail to find the Entity Manager Factory. The reference bug ID is 210280 Sufficit to say, this cost me a few hours of productivity.....