-
Notifications
You must be signed in to change notification settings - Fork 36
Using Reflection to Encode Objects as JSON
As of the upcoming 1.9 release, JSONUtil will no longer require you to put object data into Maps if you do not wish to do so. It can examine your objects using Java's reflection API and generate the JSON automatically. Reflection is not enabled by default. If you do not enable reflection then unrecognized objects will continue to have their toString() method called and the value encoded as a normal String.
There are two ways to enable reflection: selective and global.
Selective reflection only operates on those classes which you explicitly choose. You do this by adding classes to your JSONConfig object via JSONConfig.addReflectClass(Object) or JSONConfig.addReflectClasses(Collection). These methods are also available in JSONConfigDefaults so that you can have them reflected by default even if you don't use an explicit JSONConfig object. You can send java.lang.Class objects to these methods or you can send other objects and the necessary java.lang.Class object will be inferred from them.
Global reflection is enabled by calling JSONConfig.setReflectUnknownObjects(boolean) with a value of true. This will use reflection on all unrecognized objects. This method is also available in JSONConfigDefaults if you want this to be the default.
Fields will only be included if they are instance fields (not static) and not transient. By definition, transient fields are not supposed to be serialized. Instance fields from super classes will be included if they satisfy the privacy criteria described below.
The reflection code looks for JavaBeans naming convention compliant getter methods to get the values of the fields. For example if you have a field called "foo" it will look for a parameterless method called "getFoo" to call to get the value. If it cannot find such a method for a given field then it will attempt to access the field directly.
JSONConfig.setPrivacyLevel(int) sets the privacy level for including fields in the reflected output. By default, the privacy level is set to ReflectUtil.PUBLIC which means that only fields which are public or which have a public getter method will be included. Other levels are ReflectUtil.PROTECTED, ReflectUtil.PACKAGE and ReflectUtil.PRIVATE. If you use ReflectUtil.PRIVATE then all non-transient instance fields will be included in the JSON output, even if they are private and do not have getters. This method is also available in JSONConfigDefaults if you wish to set a default level other than ReflectUtil.PUBLIC.
This still gives you less control over your JSON output than using Maps or JSONAble's but it can be more convenient. Be mindful of sensitive or security related data that you might have in your objects that could end up in your JSON.
MyObj someObj = new MyObj(p1, p2, p3);
JSONConfig cfg = new JSONConfig();
cfg.addReflectClass(MyObj.class);
cfg.setPrivacyLevel(ReflectUtil.PROTECTED); // include public and protected fields/getters.
String json = JSONUtil.toJSON(someObj, cfg);
MyObj someObj = new MyObj(p1, p2, p3);
JSONConfig cfg = new JSONConfig();
cfg.setReflectUnknownObjects(true);
cfg.setPrivacyLevel(ReflectUtil.PRIVATE); // include all fields.
String json = JSONUtil.toJSON(someObj, cfg);
The code to do this is currently in the repository waiting for me to release it. I'm still working on some testing and improving the comments to match some of the new features in this release. It should be released within the next few days.