Overview
The intent of this component is to provide a configurable and customized integration of JSON De-/Serializers using GSON, Jackson 1 and Jackson 2 APIs into Avalon/Turbine. It is a common pattern with client-side MVC applications to embed data for a base set of objects in a page instead of making a separate AJAX request to load them. It is written for use in Turbine but it can be used in any container compatible with Avalon's ECM container. There are three implementations
- GSONBuilderService and
- Jackson2MapperService
- JacksonMapperService
- Support for JsonPath in Gson and Jackson 2
- Support for org.json mapping (as registered module or adapter)
JSON Service Component with Jackson 1 / 2 API
Overview
This Service serves as a JSON serializer or deserializer using Jackson Version 2 or Version 1. The JSON Jackson 2 sub module is the most elaborated of the three sub modules. It provides attribute and class filtering and cache cleaning mechanism.
It is written for use in Turbine but it can be used in any container compatible with Avalon's ECM container.
Role Configuration
Jackson Version 2.7.x
<role name="org.apache.fulcrum.json.JsonService" shorthand="json" default-class="org.apache.fulcrum.json.jackson.Jackson2MapperService"/>
Jackson Version 1.9.13
<role name="org.apache.fulcrum.json.JsonService" shorthand="json" default-class="org.apache.fulcrum.json.jackson.JacksonMapperService"/>
Component Configuration
Item | Datatype | Cardinality | Description |
---|---|---|---|
annotationInspectors | Complex | [0|1] |
If empty com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector is set as annotation introspector. You could otherwise provide a primary and (optionally) a secondary introspector. Setting the special introspector org.apache.fulcrum.json.jackson.SimpleNameIntrospector yields property and class name based filtering. See the configuration example below and in section Usage in Velocity Template. Features could be set to false or true by setting the attribute value of the sub element feature. The feature attribute type should be the class name of any sub interface of com.fasterxml.jackson.databind.cfg.ConfigFeature . The element content itself defines any feature (enum value) for this feature. Cft. the configuration example below.
|
dateFormat | String | [0|*] |
If set changes the date format. The provided string should be in a format acceptable to the class java.text.SimpleDateFormat.SimpleDateFormat(String) . The default value is
MM/dd/yyyy .
|
defaultTyping | String | [0|*] |
The default is no defaultTyping. Otherwise set it to a Jackson 2 enum value in class com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping .
|
cacheFilters | boolean | [0|*] |
If set to true , caching is enabled. Each filter applied remains valid and is not removed.
This implicits, that you cannot retrieve for the same class/bean different properties in different calls.
Otherwise different serializations per call are possible. You could invalidate (refresh) the cache per class, in most methods providing a Boolean parameter, cft. method parameters named refresh* or clean* . The default value is true .
|
escapeCharsGlobal | boolean | [0|1] |
If set to true , by default ASCII characters <= 32 character code and the four characters '<','>','&','\' (backslash) are escaped using com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_STANDARD ('\u'). for details cft. com.fasterxml.jackson.core.io.CharTypes. The default value is false .
|
useJsonPath | boolean | [0|1] |
If set to true , JsonPath is enabled, which allows to apply JsonPath expressions using the integrated jackson provider by default (without setting this property to true , com.jayway.jsonpath.spi.mapper.JsonSmartMappingProvider will be used and would need to implement net.minidev.json.writer.JsonReaderI by default - which would fail as net.minidev.json package is excluded from dependencies; you would need to include this transitive dependency manually). The default value is false .
|
Component Configuration Example
Jackson Version 2.x
<json> <annotationInspectors> <primary>org.apache.fulcrum.json.jackson.SimpleNameIntrospector</primary> <secondary>com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector</secondary> <features> <feature value="false" type="com.fasterxml.jackson.databind.SerializationFeature">FAIL_ON_EMPTY_BEANS</feature> <feature value="false" type="com.fasterxml.jackson.databind.DeserializationFeature">EAGER_DESERIALIZER_FETCH</feature> <!-- do not fail of only getter is provided --> <feature value="false" type="com.fasterxml.jackson.databind.DeserializationFeature">FAIL_ON_UNKNOWN_PROPERTIES</feature> <feature value="false" type="com.fasterxml.jackson.databind.MapperFeature">ALLOW_FINAL_FIELDS_AS_MUTATORS</feature> <feature value="true" type="com.fasterxml.jackson.core.JsonParser">ALLOW_UNQUOTED_FIELD_NAMES</feature> <!-- feature value="true">com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT</feature--> </features> </annotationInspectors> <dateFormat>MM/dd/yyyy</dateFormat> <defaultTyping type="NON_FINAL" key="type"/><!-- or e.g. OBJECT_AND_NON_CONCRETE --> <!-- cacheFilters>false</cacheFilters --> <!-- <escapeCharsGlobal>true</escapeCharsGlobal> --> <useJsonPath>true</useJsonPath> </json>
Jackson Version 1.9.x
<json> <annotationInspectors> <primary>org.apache.fulcrum.json.jackson.CustomIntrospector</primary> <secondary>org.codehaus.jackson.xc.JaxbAnnotationIntrospector</secondary> <features> <!-- support up to now only serializing features --> <feature value="false">org.codehaus.jackson.map.SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS</feature> <!-- feature value="true">org.codehaus.jackson.map.SerializationConfig.Feature.INDENT_OUTPUT</feature--> </features> </annotationInspectors> <dateFormat>MM/dd/yyyy</dateFormat> <!-- defaultTyping type="OBJECT_AND_NON_CONCRETE" key="type"/--> <!-- cacheFilters>false</cacheFilters--> </json>
Usage
You get a JSON service from the service like this:
JsonService jsonService = (JsonService)TurbineServices .getInstance().getService(JsonService.ROLE);
Usage in Velocity Template: Serialization Example
A lot of client data is nowadays provided by javascript and usage of Model-View-View Model (MVVM) frameworks is very popular. Having the required data in JSON format would be of some help. Velocity provides the integration of Java objects into templates (HTML). To generate in this context the data which should be exposed into Javascript you could integrate the provided serialization methods here, in the velocity context. As an example, you could provide it via the Turbine Pull service:
public Object getJson(Object src, String className, Boolean refresh, String... props ) { String result= null; try { Class clazz = Class.forName(className); result = jsonService.serializeOnlyFilter( src, clazz, refresh, props ); } catch ( Exception e ) { log.error(e.getMessage(),e ); } return result; }
#set ($json = $!pullTool.getJson($items, "x.y.z.Item", true, "prop1", "prop2", "prop3" ) ) ## parse json in javascript ....
Configuration Requirements
Add org.apache.fulcrum.json.jackson.SimpleNameIntrospector
to the annotation inspectors as primary or secondary inspector. [CHANGE in Version 1.1.0]: SimpleNameIntrospector now extends from NopAnnotationIntrospector to cleary divide responsibilities. Default introspector e.g. JacksonAnnotationIntrospector could be provided as a primary/secondary introspector in Component Configuration.
JSON to Object Deserialization
This could be done by providing the JSON data as client parameter to a JSON-RPC-Service function (cft. services->JSON-RPC-Service). As an example consider this:
// class is registered in screen public <T> void deSerJsonItem(String src ) { try { Item result = jsonService.deSer( src, Item.class ); // do something with result } catch ( Exception e ) { log.error(e.getMessage(),e ); } } }
jsonrpc.myFunctions.deSerJsonItem( JSON.stringify(jsonitem) );
JSON Service Component with GSON API
Overview
This Service serves as a JSON serializer or deserializer using GSON Version 2.3.1 The GSON sub module provides some include/exclude filtering strategies.
It is written for use in Turbine but it can be used in any container compatible with Avalon's ECM container.
Role Configuration
<role name="org.apache.fulcrum.json.JsonService" shorthand="json" default-class="org.apache.fulcrum.json.gson.GSONBuilderService"/>
Component Configuration
Item | Datatype | Cardinality | Description |
---|---|---|---|
globalAdapters | Complex | [0|1] |
If not set no adapter is set. Otherwise provide for each sub element adapter the class name of the adapter and set the attribute forClass to the class name the adapter should be applied. See the configuration example below.
|
dateFormat | String | [0|*] |
If set changes the date format. Provided string should be in a Format acceptable to the class java.text.SimpleDateFormat.SimpleDateFormat(String) . The default value is
MM/dd/yyyy .
|
useJsonPath | boolean | [0|1] |
If set to true , JsonPath is enabled, which allows to apply JsonPath expressions using the integrated gson provider by default. The default value is false . For more information see jackson2 component configuration property description.
|
Component Configuration Example
<json> <dateFormat>MM/dd/yyyy</dateFormat> <globalAdapters>> <adapter forClass="x.y.z.Class">a.b.c.d.AdapterForClassXYZ</adapter--> </globalAdapters> <useJsonPath>true</useJsonPath> </json>
Usage
You get a JSON service from the service like this:
JsonService jsonService = (JsonService)TurbineServices .getInstance().getService(JsonService.ROLE);