Saturday, January 14, 2017

ORM Persistence design for GWT, Android, iOS and J2SE

Our persistence challenge is to have Object Relationship Management (ORM) that works on Android, with GWT RequestFactory, with iOS using j2objc, and using "normal" J2SE for an eventual desktop app.

ORMLite provides a very nice ORM framework that works both using JDBC (e.g. Desktop/Server side java).  GWT requires proxy interfaces so it can manage the back/forth from the server.  SharkORM requires objective c classes.  It all gets very repetitive:

It requires ORM classes like so:

package com.example.helloandroid;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import com.j256.ormlite.field.DatabaseField;

/**
 * A simple demonstration object we are creating and persisting to the database.
 */
public class SimpleData {

	// id is generated by the database and set on the object automagically
	@DatabaseField(generatedId = true)
	int id;
	@DatabaseField(index = true)
	String string;
	@DatabaseField
	long millis;
	@DatabaseField
	Date date;

	SimpleData() {
		// needed by ormlite
	}
}


GWT's Request Factory requires a proxy interface that it uses to send data back and forth like so:

@ProxyFor(SimpleData.class)
public interface SimpleDataProxy extends EntityProxy {

       public int getId();
       public void setId(int id);

       public String getString();
       public void setString(String string);
         
       public Date getDate();
       public void setDate(Date date);
}

SharkORM wants something like (haven't tested this yet - but the gist is correct):

//  Header File : SimpleData.h
#import "SharkORM.h"
@interface SimpleData : SRKObject
@property int               id;
@property NSString* string; @property long date;
@end

// Source File : SimpleData.m
#import "Person.h"
@implementation Person
@dynamic id,string,date;
@end

Enter Roaster where you can parse and generate java code.  In NanoLRS (our in progress implementation of an Experience API server designed for embedding in apps) we just make the proxy interface and the rest is generated by roaster by our EntityGeneratorOrmLite class like so:

JavaInterfaceSource proxyInterface = Roaster.parse(JavaInterfaceSource.class, proxyStr);
Iterator<MethodSource<JavaInterfaceSource>> iterator = proxyInterface.getMethods().iterator();

It's a work in progress - but at least it seems like I've found a way around writing the same code slightly differently by hand three times.