title: Multiple converters with Retrofit 2
body: <p>I have a <a href="http://stateless.co/hal_specification.html">HATEOAS (HAL)</a> REST service and managed to talk to it with the code below (using <a href="http://confluence.surech.ch/display/HAL/halarious+Home?from=DIAp">halarious</a> as a conversion engine) but when I try to <a href="https://www.youtube.com/watch?v=KIAoQbAu3eA&amp;t=19m45s">merge the converters</a> (<code>stallone</code> and <code>stallone2</code>), the app will always pick up the first converter, instead of the one that is appropriate for the response type which of course leads to an error. </p>
  
  <p><strong>How could I avoid duplicate retrofits that are only different in a small type detail?</strong></p>
  
  <pre class="lang-java prettyprint-override"><code>public interface Stallone {
     @GET("/discovery")
     Call&lt;DiscoveryResponse&gt; discover();
     @POST()
     Call&lt;LoginResponse&gt; login(@Url String url, @Body LoginRequest secret);
  }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>   public static void main(String... args) throws IOException {
        // Initialize a converter for each supported (return) type
        final Stallone stallone = new Retrofit.Builder()
           .baseUrl(BASE)
           .addConverterFactory(HALConverterFactory.create(DiscoveryResponse.class))
           .build().create(Stallone.class);
        final Stallone stallone2 = new Retrofit.Builder()
           .baseUrl(BASE)
           .addConverterFactory(HALConverterFactory.create(LoginResponse.class))
           .build().create(Stallone.class);
  
        // Follow the HAL links
        Response&lt;DiscoveryResponse&gt; response = stallone.discover().execute();
        System.out.println(response.code() + " " + response.message());
        Assert.assertNotNull(response.body());
        String loginPath = response.body().getLogin();
        Assert.assertEquals(loginPath, "/login");
  
        // Follow another link
        if (loginPath.startsWith("/"))
           loginPath = loginPath.substring(1);
        Response&lt;LoginResponse&gt; response2 =
           stallone2.login(loginPath,
                          new LoginRequest(AUTH0TOKEN, null)).execute();
        System.out.println(response2.code() + " " + response2.message());
        Assert.assertNotNull(response2.body());
  
        String setupPath = response2.body().getSetup();
        Assert.assertEquals(setupPath, "/setup");
  
        System.out.println("All OK!");
     }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>public final class HALConverterFactory extends Converter.Factory {
  
     private final Gson gson;
  
     public static HALConverterFactory create(Class&lt;?&gt; type) {
        return new HALConverterFactory(type);
     }
  
     private HALConverterFactory(Class&lt;?&gt; type) {
        if (!HalResource.class.isAssignableFrom(type))
           throw new NullPointerException("Type should be a subclass of HalResource");
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(HalResource.class, new HalSerializer());
        builder.registerTypeAdapter(HalResource.class, new HalDeserializer(type));
        builder.setExclusionStrategies(new HalExclusionStrategy());
        this.gson = builder.create();
     }
  
     @Override
     public Converter&lt;ResponseBody, ?&gt; fromResponseBody(Type type, Annotation[] annotations) {
        return new HALResponseBodyConverter&lt;&gt;(gson);
     }
  
     @Override public Converter&lt;?, RequestBody&gt; toRequestBody(Type type, Annotation[] annotations) {
        return new GsonRequestBodyConverter&lt;&gt;(gson, type);
     }
  }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>final class HALResponseBodyConverter&lt;T extends HalResource&gt;
     implements Converter&lt;ResponseBody, T&gt; {
     private final Gson gson;
  
     HALResponseBodyConverter(Gson gson) {
        this.gson = gson;
     }
  
     @Override public T convert(ResponseBody value) throws IOException {
        BufferedSource source = value.source();
        try {
           String s = source.readString(Charset.forName("UTF-8"));
           return (T) gson.fromJson(s, HalResource.class);
        } catch (Exception e) {
           throw new RuntimeException(e);
        } finally {
           closeQuietly(source);
        }
     }
  
     private static void closeQuietly(Closeable closeable) {
        if (closeable == null) return;
        try {
           closeable.close();
        } catch (IOException ignored) {
        }
     }
  }
  </code></pre>
  
  <p><strong>Again, the problem is that</strong> when you try to shorten the above like this:</p>
  
  <pre class="lang-java prettyprint-override"><code>  final Stallone stallone = new Retrofit.Builder()
       .baseUrl(BASE)
  .addConverterFactory(HALConverterFactory.create(DiscoveryResponse.class))
       .addConverterFactory(HALConverterFactory.create(LoginResponse.class))
       .build().create(Stallone.class);
  </code></pre>
  
  <p>you'll get an exception at the <code>Response&lt;LoginResponse&gt; response2 = ...</code> line:</p>
  
  <blockquote>
    <p>Exception in thread "main"
    java.lang.ClassCastException: com.example.retrofit.DiscoveryResponse
    cannot be cast to com.example.retrofit.LoginResponse</p>
  </blockquote>