APACHE SLING & FRIENDS TECH MEETUP
BERLIN, 25-27 SEPTEMBER 2017
Fun Times with Sling Models Exporters
Justin Edelson, Adobe Systems
Sling Models – Reducing Boilerplate Since ‘14
2
§ OG
§ AdapterFactories
Roadmap from 2014
3
§ More Standard Injectors
§ SelfInjector, SlingObjectInjector
§ AEM-specific injectors in ACS AEM Commons
§ AemObjectsInjector
§ Pluggable @Via Support
§ Done this year
Der Mensch denkt und Gott lenkt
4
§ Injector-Specific Annotations
§ ModelFactory
§ Sling Validation Integration
§ Alternate Adapter Classes
§ BND Plugin
§ Exporter Framework
Sling Models – Reducing Boilerplate Since ‘14
5
§ OG
§ AdapterFactories
§ Exporter Framework
§ Format Conversion
§ Content Access Servlets
Use Cases
6
§ Customized content output for external
applications
§ Isomorphic rendering – use the same model
on the client and server
In a Nutshell
7
§ GET /content/something.model.json
1. Adapt the Resource to some model object
2. Transform that model to a String
3. Serve the String to the client
No Code Required*
How To
8
1. Add resourceType attribute to @Model
2. Add @Exporter(name = “jackson”, extension
= “json”)
3. (Optional) Annotate model
methods/properties.
How It Works
9
HTL Script
JSONHTML
Resource
Sling Model
Exporter
HTTP
Client
Jackson Exporter
1
2
4
5
1
HTTP GET Request is made for a resource in AEM
with the selector and extension registered with the
Sling Model’s Exporter.
Example: HTTP GET /content/my-resource.model.json
2
Sling resolves the the requested resource’s
sling:resourceType, selector and extension to a
dynamically generated Sling Exporter Servlet, which is
mapped to the Sling Model with Exporter.
4
e exporter serializes the Sling Model based
on the Exporter Options and Exporter-specic
Sling Model annotations and returns the
result to the Sling Exporter Servlet as a String.
5
e Sling Exporter Servlet returns the String
export of the Sling Model as the HTTP
Response.
Sling Exporter Servlet
Custom Exporters
3
3
e resolved Sling Exporter Servlet invokes the
Sling Model Exporter against the Sling Model
object adapted from the request or resource (as
determined by the Sling Models adaptables)
Handling Object Graphs
10
§ Q: Which class needs
@Exporter?
§ A: Only ParentComponent
§ @Exporter goes on the
HTTP entrypoint
title: String
child : ChildComponent
ParentComponent
property : String
ChildComponent
title: String
child : ChildComponent
@Model
@Exporter
ParentComponent
property : String
@Model
ChildComponent
Other Conversions – Not just for Strings!
11
§ ModelAdapterFactory.exportModel()
§ Examples:
§ Jackson – export to Map
§ JAXB – export to DOM Document
Multiple Exporters – Use @Exporters
12
@Model(adaptables=Resource.class,
resourceType="myco/something")
@Exporters({
@Exporter(name = "jackson",
extensions = "json"),
@Exporter(name = "gson", selector = "gson",
extensions = "json")
})
Exporter Options
13
§ Simple map of name/value pairs.
§ Semantics are up to ModelExporter impl.
§ Specified with
§ exportModel() API
§ @ExporterOption annotation
§ Selectors
§ Request parameters
Exporter Options - Jackson
14
§ “tidy
§ SerializationFeature.*
§ http://bit.ly/jack-serial
§ MapperFeature.*
§ http://bit.ly/jack-mapper
ExporterOption Examples
15
@ExporterOption(
name =
"SerializationFeature.WRITE_DATES_AS_TIMESTAMPS",
value = ”false")
GET /content/something.model.tidy.json
GET /content/something.model.json?tidy=true
16
Extension Points
Extension Point - ModelExporter
17
§ Defines a new
named exporter
getName() : String
isSupported(class) : boolean
export(model, class, options) : T
<<interface>>
ModelEx porter
ModelExporter Example - GSON
18
public <T> T export(Object model, Class<T> clazz,
Map<String, String> options)
throws ExportException {
return (T) new Gson().toJson(model);
}
ModelExporter Example - JAXB
19
public <T> T export(Object model, Class<T> clazz,
Map<String, String> options) throws ExportException {
try {
JAXBContext jaxbContext =
JAXBContext.newInstance(model.getClass());
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter sw = new StringWriter();
marshaller.marshal(model, sw);
return (T) sw.toString();
} catch (JAXBException e) { throw new ExportException(e); }
}
Extension Point – Jackson ModuleProvider
20
§ Customize serialization of classes outside
your codebase.
§ See http://bit.ly/jack-modules
§ Provided Examples:
§ Sling Resources
§ (Http|SlingHttp)?ServletRequest
§ java.util.Enumeration
Jackson ModuleProvider – Joda
21
import org.joda.time.DateTime;
public class TestModel {
public DateTime getTimestamp() {
return new DateTime();
}
}
Jackson ModuleProvider – Joda (no Module)
22
"timestamp" : {
"era" : 1, "dayOfYear" : 242, "dayOfWeek" : 3,
"dayOfMonth" : 30, "year" : 2017, "weekOfWeekyear" : 35,
"hourOfDay" : 12, "minuteOfHour" : 33, "monthOfYear" : 8,
"millisOfDay" : 45184141, "secondOfMinute" : 4, "millisOfSecond" : 141,
"weekyear" : 2017, "yearOfEra" : 2017, "yearOfCentury" : 17,
"centuryOfEra" : 20, "secondOfDay" : 45184, "minuteOfDay" : 753,
"zone" : {
"fixed" : false,
"uncachedZone" : {
"cachable" : true, "fixed" : false, "id" : "America/New_York
},
"id" : "America/New_York
},
"millis" : 1504110784141,
"chronology" : {
"zone" : {
"fixed" : false,
"uncachedZone" : {
"cachable" : true "fixed" : false, "id" : "America/New_York
},
"id" : "America/New_York
}
},
"afterNow" : false, "beforeNow" : true, "equalNow" : false
}
Jackson ModuleProvider - Joda
23
@Component
public class JodaModuleProvider
implements ModuleProvider {
public Module getModule() {
return new JodaModule();
}
}
Jackson ModuleProvider – Joda (w/ Module)
24
"timestamp" : 1504111214012
Summary
25
§ Model Objects -> JSON Servlets
§ Just add annotations
§ Supported by Jackson
§ Use ModuleProvider SPI for unowned classes
§ Other formats through ModelExporter SPI
26
Q&A
27
Thanks!