{"id":60976,"date":"2016-10-19T10:00:51","date_gmt":"2016-10-19T07:00:51","guid":{"rendered":"https:\/\/www.javacodegeeks.com\/?p=60976"},"modified":"2016-10-18T18:59:58","modified_gmt":"2016-10-18T15:59:58","slug":"command-interfaces-approaching-redis-dynamic-apis-java","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html","title":{"rendered":"Command Interfaces: Approaching Redis with dynamic APIs in Java"},"content":{"rendered":"<p>Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each major Redis release comes with new commands. This year Redis was opened up for 3rd party vendors to develop modules that extend Redis functionality. Command growth and keeping track with upcoming modules are challenging for client developers and Redis users.<\/p>\n<h2>Command growth<\/h2>\n<p>Command growth in Redis is a challenging business for client libraries. Several clients expose a typed API that declares a method (function) signature for each Redis API call. Static declarations are beneficial for use but the amount of Redis commands pollutes clients with tons of method signatures. Some commands can be executed in different ways that affects the response type (<code>ZREVRANGE<\/code>, <code>ZREVRANGE \u2026 WITHSCORES<\/code>) that require additional signatures. Let\u2019s take a closer look on some method signatures:<\/p>\n<p><strong>redis-rb<\/strong><\/p>\n<pre class=\"brush:java\"># Get the values of all the given hash fields.\r\n# \r\n# @example\r\n#   redis.hmget(\"hash\", \"f1\", \"f2\")\r\n  def hmget(key, *fields, &amp;blk)<\/pre>\n<p><strong>jedis<\/strong><\/p>\n<pre class=\"brush:java\">public List&lt;String&gt; hmget(final String key, final String... fields)<\/pre>\n<p><strong>lettuce<\/strong><\/p>\n<pre class=\"brush:java\">List&lt;V&gt;\r\npublic List&lt;K&gt; hmget(K key, K... fields)<\/pre>\n<p>Declared methods provide type safety and documentation to developers, but they are static at the same time. As soon as a Redis introduces a new command, the client vendor has to change the API otherwise new commands are not usable. Most Redis clients expose a client call API to execute custom commands to address this issue:<\/p>\n<p><strong>redis-rb<\/strong><\/p>\n<pre class=\"brush:java\">client.call([:hmget, key] + fields)<\/pre>\n<p><strong>jedis<\/strong><\/p>\n<pre class=\"brush:java\">final byte[][] params = \u2026;\r\njedis.sendCommand(HMGET, params);<\/pre>\n<p><strong>lettuce<\/strong><\/p>\n<pre class=\"brush:java\">lettuce.dispatch(CommandType.HMGET, new ValueListOutput&lt;&gt;(codec),\r\nnew CommandArgs&lt;&gt;(codec)\r\n   .addKey(key)\r\n   .addKey(field));<\/pre>\n<p><strong>Jedipus<\/strong><\/p>\n<pre class=\"brush:java\">rce.accept(client -&gt; client.sendCmd(Cmds.HMGET, \"hash\", \"field1\", \"field2\", \u2026));<\/pre>\n<p>Other clients, like <code>node_redis<\/code> create function prototypes based on Redis commands. This is an improvement to static APIs because it enables a certain flexibility in the API.<\/p>\n<p>Constructing a Redis command requires knowledge about its request and response structure. This knowledge is written down at a location inside of the calling code. This is handy because you put it in the place where you need the code, but it comes with a few downsides. Because custom commands are run from inside a method, custom commands require additional effort to be reusable. The typical method signature as found on many clients is not required. This approach makes introspection more challenging, if not following an API component approach. This is, because all custom commands call the same method with just different arguments.<\/p>\n<p>The nature of static method declarations with a fixed parameter list is limited to accept the provided parameters only. Contextual controls to method calls cannot be applied through that method. Lettuce for example provides a synchronous API that allows controlling the command timeout for all commands but not on command invocation level.<\/p>\n<p>Let\u2019s approach Redis with a dynamic API.<\/p>\n<h2>Dynamic API<\/h2>\n<p>Dynamic APIs are programming interfaces that give a certain amount of flexibility because they follow conventions. Dynamic APIs might be known from <a title=\"Resteasy Client Proxies\" href=\"https:\/\/docs.jboss.org\/resteasy\/docs\/3.0-beta-3\/userguide\/html\/RESTEasy_Client_Framework.html#d4e2049\">Resteasy Client Proxies<\/a> or <a href=\"http:\/\/docs.spring.io\/spring-data\/jpa\/docs\/current\/reference\/html\/#repositories.query-methods.query-creation\">Spring Data\u2019s Query Derivation<\/a>. Both are interfaces that live in userland code. Resteasy\/Spring Data inspect the interfaces and implement those by providing Java proxies. Method calls on these interfaces (proxies) are intercepted, inspected and translated into the according call. Let\u2019s see how this could work for Java and Redis:<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p><em>A simple command interface<\/em><\/p>\n<pre class=\"brush:java\">public interface MyRedisCommands {\r\n\r\n  List&lt;String&gt; hmget(String key, String... values);\r\n\r\n}<\/pre>\n<p>The interface from above declares one method: <code>List&lt;String &gt; hmget(String key, String... fields)<\/code>. We can derive from that declaration certain things:<\/p>\n<ul>\n<li>It should be executed synchronously \u2013 there\u2019s no asynchronous or reactive wrapper declared in the result type<\/li>\n<li>The Redis command method returns a <code>List<\/code> of <code>String<\/code>s \u2013 that tells us about the command result expectation, so we expect a Redis array and convert each item into a string<\/li>\n<li>The method is named <code>hmget<\/code>. As that\u2019s the only detail available, we assume the command is named <code>hmget<\/code>.<\/li>\n<li>There are two parameters defined: <code>String key<\/code> and <code>String... values<\/code>. This tells us about the order of parameters and their types. Although Redis does not take any other parameter types than bulk strings, we still can apply a transformation to the parameters \u2013 we can conclude their serialization from the declared type.<\/li>\n<\/ul>\n<p>The command from above called would look like:<\/p>\n<pre class=\"brush:java\">commands.hmget(\"key\", \"field1\", \"field2\");<\/pre>\n<p>and translated to a Redis Command:<\/p>\n<pre class=\"brush:java\">HMGET key field1 field2<\/pre>\n<p>The declaration on an interface comes with two interesting properties:<\/p>\n<ol>\n<li>There\u2019s a method signature. Although that\u2019s an obvious fact, it is a common executable that gets called. It allows analyzing callers quickly by building searching for references to this method.<\/li>\n<li>There\u2019s blank space above the method signature, ideally for documentation purposes.<\/li>\n<\/ol>\n<p><strong>Multiple execution models<\/strong><\/p>\n<pre class=\"brush:java\">public interface MyRedisCommands {\r\n\r\n  List&lt;String&gt; hmget(Timeout timeout, String key, String... values);\r\n\r\n  RedisFuture&lt;List&lt;String&gt;&gt; mget(String... keys);\r\n\r\n  Flux&lt;String&gt; smembers(String key);\r\n\r\n}<\/pre>\n<p>A dynamic API allows variance in return types. Let\u2019s see how this affects the things we could derive from their return types.<\/p>\n<ul>\n<li>You already know <code>hmget<\/code> is executed in a blocking way. But wait, what\u2019s that <code>Timeout<\/code> parameter? This is an own parameter type to declare a timeout on invocation level. The underlying execution applies timeouts from the parameter and no longer the defaults set on connection level.<\/li>\n<li><code>mget<\/code> declares a <code>RedisFuture<\/code> return type wrapping a <code>List<\/code> of <code>String<\/code>. <code>RedisFuture<\/code> is a wrapper type for asynchronous execution and returns a handle to perform synchronization or method chaining in a later stage. This method could be executed asynchronously.<\/li>\n<li><code>smembers<\/code> uses <code>Flux<\/code> of <code>String<\/code>. Based on the return type we can expect two properties: <code>Flux<\/code> is a reactive execution wrapper that delay execution until a subscriber subscribes to the <code>Flux<\/code>. The <code>List<\/code> type is gone because a <code>Flux<\/code> can emit <code>0..N<\/code> items so we can decide for a streaming reactive execution.<\/li>\n<\/ul>\n<p><strong>Command structure<\/strong><\/p>\n<pre class=\"brush:java\">public interface MyRedisCommands {\r\n\r\n  List&lt;String&gt; mget(String... keys);\r\n\r\n  @Command(\"MGET\")\r\n  RedisFuture&lt;List&lt;String&gt;&gt; mgetAsync(String... keys);\r\n\r\n  @CommandNaming(strategy = DOT)\r\n  double nrRun(String key, int... indexes)\r\n\r\n  @Command(\"NR.OBSERVE ?0 ?1 -&gt; ?2 TRAIN\")\r\n  List&lt;Integer&gt; nrObserve(String key, int[] in, int... out)\r\n}<\/pre>\n<p>Java requires methods to vary in name or parameter types. Variance in just the return type is supported at bytecode level but not when writing methods in your code. What if you want to declare one synchronously executed method and one that asynchronously executed taking the same parameters? You need to specify a different name. But doesn\u2019t this clash with the previously explained name derivation? It does.<\/p>\n<ul>\n<li>Take a closer look at <code>mget<\/code> and <code>mgetAsync<\/code>. Both methods are intended to execute the <code>MGET<\/code> command \u2013 synchronously and asynchronously. <code>mgetAsync<\/code> is annotated with <code>@Command<\/code> that provides the command name to the command and overrides the assumption that the method would be named <code>MGETASYNC<\/code> otherwise.<\/li>\n<li>Redis is open to modules. Each module can extend Redis by providing new commands where the command pattern follows the &lt;PREFIX&gt;.&lt;COMMAND&gt; guideline. However, dots are not allowed in Java method names. Let\u2019s apply a different naming strategy to <code>nrRun<\/code> with <code>@CommandNaming(strategy = DOT)<\/code>. Camel humps (changes in letter casing) are expressed by placing a dot between individual command segments and we\u2019re good to run <code>NR.RUN<\/code> from <a href=\"https:\/\/github.com\/antirez\/neural-redis#nrrun-key-i0-i1-i2-i3-i4--in\">Neural Redis<\/a>.<\/li>\n<li>Some commands come with a more sophisticated syntax that does not allow just concatenation of parameters. Take a look at <code>NR.OBSERVE<\/code>. It has three static parts with parameters in between. That command structure is expressed in a command-like language. <code>NR.OBSERVE ?0 ?1 -&gt; ?2 TRAIN<\/code> describes the command as string and puts in index references for arguments. All string parts in the command are constants and parameter references are replaces with the actual parameters.<\/li>\n<\/ul>\n<h2>Conclusion<\/h2>\n<p>Applying a dynamic API to Redis shifts the view to a new perspective. It can provide a simplified custom command approach to users without sacrificing reusability. The nature of method declaration creates a place for documentation and introspection regarding its callers.<\/p>\n<p>A dynamic API is beneficial also to other applications using RESP such as <a href=\"https:\/\/github.com\/antirez\/disque\">Disque<\/a> or <a href=\"https:\/\/github.com\/tidwall\/tile38\">Tile38<\/a>.<\/p>\n<p>An experimental implementation is available with <a href=\"https:\/\/github.com\/mp911de\/lettuce\">lettuce<\/a> from Sonatype\u2019s OSS Snapshot repository <a href=\"https:\/\/oss.sonatype.org\/content\/repositories\/snapshots\/\">https:\/\/oss.sonatype.org\/content\/repositories\/snapshots\/<\/a>:<\/p>\n<pre class=\"brush:java\">&lt;dependency&gt;\r\n     &lt;groupId&gt;biz.paluch.redis&lt;\/groupId&gt;\r\n     &lt;artifactId&gt;lettuce&lt;\/artifactId&gt;\r\n     &lt;version&gt;5.0.0-dynamic-api-SNAPSHOT&lt;\/version&gt;\r\n&lt;\/dependency&gt;<\/pre>\n<p><em>Using RedisCommandFactory<\/em><\/p>\n<pre class=\"brush:java\">RedisCommandFactory factory = new RedisCommandFactory(connection);\r\n\r\nTestInterface api = factory.getCommands(TestInterface.class);\r\nString value = api.get(\"key\");\r\n\r\npublic interface TestInterface {\r\n\r\n  String get(String key);\r\n\r\n  @Command(\"GET\")\r\n  byte[] getAsBytes(String key);\r\n}<\/pre>\n<h2>Reference<\/h2>\n<ul>\n<li><code>@Command<\/code>: Command annotation specifying a command name or the whole command structure by using a command-like language.<\/li>\n<li><code>@CommandNaming<\/code>: Annotation to specify the command naming strategy.<\/li>\n<li><code>Timeout<\/code>: Value object containing a timeout.<\/li>\n<li><code>RedisFuture<\/code>: A Future result handle.<\/li>\n<li><code>Flux<\/code>: <a href=\"\/projectreactor.io\">Project Reactor<\/a> publisher for reactive execution that emits <code>0..N<\/code> items.<\/li>\n<\/ul>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"http:\/\/paluch.biz\/blog\/168-command-interfaces-approaching-redis-with-dynamic-apis-in-java.html\">Command Interfaces: Approaching Redis with dynamic APIs in Java<\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/join-us\/jcg\/\">JCG partner<\/a> Mark Paluch at the <a href=\"http:\/\/paluch.biz\">paluch.biz<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each major Redis release comes with new commands. This year Redis was opened up for 3rd party vendors to develop modules that extend Redis functionality. Command growth and keeping track with upcoming modules are &hellip;<\/p>\n","protected":false},"author":961,"featured_media":223,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[117],"class_list":["post-60976","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-redis"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Command Interfaces: Approaching Redis with dynamic APIs in Java - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Command Interfaces: Approaching Redis with dynamic APIs in Java - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2016-10-19T07:00:51+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Mark Paluch\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mp911de\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mark Paluch\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html\"},\"author\":{\"name\":\"Mark Paluch\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/6784fa28c2d80a98d0b0a6c96bd0cc66\"},\"headline\":\"Command Interfaces: Approaching Redis with dynamic APIs in Java\",\"datePublished\":\"2016-10-19T07:00:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html\"},\"wordCount\":1212,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"keywords\":[\"Redis\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html\",\"name\":\"Command Interfaces: Approaching Redis with dynamic APIs in Java - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"datePublished\":\"2016-10-19T07:00:51+00:00\",\"description\":\"Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2016\\\/10\\\/command-interfaces-approaching-redis-dynamic-apis-java.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Command Interfaces: Approaching Redis with dynamic APIs in Java\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/6784fa28c2d80a98d0b0a6c96bd0cc66\",\"name\":\"Mark Paluch\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3c9eb4e924137ebf74d238ca26f809744f2b7bd259994e226abed8029c3af84b?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3c9eb4e924137ebf74d238ca26f809744f2b7bd259994e226abed8029c3af84b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3c9eb4e924137ebf74d238ca26f809744f2b7bd259994e226abed8029c3af84b?s=96&d=mm&r=g\",\"caption\":\"Mark Paluch\"},\"description\":\"Mark is a software craftsman, did just about every job in IT, open source committer, and is passionate about dev culture. Particularly interested in hardware hacking and internet of things. Mark helps development teams to improve continuously during their software endeavor to achieve outstanding performance.\",\"sameAs\":[\"http:\\\/\\\/paluch.biz\",\"https:\\\/\\\/x.com\\\/mp911de\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/mark-paluch\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Command Interfaces: Approaching Redis with dynamic APIs in Java - Java Code Geeks","description":"Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html","og_locale":"en_US","og_type":"article","og_title":"Command Interfaces: Approaching Redis with dynamic APIs in Java - Java Code Geeks","og_description":"Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each","og_url":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2016-10-19T07:00:51+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","type":"image\/jpeg"}],"author":"Mark Paluch","twitter_card":"summary_large_image","twitter_creator":"@mp911de","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Mark Paluch","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html"},"author":{"name":"Mark Paluch","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/6784fa28c2d80a98d0b0a6c96bd0cc66"},"headline":"Command Interfaces: Approaching Redis with dynamic APIs in Java","datePublished":"2016-10-19T07:00:51+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html"},"wordCount":1212,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","keywords":["Redis"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html","url":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html","name":"Command Interfaces: Approaching Redis with dynamic APIs in Java - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","datePublished":"2016-10-19T07:00:51+00:00","description":"Redis is a data store supporting over 190 documented commands and over 450 command permutations. The community supports actively Redis development; each","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2016\/10\/command-interfaces-approaching-redis-dynamic-apis-java.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Command Interfaces: Approaching Redis with dynamic APIs in Java"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/6784fa28c2d80a98d0b0a6c96bd0cc66","name":"Mark Paluch","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/3c9eb4e924137ebf74d238ca26f809744f2b7bd259994e226abed8029c3af84b?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/3c9eb4e924137ebf74d238ca26f809744f2b7bd259994e226abed8029c3af84b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3c9eb4e924137ebf74d238ca26f809744f2b7bd259994e226abed8029c3af84b?s=96&d=mm&r=g","caption":"Mark Paluch"},"description":"Mark is a software craftsman, did just about every job in IT, open source committer, and is passionate about dev culture. Particularly interested in hardware hacking and internet of things. Mark helps development teams to improve continuously during their software endeavor to achieve outstanding performance.","sameAs":["http:\/\/paluch.biz","https:\/\/x.com\/mp911de"],"url":"https:\/\/www.javacodegeeks.com\/author\/mark-paluch"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/60976","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/961"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=60976"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/60976\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/223"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=60976"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=60976"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=60976"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}