{"id":21726946,"url":"https://github.com/wttech/slice","last_synced_at":"2025-04-12T23:33:22.869Z","repository":{"id":4750848,"uuid":"5900702","full_name":"wttech/Slice","owner":"wttech","description":"Slice - a framework which simplifies Sling/AEM development by using dependency injection pattern and mapping Sling resources into Java objects","archived":false,"fork":false,"pushed_at":"2021-06-14T10:15:51.000Z","size":11566,"stargazers_count":65,"open_issues_count":7,"forks_count":26,"subscribers_count":56,"default_branch":"master","last_synced_at":"2025-03-26T17:42:26.452Z","etag":null,"topics":["aem","apache-sling","dependency-injection","google-guice","guice","htl","java","sightly","sling"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"mjackson/mach","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wttech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-09-21T11:52:26.000Z","updated_at":"2024-12-20T15:38:24.000Z","dependencies_parsed_at":"2022-09-26T21:40:41.314Z","dependency_job_id":null,"html_url":"https://github.com/wttech/Slice","commit_stats":null,"previous_names":["cognifide/slice"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wttech%2FSlice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wttech%2FSlice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wttech%2FSlice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wttech%2FSlice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wttech","download_url":"https://codeload.github.com/wttech/Slice/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248647259,"owners_count":21139081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aem","apache-sling","dependency-injection","google-guice","guice","htl","java","sightly","sling"],"created_at":"2024-11-26T03:42:18.572Z","updated_at":"2025-04-12T23:33:22.849Z","avatar_url":"https://github.com/wttech.png","language":"Java","readme":"![Wunderman Thompson Technology logo](./assets/wtt-logo.png)\r\n\r\n[![Build Status](https://travis-ci.org/Cognifide/Slice.svg?branch=master)](https://travis-ci.org/Cognifide/Slice)\r\n[![Coverity Status](https://scan.coverity.com/projects/4863/badge.svg)](https://scan.coverity.com/projects/4863)\r\n[![Coverage Status](https://coveralls.io/repos/Cognifide/Slice/badge.svg)](https://coveralls.io/r/Cognifide/Slice)\r\n[![Latest release](https://maven-badges.herokuapp.com/maven-central/com.cognifide.slice/slice-assembly/badge.svg)](http://mvnrepository.com/artifact/com.cognifide.slice/slice-assembly)\r\n\r\n# Slice\r\n\r\n\u003cbr\u003e\r\n\u003cp align=\"center\"\u003e\r\n  \u003cimg src=\"assets/slice_logo.png\" alt=\"Slice Logo\"/\u003e\r\n\u003c/p\u003e\r\n\u003cbr\u003e\r\n\r\n## Purpose\r\n\r\nSlice is a framework which simplifies Sling/Adobe AEM development by using dependency injection pattern (DI). It glues Sling and Google Guice together, allowing developers to create a code with a clean separation of concerns. You can map resources to Java models seamlessly and thanks to DI arrange your application in easily testable and maintainable code.\r\n\r\n**What can you gain?**\r\n * Lean and neat code, slicker design!\r\n * Improved testability of your code - thanks to dependency injection it can be easily unit-tested.\r\n * Improved maintenance of your code - all business logic arranged in clean and simple Java classes (POJOs)\r\n * Easy to start with! Slice is easy to learn and if you use it in all your projects, your developers know exactly how to start.\r\n * Faster development – code reuse, dependency injection and simplicity make you more efficient than ever.\r\n * Overall costs reduced!\r\n\r\n## Features\r\n### Separation of concerns\r\nNo more business logic in your view (JSP, [HTL](https://docs.adobe.com/docs/en/htl/overview.html) scripts) - business logic's place is in Java classes and Slice knows it!\r\n\r\n**Slice loves HTL**. HTL loves Slice. They go together like strawberries and cream! Seamless integration you will love:\r\n```html\r\n\u003cdiv data-sly-use.model=\"com.example.components.text.TextModel\"\u003e\r\n    \u003cp\u003e${model.text}\u003cp\u003e\r\n\u003c/div\u003e\r\n```\r\n\r\n**JSPs made clean and tidy** - no more ugly scriptlets.\r\n```jsp\r\n\u003cslice:lookup var=\"model\" type=\"\u003c%=com.example.components.text.TextModel%\u003e\" /\u003e\r\n\u003cp\u003e${model.text}\u003c/p\u003e\r\n```\r\n\r\n**Reusable Java models** which expose data for your view - note that the same model can be used by HTL and JSP components - one model to feed them all!\r\n```java\r\n@SliceResource\r\npublic class TextModel {\r\n  \r\n    @JcrProperty\r\n    private String text;\r\n  \r\n    public String getText() {\r\n        return text;\r\n    }\r\n}\r\n```\r\n\r\nInterested in details? Read about [Slice concepts](https://cognifide.atlassian.net/wiki/display/SLICE/Slice+concepts+-+4.4) and [how it works internally](https://cognifide.atlassian.net/wiki/display/SLICE/How+exactly+does+it+work+-+4.4) on our Wiki.\r\n\r\n### Mapping resources to Java objects\r\n\r\nSlice allows you to map a resource to a plain Java object. It's annotation-driven, very easy to use and fully extensible, so you can write your own ways of mapping if a set of available features is not enough for your needs. Slice supports mapping of:\r\n * simple properties (`String`, `Long`, `Boolean`, etc.) into primitives and objects\r\n * simple properties into enums.\r\n * multi-value properties to arrays or lists\r\n * child resources to a Java object or list of objects\r\n * nested resources/classes hierarchy\r\n \r\nThe following code snippet demonstrates all of the above features in one model. It's simple - just annotate a class with `@SliceResource` and its fields with `@JcrProperty` to get auto mapping of resource properties to class fields:\r\n\r\n```java\r\n@SliceResource\r\npublic class ComplexTextModel {\r\n\r\n\t@JcrProperty\r\n\tprivate String text;\r\n\t\r\n\t@JcrProperty\r\n\tprivate String[] styles;\r\n\r\n\t@JcrProperty\r\n\tprivate AlignmentEnum alignment;\r\n\r\n\t@Children(LinkModel.class)\r\n\t@JcrProperty\r\n\tprivate List\u003cLinkModel\u003e links;\r\n\t\r\n\t@JcrProperty\r\n\tprivate ImageModel image;\r\n\r\n\t//... do whatever business logic you want in your model\r\n}\r\n\r\npublic enum AlignmentEnum {\r\n\tLEFT, RIGHT, CENTER;\r\n}\r\n\r\n@SliceResource(MappingStrategy.ALL)\r\npublic class LinkModel {\r\n\tprivate String path;\r\n\tprivate String label;\r\n\t//...\r\n}\r\n\r\n@SliceResource(MappingStrategy.ALL)\r\npublic class ImageModel {\r\n\tprivate String imagePath;\r\n\tprivate String altText;\r\n\t//...\r\n}\r\n```\r\n\r\nRead more about mapping on our [Wiki](https://cognifide.atlassian.net/wiki/display/SLICE/Mapper+-+4.4).\r\n\r\n\r\n### Dependency Injection with Google Guice\r\n\r\nIf your AEM components are more than simple text/image/title components (and they certainly are), then you probably need to combine their functionality with some external data or more complex business logic provided by other classes. Dependency injection allows you to do this easily and keep your code testable without boiler-plate code and unneeded arguments in methods used only to propagate a value down into the class hierarchy.\r\n\r\nWe took Guice as a DI container. Why it's awesome? Take a look here: [Google I/O 2009 - Big Modular Java with Guice](https://www.youtube.com/watch?v=hBVJbzAagfs), and here to check [motivation of Google Guice creators](https://code.google.com/p/google-guice/wiki/)\r\n\r\nTo demonstrate an example of a complex component which combines use of Slice features with power of DI, take a look at the following code which is an implementation of a Twitter component.\r\n\r\n```html\r\n\u003cdiv data-sly-use.model=\"com.example.components.twitter.TwitterModel\"\u003e\r\n\t\u003cul data-sly-list=\"${model.tweets}\"\u003e\r\n\t\t\u003cli\u003e${item}\u003c/li\u003e\r\n\t\u003c/ul\u003e\r\n\u003c/div\u003e\r\n```\r\n\r\n```java\r\n@SliceResource\r\npublic class TwitterModel {\r\n\r\n\t@JcrProperty\r\n\tprivate int limit;\r\n\r\n\tprivate final TwitterHandler twitterHandler;\r\n\t\r\n\t@Inject\r\n\tpublic TwitterModel(TwitterHandler twitterHandler) {\r\n\t\tthis.twitterHandler = twitterHandler;\r\n\t}\r\n\r\n\t//returns list of tweets limited by number configurable by authors\r\n\tpublic List\u003cString\u003e getTweets() {\r\n\t\tList\u003cString\u003e tweets = twitterHandler.readTweets();\r\n\t\treturn tweets.subList(0, Math.max(tweets.size(), limit));\r\n\t}\r\n\t\r\n\t//...\r\n}\r\n```\r\n\r\nThe model of the component is fairly simple and fully testable because you can easily mock the TwitterHandler in your unit test case.\r\n\r\nTwitterHandler is also very simple as it uses Twitter client (from Twitter4j library). Please note that this client is injected by Guice and you don't have to care about its configuration in the handler itself.\r\n\r\n```java\r\npublic class TwitterHandler {\r\n\r\n\t@Inject\r\n\tprivate Twitter twitterClient; //Twitter4j client\r\n\r\n\tpublic List\u003cString\u003e readTweets() {\r\n\t\tList\u003cString\u003e tweets = new ArrayList\u003cString\u003e();\r\n\t\tList\u003cStatus\u003e statuses = twitterClient.getHomeTimeline();\r\n\t\tfor (Status status : statuses) {\r\n\t\t\ttweets.add(status.getText());\r\n\t\t}\r\n\t\treturn tweets;\r\n\t}\r\n}\r\n```\r\n\r\nThe configuration is set while instantiating the twitter client by Guice. To instruct Guice how to create the client object we need to create a so called [provider](https://code.google.com/p/google-guice/wiki/ProvidesMethods). You can do this in module configuration. It reads some configuration properties from repository (using ModelProvider). ContextScope instructs Guice to create such an object only once per request or OSGi service call - yes, you can reuse the TwitterHandler in you OSGi services which are request/resource agnostic - that's the power of Slice!.\r\n\r\n```java\r\npublic class MyModule extends AbstractModule {\r\n\r\n\tprivate static final String TWITTER_CONFIG_PATH = \"/etc/twitter/configuration/jcr:content/twitterConfig\";\r\n\r\n\t@Provides\r\n\t@ContextScoped\r\n\tpublic Twitter getTwitter(ModelProvider modelProvider) {\r\n\t\tTwitterConfiguration config = modelProvider.get(TwitterConfiguration.class,\r\n\t\t\t\tTWITTER_CONFIG_PATH);\r\n\t\tConfigurationBuilder builder = new ConfigurationBuilder(); // from Twitter4j\r\n\t\tbuilder.setOAuthConsumerKey(config.getOAuthKey())\r\n\t\t\t\t.setOAuthConsumerSecret(config.getOAuthSecret());\r\n\t\tTwitterFactory factory = new TwitterFactory(builder.build());\r\n\t\treturn factory.getInstance();\r\n\t}\r\n\r\n\t//...\r\n\r\n}\r\n```\r\n\r\n## Prerequisites\r\n\r\n* AEM / Apache Sling 2\r\n* Maven 2.x, 3.x\r\n\r\n## Installation\r\n\r\nSlice is available from the Maven Central Repo. However if you want to check out the newest development version, do the following:\r\n\r\nCheckout the source code:\r\n\r\n    cd [folder of your choice]\r\n    git clone git://github.com/wttech/Slice.git\r\n    cd Slice\r\n\r\nCompile and install:\r\n\r\n    mvn install\r\n\r\n## Usage\r\n\r\nAdd dependencies to your POM file:\r\n\r\n```xml\r\n(...)\r\n\u003cdependency\u003e\r\n\t\u003cgroupId\u003ecom.cognifide.slice\u003c/groupId\u003e\r\n\t\u003cartifactId\u003eslice-core-api\u003c/artifactId\u003e\r\n\t\u003cversion\u003e4.4.0\u003c/version\u003e\r\n\u003c/dependency\u003e\r\n\u003cdependency\u003e\r\n\t\u003cgroupId\u003ecom.cognifide.slice\u003c/groupId\u003e\r\n\t\u003cartifactId\u003eslice-core\u003c/artifactId\u003e\r\n\t\u003cversion\u003e4.4.0\u003c/version\u003e\r\n\u003c/dependency\u003e\r\n\u003cdependency\u003e\r\n\t\u003cgroupId\u003ecom.cognifide.slice\u003c/groupId\u003e\r\n\t\u003cartifactId\u003eslice-mapper\u003c/artifactId\u003e\r\n\t\u003cversion\u003e4.4.0\u003c/version\u003e\r\n\u003c/dependency\u003e\r\n\u003cdependency\u003e\r\n\t\u003cgroupId\u003ecom.cognifide.slice\u003c/groupId\u003e\r\n\t\u003cartifactId\u003eslice-mapper-api\u003c/artifactId\u003e\r\n\t\u003cversion\u003e4.4.0\u003c/version\u003e\r\n\u003c/dependency\u003e\r\n(...)\r\n```\r\n\r\nThe last thing you need to do is to prepare an `Injector` of your application in its `BundleActivator`. Read more on how to do this on our [Wiki](https://cognifide.atlassian.net/wiki/display/SLICE/Setting+up+-+4.4)\r\n\r\nAEM/CQ related add-ons:\r\n* Slice AEM v6.3, 6.2, 6.1, 6.0 Addon: https://github.com/Cognifide/Slice-AEM60\r\n* Slice CQ v5.6 Addon: https://github.com/Cognifide/Slice-CQ56/\r\n* Slice CQ v5.5 Addon: https://github.com/Cognifide/Slice-CQ55/\r\n\r\n\r\n# Commercial Support\r\n\r\nTechnical support can be made available if needed. Please [contact us](mailto:labs-support@cognifide.com) for more details.\r\n\r\nWe can:\r\n\r\n* prioritize your feature request,\r\n* tailor the product to your needs,\r\n* provide a training for your engineers,\r\n* support your development teams.\r\n\r\n\r\n# More documentation\r\n------------------\r\n* [Full documentation of Slice 4.5](https://cognifide.atlassian.net/wiki/display/SLICE/Slice+4.5)\r\n* [Slice Wiki](https://cognifide.atlassian.net/wiki/display/SLICE)\r\n* [Slice users mailing group](http://slice-users.2340343.n4.nabble.com/) if you have any question on how to use it\r\n* [Slice issue tracking](https://cognifide.atlassian.net/browse/SLICE)\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwttech%2Fslice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwttech%2Fslice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwttech%2Fslice/lists"}