BACKGROUND SETTING
I am trying to create a library for accessing and caching web service data in Android and have stumbled across a problem.
All the objects managed by my library inherit from a base Entity
class. Any derivate class of Entity
can declare other fields* or attributes*.
The base class is responsible for returning the Entity
attributes that are to be read from cache (SQLite or File) or from a web service (REST or SOAP). In my current implementation, the Entity
class performs this using reflection: it reads all class field names that are marked with an @Attribute
annotation.
PROBLEM
The issue that I'm having in my implementation is the following: every time that I request all the Entity
's attributes using a function like static Set<String> getAttributes()
, this function must create a Set
implementation (currently using HashSet
for that for fast look-up).
I would like to avoid allocating and initialising a Set<String>
every time a request for all attributes is made.
From my point of view an attribute set is specific for an entire Entity
class, not an Entity
object. I.e.: having class Customer extends Entity
, all Customer
instances have the same exact attributes - each has a name, an address and so on.
My current attempt at this is to declare a static Set<String> attributes
in every class that extends Entity
and initialise that Set
using reflection in the class' static
block like this:
class Customer extends Entity
{
private static final Set<String> attributes = new HashSet<String>();
static
{
Entity.populateAttributes(Customer.class);
}
}
Given the class to initialise, the Entity
class can look up all fields marked with the @Attribute
annotation in that class and it's base classes (e.g. Customer extends Person
and Person extends Entity
would fill the Customer.attributes
set with attributes declared for the Customer
class and the ones inherited from the Person
class).
The problem I have is that an attributes
set might not be defined for a class which extends Entity
and I would like to enforce that at compile time.
I have seen this being done for the Serializable
interface in Eclipse: when create a class which implements Serializable
, Eclipse shows a warning if your class does not declare a [private] static final long serialVersionUID
.
QUESTION
Is there any way that I enforce that Serializable
behaviour for my Entity
class and show a warning or (better) an error if a class has not declared a field?
Is there a different approach to returning the attribute names for an Entity
-derived class?
FOOTNOTE
*I used the term field
for object properties that should not be managed by the library and the term attribute
for object properties that should be managed by the library (be read from a web service or SQLite/File cache and be persisted in a web service or SQLite/File cache)
EDIT 1
Basically, what I am trying to achieve is a to get a set of an Entity
's attributes* (see footnote above) in an efficient manner. This list is used by helper classes to store object values in a database (the CREATE TABLE
queries can be deduced from the attribute names and types) or to send to a web-service.
This library is used for caching values from a web-service and for synchronizing the local database (which might contain extra user input values and might be missing server updated values for objects) with data accessible through a web-service. It is not intended to replace the use of per-field accessors/mutators in an application with generic accessors/mutators.
This concept is known as Key-Value Coding and is used by many frameworks and libraries. As an example, the first two examples of libraries using KVC that I've found with a Google search are Cocoa and Sproutcore. References: Apple developer documentation and Sproutcore wiki.
KVC is also used in Android development. Bundle
, SQLiteCursor
and ContentValues
make intense use of KVC.
Since I may not be able to enforce the declaration of a static field in the deriving classes' definition, I will go by storing a map of attribute sets and class descriptions in the definition of the Entity
class described above and making sure that the set of attributes for a derived class is initialized in the Entity
constructor.
As an example:
public class Entity
{
private final static Map<Class<? extends Entity>, Set<String>> attributes = new HashMap<Class<? extends Entity>, Set<String>>();
public static void populateAttributes(Class<? extends Entity> derivedClass)
{
//initialize the set of attributes for the derived class and
//add it to attributes map with "derivedClass" as key
}
static
{
populateAttributes(Entity.class);
}
public Entity()
{
//calling this.getClass() returns the object's actual (derived) class(*)
if(!attributes.containsKey(this.getClass())
populateAttributes(this.getClass());
}
//rest of class definition (including getAttributes method)
}
public class Customer extends Entity
{
@Attribute
String someAttribute; //will be processed automatically
}
The cost of getting an Entity
s attributes is reduced from parsing all class attributes and creating a new set to hold them to a check-and-retrieve operation on a Map
which should be quite small when using a HashMap
.
The cost of creating an Entity
instance is increased by a check done to the attributes Map
(fast on HashMap
s). The cost of initializing the attributes
set for a given class is negligible, as it is done only once per derivate class type.
Considering that the attributes are requested at least once per class instance on 90% or more of the occasions, this should give better overall performance than the initial solution described in the question.
(*)calling this.getClass()
in a base class instance method will return the object's actual class. If the object has been initialized as a derived class instance, the derived class' description (Class
object) will be returned. A question about this has already been asked and answered here: Which class does getClass() report inside a constructor of a base class.