While writing some basic CRUD code for a recent project, I decided to create a base struct containing the redundant fields for all of my data entities (id,date_created, etc…). I then embedded this struct in all data entities and tagged it as inline so json/bson marshalers would treat it accordingly. A problem arose when I wanted to pass newly created data entities from clients into a json webservice. Normally when instantiating a data entity struct I would use the associated creation method (NewSomeEntity()) which would set the appropriate id/created date etc… however the json marshaler is not smart enough to do this as it builds the object graph. If the object graph is only one level deep, you can just run an init function on the new object returned from the marshaler, when the object contains n-levels (n-many relationships) it becomes a problem.
I had two options: I could implement custom marshal interfaces for every data entity struct, or I could write a function that reflects over the object graph after it has been built by the json marshaler and run my initialization function against any new/unintitalized base entity structs. I decided to go with the later option.
There are a few key functions needed to achieve the method described above, mainly: reflecting over an object to get a list of it’s fields, checking the type of the reflected field against your base struct, checking if the reflected field value is uninitialized or in the case of a pointer nil, and finally setting the value of an empty field to an initialized struct.
Here are some code examples:
1 2 3 4 5 6 7 8 9 10
Reflect over object and get list of fields
1 2 3 4 5 6 7 8
Compare reflected type
1 2 3
Checking for uninitialized/empty struct
1 2 3
Checking for nil pointer - if you are using pointers you may need to check for a nil pointer rather than an uninitialized struct.
1 2 3
Finally once an empty field is found set it to an initialized Entity struct
With the above snippets you can easily build a custom function for iterating over your object graph and initialize empty structs.