<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paul Hameteman</title>
    <description>The latest articles on DEV Community by Paul Hameteman (@hameteman).</description>
    <link>https://dev.to/hameteman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F153477%2F1b8247e0-767d-41f1-9652-9f81cead2b89.jpeg</url>
      <title>DEV Community: Paul Hameteman</title>
      <link>https://dev.to/hameteman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hameteman"/>
    <language>en</language>
    <item>
      <title>An Introduction to Paparazzi for Snapshot Testing</title>
      <dc:creator>Paul Hameteman</dc:creator>
      <pubDate>Thu, 03 Aug 2023 05:28:36 +0000</pubDate>
      <link>https://dev.to/hameteman/an-introduction-to-paparazzi-for-snapshot-testing-5aai</link>
      <guid>https://dev.to/hameteman/an-introduction-to-paparazzi-for-snapshot-testing-5aai</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KMQ77nxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zibconslpzfjkwqty7hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KMQ77nxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zibconslpzfjkwqty7hw.png" alt="An Introduction to Paparazzi for Snapshot Testing" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: Snapshot testing with Paparazzi allows you to ensure your Jetpack Compose components behave as expected, without needing an emulator. This article covers setting up Paparazzi, creating a simple Tag composable, and using Paparazzi to create, verify, and update snapshot tests for your Android app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What is Snapshot Testing?
&lt;/h3&gt;

&lt;p&gt;Snapshot testing allows you to ensure that your output continues to behave as expected. This is useful because as you revisit your code, some changes might cause something to break.&lt;/p&gt;

&lt;p&gt;When writing snapshot tests for Jetpack Compose components, you first need to have your code in a working state. Then generate a snapshot of its expected output given certain data. The snapshot tests are committed alongside the component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cashapp/paparazzi"&gt;Paparazzi&lt;/a&gt; is an Android library you can use to create those snapshots for your apps in a simple and friendly way and compare them. One of the advantages this library has over its competitor &lt;a href="https://github.com/pedrovgs/Shot"&gt;Shot&lt;/a&gt; is that it doesn't need an emulator to run the tests, it just runs in the unit test stage which is &lt;em&gt;much&lt;/em&gt; faster.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cashapp"&gt;
        cashapp
      &lt;/a&gt; / &lt;a href="https://github.com/cashapp/paparazzi"&gt;
        paparazzi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Render your Android screens without a physical device or emulator
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Set up
&lt;/h3&gt;

&lt;p&gt;Let's begin the setup process for our first test! To get started, we need to make some changes to the root &lt;code&gt;build.gradle&lt;/code&gt; file. First, we'll add the necessary dependency for Paparazzi and apply the plugin. The latest version available at the time of writing is 1.3.1.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;build.gradle&lt;/code&gt; file should look like this after adding the dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buildscript {
    // ... Repositories and other settings
    dependencies {
        classpath 'app.cash.paparazzi:paparazzi-gradle-plugin:1.3.1'
        // ... Other dependencies
    }
}

// ... The rest of your build.gradle content

apply plugin: 'app.cash.paparazzi'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in your Android library or app module, we need to include the Paparazzi plugin in the plugins block within &lt;code&gt;build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins {
    // Other plugin ids
    id 'app.cash.paparazzi'
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making these changes, perform a Gradle sync to complete the setup process. Now, we are all set to create our first snapshot using Paparazzi!&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the first snapshot test
&lt;/h3&gt;

&lt;p&gt;Let's create a simple Tag composable of which we can make a snapshot later on. Normally a component like this would also have support for click interactions and accessibility. For brevity, we will leave these out in this example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun Tag(
    name: String,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor)
) {
    Text(
        text = "#$name".toLowerCase(Locale.current),
        modifier = modifier
            .background(
                color = backgroundColor,
                shape = MaterialTheme.shapes.small
            )
            .padding(horizontal = 4.dp, vertical = 2.dp),
        color = contentColor,
        fontSize = 12.sp
    )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will end up in a component looking like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8iK_0hpQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1690953159374/44670216-e6c4-4c03-8c02-4eef08c2a339.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8iK_0hpQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1690953159374/44670216-e6c4-4c03-8c02-4eef08c2a339.png" alt="A purple tag with the word tag on it" width="90" height="56"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, let's create the snapshot test. Create a new test and make sure to place it inside the &lt;code&gt;unitTest&lt;/code&gt; folder instead of &lt;code&gt;androidTest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;TagTest&lt;/code&gt; class, add the Paparazzi rule, use rendering mode &lt;code&gt;SHRINK&lt;/code&gt; here if you only want to capture the component instead of the whole screen of the device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@get:Rule
val paparazzi = Paparazzi(
    deviceConfig = DeviceConfig.NEXUS_5.copy(softButtons = false),
    renderingMode = SessionParams.RenderingMode.SHRINK
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a test to render the component like so;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
fun testTag() {
    paparazzi.snapshot("Tag") {
        MaterialTheme {
            Tag(name = "Snapshot-Test")
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we've added Paparazzi to the Gradle files already, there are now 2 additional tasks that you can run.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;verifyPaparazziDebug&lt;/code&gt; -- Runs tests and verifies against previously-recorded golden values. Failures generate diffs at &lt;code&gt;build/paparazzi/failures&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recordPaparazziDebug&lt;/code&gt; -- Saves snapshots as golden values to a predefined source-controlled location (defaults to &lt;code&gt;src/test/snapshots&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because we haven't created the golden values yet, running the verify task now will result in a failed test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./gradlew :app:verifyPaparazziDebug

&amp;gt; Task :app:testReleaseUnitTest

com.appsoluut.paparazzi.tag.TagTest &amp;gt; testTag FAILED
    java.lang.AssertionError at TagTest.kt:19

* What went wrong:
Execution failed for task ':app:testReleaseUnitTest'.
&amp;gt; There were failing tests. See the report at: file://android/paparazzi/app/build/reports/tests/testReleaseUnitTest/index.html

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating the golden values is simple. Look at the tasks table above and see you only need to run the &lt;code&gt;recordPaparazziDebug&lt;/code&gt; task to start recording. If it doesn't already exists, a new &lt;code&gt;snapshots&lt;/code&gt; folder will be created in the &lt;code&gt;src/test&lt;/code&gt; directory. This will contain our snapshot and should look something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_XcyMB7e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1691039337150/a2c56181-55a3-4355-a2b9-9cd93ab1ee1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_XcyMB7e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1691039337150/a2c56181-55a3-4355-a2b9-9cd93ab1ee1f.png" alt="Golden value snapshot" width="291" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you would run the &lt;code&gt;verifyPaparazziDebug&lt;/code&gt; task again, all tests should report successfully. But let's make it more interesting and break the snapshot! Remove the &lt;code&gt;.toLowerCase(Locale.current)&lt;/code&gt; part from the Tag composable so we have minimal changes. Run the &lt;code&gt;verifyPaparazziDebug&lt;/code&gt; task again and see what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Task :app:testDebugUnitTest FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:testDebugUnitTest'.
&amp;gt; There were failing tests. See the report at: file://android/paparazzi/app/build/reports/tests/testDebugUnitTest/index.html

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unsurprisingly the test failed. You can either open up the HTML report and get a written report of what was going wrong, but that one will only tell you the percentage difference or if the size has changed of the snapshot.&lt;/p&gt;

&lt;p&gt;More interesting is to see the actual difference in the snapshot. The tasks will now have created 2 output files which can be found in the &lt;code&gt;build/paparazzi/outputs&lt;/code&gt; directory. The &lt;code&gt;delta&lt;/code&gt; variant will show the expected, difference and actual snapshot in one handy image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DkIbQCvw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1691040059231/7a95f530-6dad-4322-b379-d7815dbc87f1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DkIbQCvw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1691040059231/7a95f530-6dad-4322-b379-d7815dbc87f1.png" alt="Delta view" width="800" height="56"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's directly clear from the above image what the problem is. If this was expected to change, you can just run the &lt;code&gt;recordPaparazziDebug&lt;/code&gt; task again to update the golden values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final words
&lt;/h3&gt;

&lt;p&gt;I hope this article helped you get a basic understanding of snapshot testing and inspired you to add them to your project. The next part in this series will be adding the tests to be part of your CI/CD setup.&lt;/p&gt;

</description>
      <category>android</category>
      <category>ui</category>
      <category>testing</category>
      <category>jetpackcompose</category>
    </item>
    <item>
      <title>How-to not clear the logcat on a crash</title>
      <dc:creator>Paul Hameteman</dc:creator>
      <pubDate>Mon, 13 Dec 2021 08:51:24 +0000</pubDate>
      <link>https://dev.to/hameteman/how-to-not-clear-the-logcat-on-a-crash-1phi</link>
      <guid>https://dev.to/hameteman/how-to-not-clear-the-logcat-on-a-crash-1phi</guid>
      <description>&lt;p&gt;It is already annoying that your app crashes. But even more so when you can’t find the crash in the logcat due to the app restarting on either the emulator or a physical device.&lt;/p&gt;

&lt;p&gt;Luckily, there is a very simple and quick solution for this, it stops Android Studio from clearing the logcat which means you can stop trying to reproduce it multiple times or are forced to use the command line. You can just start fixing the actual error instead.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6kQPkBUL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swva3h7adh9ctp7t7yuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6kQPkBUL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swva3h7adh9ctp7t7yuz.png" alt="Image description" width="436" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It only consists of two steps, first open the logcat window in your Android Studio if it’s not already there. On the top right you see the filters dropdown. Open this and select &lt;em&gt;Edit Filter Configuration&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Create New Logcat Filter&lt;/em&gt; window fill in the &lt;em&gt;Package Name&lt;/em&gt; of your application. In my case it is &lt;code&gt;eu.walkthecity&lt;/code&gt;. You can fill in anything you want in &lt;em&gt;Filter Name&lt;/em&gt; but I would recommend to put the name of your application there so you can easily find it back if you’re working on multiple apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CjnECx6f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iot5hc0t6gr4toz165te.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CjnECx6f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iot5hc0t6gr4toz165te.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Log Level&lt;/em&gt; can be set to anything you want as crashes are always reported as &lt;em&gt;Error&lt;/em&gt;. I used &lt;em&gt;Verbose&lt;/em&gt; so I can just leave this filter on when looking for my debug messages as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Voila&lt;/em&gt;, you’re done. Simple right? Now back to more important stuff and get those amazing apps out there!&lt;/p&gt;

</description>
      <category>android</category>
      <category>androidstudio</category>
      <category>howto</category>
      <category>tipsandtricks</category>
    </item>
    <item>
      <title>Android Jetifier — Can we say Bye-Bye yet</title>
      <dc:creator>Paul Hameteman</dc:creator>
      <pubDate>Thu, 11 Nov 2021 15:30:16 +0000</pubDate>
      <link>https://dev.to/hameteman/android-jetifier-can-we-say-bye-bye-yet-560m</link>
      <guid>https://dev.to/hameteman/android-jetifier-can-we-say-bye-bye-yet-560m</guid>
      <description>&lt;p&gt;A couple of years ago Google deprecated the support libraries in favor of the new AndroidX library. Jetifier is a tool to do this conversion for you if you are using libraries that still depend on those deprecated support libraries. However, doing this conversion every build might be time consuming and it might not even be needed anymore by this time.&lt;/p&gt;

&lt;p&gt;“&lt;em&gt;But how do I know if it is still useful?&lt;/em&gt;” I hear you ask. Fortunately there is a &lt;a href="https://github.com/dipien/bye-bye-jetifier" rel="noopener noreferrer"&gt;Bye Bye Jetifier&lt;/a&gt; Gradle plugin available by &lt;a href="https://www.dipien.com" rel="noopener noreferrer"&gt;Dipien&lt;/a&gt; that has the answer!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dipien" rel="noopener noreferrer"&gt;
        dipien
      &lt;/a&gt; / &lt;a href="https://github.com/dipien/bye-bye-jetifier" rel="noopener noreferrer"&gt;
        bye-bye-jetifier
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Gradle Plugin to verify if you can keep Android Jetifier disabled
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Two simple steps to get you started
&lt;/h2&gt;

&lt;p&gt;Luckily it is very easy to get started! Just add the following dependency to your app &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buildscript {
  dependencies {
    classpath "com.dipien:bye-bye-jetifier:1.2.0"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The version at the time of this writing was 1.2.0.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At the end of the same &lt;code&gt;build.gradle&lt;/code&gt; file, apply the plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apply plugin: "com.dipien.byebyejetifier"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’re all set. Now when you run the Gradle command &lt;code&gt;./gradlew canISayByeByeJetifier -Pandroid.enableJetifier=false&lt;/code&gt; in a terminal, you'll get an output telling you if your project is still depending on Jetifier or not. In my case I still have to do some more maintenance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9e64nrrrccf6blsdq9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9e64nrrrccf6blsdq9p.png" alt="Failing "&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;You can not say Bye Bye Jetifier&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>jetifier</category>
      <category>androidx</category>
      <category>gradle</category>
    </item>
    <item>
      <title>Gson using AutoValue and Polymorphism</title>
      <dc:creator>Paul Hameteman</dc:creator>
      <pubDate>Mon, 19 Jul 2021 06:52:44 +0000</pubDate>
      <link>https://dev.to/hameteman/gson-using-autovalue-and-polymorphism-2470</link>
      <guid>https://dev.to/hameteman/gson-using-autovalue-and-polymorphism-2470</guid>
      <description>&lt;p&gt;Recently, I ran into a situation where a RESTful API provided me with a list of objects. Normally this isn’t a problem since REST provides you with a structure that is easy to convert. The catch was that some objects inside other objects were polymorphic and required to parse specific fields.&lt;/p&gt;

&lt;p&gt;The previous solution was to have a HashMap that contained all the supplied fields. The application then needed to check what kind of object was returned and decide if all required key-value pairs were filled with usable data. This was not a preferred solution and prone to errors.&lt;/p&gt;

&lt;p&gt;A lot of suggestions were made to look into custom (de)serializers, which is a good idea, but also a lot of work. I came across the “hidden” &lt;a href="https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java"&gt;RuntimeTypeAdapterFactory&lt;/a&gt; class in the Gson repository which solved most of my problem quite nicely.&lt;/p&gt;




&lt;h2&gt;
  
  
  An Example Problem
&lt;/h2&gt;

&lt;p&gt;Take the following JSON-structure for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"article"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello world"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi there"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/hello-world-banner.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World! banner"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"video"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_surround.avi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"thumbnail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://peach.blender.org/wp-content/uploads/dl_1080p.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Big Buck Bunny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;574&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the objects in the &lt;code&gt;body&lt;/code&gt; array contain a field called &lt;code&gt;type&lt;/code&gt;, which determines the type of object being returned. This will give you flexibility to parse the objects into their own respected models, which in this case should be “&lt;code&gt;text&lt;/code&gt;”, “&lt;code&gt;image&lt;/code&gt;” and “&lt;code&gt;video&lt;/code&gt;”. See the 3 model examples below using Google’s AutoValue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@AutoValue&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TextBlock&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@AutoValue&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImageBlock&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"source"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;source&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;author&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;description&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@AutoValue&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VideoBlock&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"source"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;source&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"thumbnail"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;thumbnail&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"duration"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(For brevity sake I left out the Builders and Gson Type Adapter generators in the above examples.)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;First we’ll need to create the Article model itself. In the example below you’ll notice the &lt;code&gt;List&amp;lt;Block&amp;gt;&lt;/code&gt; return type. If you take a look at the Blocks example code, you’ll see these all implement the Block interface. This way we can easily define new typed objects we want to support in future updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AutoValue&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@SerializedName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"blocks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;blocks&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now parsing it; here the magic called RuntimeTypeAdapterFactory will step in! When creating the Gson parser, you can register all kinds of type adapter factories. Add the generated AutoValue adapter and the Runtime adapter and you’re set.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;RuntimeTypeAdapterFactory&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;articleBlockFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RuntimeTypeAdapterFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerSubtype&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TextBlock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerSubtype&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ImageBlock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"image"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerSubtype&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VideoBlock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"video"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Gson&lt;/span&gt; &lt;span class="n"&gt;gson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GsonBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDateFormat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"yyyy-MM-dd'T'HH:mm:ssZ"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerTypeAdapterFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AutoValueTypeAdapterFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerTypeAdapterFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;articleBlockFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Retrofit&lt;/span&gt; &lt;span class="n"&gt;retrofit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Retrofit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.example.com/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addConverterFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GsonConverterFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gson&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever the Gson parser encounters an object of the type &lt;code&gt;Block&lt;/code&gt; the adapter will check if it can parse to any of the defined subtypes. If your API defines the type in a different field than &lt;code&gt;"type"&lt;/code&gt; you can provide it. &lt;code&gt;"type"&lt;/code&gt; is the default name for the key so you can omit it entirely if your API does work this way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;I ran into a couple of minor issues which I needed to solve for my purpose. These findings might also come in handy for you to know when you’ll start working with the RuntimeTypeAdapterFactory.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the parser encounters an unexpected type, an exception will be thrown and your complete object will be invalid — You can modify the parser to return &lt;code&gt;null&lt;/code&gt; instead if you don’t like this approach&lt;/li&gt;
&lt;li&gt;The parsed &lt;code&gt;"type"&lt;/code&gt; field will not be returned to the model — if you want this info, you’ll need to re-add it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>android</category>
      <category>polymorphism</category>
      <category>json</category>
      <category>api</category>
    </item>
  </channel>
</rss>
