OkHttp + Restricted APIs

Certain TLS features like Server Name Indication (SNI) and Application-Layer Protocol Negotiation (ALPN) existed in Android before they had public APIs. The code was there; there just wasn’t a good way to use it.

OkHttp hacks around such limitations with reflection. Our internal platform package integrates both Android and JVM-specific features to get the best behavior even when public APIs don’t exist. When public APIs eventually get published we update OkHttp to use them. We don’t want to use more reflection than strictly necessary!

With Android 11 Google is restricting some old APIs that OkHttp was using. If you use an old OkHttp release to target Android API 30, you’ll get this weird crash:

IllegalStateException: Expected Android API level 21+ but was 29  
  at okhttp3.internal.platform.AndroidPlatform.buildIfSupported
  at okhttp3.internal.platform.Platform.findPlatform

The best fix is to use the latest OkHttp, which is 4.4.0 as of this post.

If you’re still on 3.x, today we're releasing OkHttp 3.12.9 and 3.14.7 to backport Android 11 support. You’ll need to upgrade to one of these before you can target API 30.

UPDATE 2020-03-01: We introduced a

KitKat and TLSv1.2

TLSv1.2 came out in 2008 but Android didn’t get support for it until Android 5 in 2014. Previous releases including Android 4.4 KitKat support up to TLSv1.1 by default.

KitKat’s old TLSv1.1 isn’t secure enough and so its retirement has been planned for a long time. RFC 7525 said this in 2015:

“Implementations MUST support TLS 1.2 and MUST prefer to negotiate TLS version 1.2 over earlier versions of TLS.

Rationale: Several stronger cipher suites are available only with TLS 1.2. In fact, the cipher suites recommended by this document are only available in TLS 1.2.”

Browsers are shutting off TLSv1.1 right now.

SSL Labs started limiting grades to ‘B’ for HTTPS sites that still offer TLSv1.1. Early this year Chrome, Safari, Firefox, and Edge will require TLSv1.2 or better.

Keep KitKat?

If you maintain an app that runs on KitKat, you have options:

  • Continue to use TLSv1.1. Webservers can support many versions of TLS simultaneously and so you can offer TLSv1.1 to KitKat users and TLSv1.2 to everyone else.

  • Hook up Google Play Services’ ProviderInstaller. This lets you run TLSv1.2 on

Modeling States vs. Facts

Lots of object models primarily track application state. For example, OkHttp’s Http2Connection.kt has state for whether a ping’s reply is outstanding:

private var awaitingPong = false

This is set to true each time a ping is sent and then false again when its reply is received.

I’ve recently started to prefer models that primarily track facts instead. For example:

private var pingsSent = 0L
private var pongsReceived = 0L

The pingsSent is incremented when a ping is sent and pongsReceived is incremented when its reply is received. The state is a function of the two fields:

fun awaitingPong() = (pingsSent > pongsReceived)

Tracking facts is more code so I shouldn’t prefer it! But I do:

  • There’s no lock shared between the thread writing pings and the thread reading their replies.
  • When a reply is late the code can now report how many successes we saw before the failure.
  • It affords more focus in tests.

I like event-driven architectures for microservices. It’s awesome how that strategy scales down to a single class.

Naming Versions

I’m working on some code to sort software versions and it’s tricky.


Software that releases to Maven Central should follow Maven’s versioning scheme. This list is sorted by Maven’s scheme:

  • 1.0.0-alpha
  • 1.0.0-beta
  • 1.0.0-rc1
  • 1.0.0-RC2
  • 1.0.0
  • 1.0.0-final
  • 1.0.0-delta
  • 1.0.0-preview

In this scheme certain strings like “alpha”, “beta”, and “final” are special and that impacts where they sort. Strings like “delta” and “preview” are not special. Maven versions are case-insensitive.


There’s a spec for semantic versioning at It formalizes using version strings to express major, minor, and patch-level changes. This list is sorted by SemVer:

  • 1.0.0-RC2
  • 1.0.0-alpha
  • 1.0.0-beta
  • 1.0.0-delta
  • 1.0.0-final
  • 1.0.0-preview
  • 1.0.0-rc1
  • 1.0.0

In this scheme a version is either pre-release (with a dash) or release (without a dash). Pre-release strings use case-sensitive sorting so “RC2” comes before “rc1”!


Maven and SemVer schemes are surprising in their own ways, and also mutually incompatible. For the JVM ecosystem, Maven is what matters most. SemVer is handy because it specifies major/minor/

Kotlin’s Assert Is Not Like Java’s Assert

OkHttp uses synchronized as an allocation free mutex. Our concurrency model is tricky enough that we’ve documented the rules! And if we forget the rules, we also use runtime assertions to catch mistakes:

  @Override void flush() {
    // Make sure we don’t hold a lock while doing I/O!
    assert (!Thread.holdsLock(Http2Stream.this));

When we migrated to Kotlin in 4.0, our assertions migrated too:

  override fun flush() {
    // Make sure we don’t hold a lock while doing I/O!

This seems like a boring change but unfortunately it wasn’t! One of our users reported a performance regression introduced with the Kotlin conversion.

To better understand the regression, let’s look at how the Java assert keyword works. The Java code above is equivalent to this source code:

  @Override void flush() {
    if (Http2Stream.class.desiredAssertionStatus()) {
      if (!Thread.holdsLock(Http2Stream.this) == false) {
        throw new AssertionError();

It first checks to see if assertions are enabled. (You can enable them with the -ea flag to the Java process.) Only if they are does it execute the potentially-expensive assert expression. And if that is false then our program crashes with an AssertionError.

The Kotlin assert keyword works

A Dependency Injector’s 3 Jobs

You can do dependency injection (DI) manually or with a library.

Constructing your application’s dependency graph by hand is a cute exercise but not practical beyond toy examples. You’ll eventually find yourself extracting the repetitive manual DI code into your own bespoke library, one that’s likely to be undesigned and incomplete.

But before you can do DI with a proper library, you’ve got to pick one. In this post I’ll describe the duties of a dependency injector. This could help you to understand the tradeoffs in various libraries. It may also explain why DI advocates like myself care so strongly about seemingly small differences.

Job 1: Uniform Syntax

A DI library’s user interface is its syntax: how to declare dependencies and how to satisfying them.

The javax.inject package is a popular mechanism to declare dependencies. Here’s what it looks like in a chess app:

class MoveRecommender {

  public MoveRecommender(
      BoardRanker boardRanker,
      PredictionPruner predictionPruner) {

The @Inject annotation signals that each constructor parameter is a dependency. This annotation is useful for the library and for other developers!

Each DI library has syntax for defining rules on how dependencies are satisfied. Here’s Guice 1.

Value Objects, Service Objects, and Glue

This post expands on a section in my Writing Code That Lasts Forever talk.

When I was learning object oriented programming I struggled to define boundaries between classes. Should a Chess game’s Bishop class have a move() method to reposition itself on the board? Should there even be a Bishop class? Board? Move? BishopMove? Which of these types should have interfaces? What changes if the game is online? Has undo?

So I learned to do it by feel. Follow patterns from the codebase, do what the JDK does, and refactor when I get it wrong. But it was still unsatisfying. Certain classes were difficult to test because of how they were structured. Other classes were easy to test but their tests were mostly ceremony. Does Bishop.setLocation() work? Whoop-de-doo.

It was only after I got serious about immutability and dependency injection that I found a reliable strategy for dividing responsibilities among classes. All code serves one of 3 purposes.

Value Objects

These model data. It's natural to represent these using JSON, protocol buffers, or SQL.

They should be immutable. For stateful entities like ChessPlayer, the value object holds a snapshot of the whole entity or some aspect of it.

Factory or Extension Function?

I’m working on OkHttp’s Kotlin upgrade. Java callers use this code to go from a String to an HttpUrl:

String string = ...
HttpUrl httpUrl = HttpUrl.get(string); 

Should it remain the same in Kotlin?

val string: String = ...
val httpUrl: HttpUrl = HttpUrl.get(string)

or should we follow the core library’s pattern?

val string: String = ...
val httpUrl: HttpUrl = string.toHttpUrl()

Whether HttpUrl shows up in the already-long list of autocomplete suggestions is either a perk or a drawback depending on how you code.

It helps to see how these patterns interact Kotlin language features. Suppose I want the port of a possibly-null URL string. With the static factory:

val string: String? = ...
val port = if (string != null) HttpUrl.get(string).port else 80

vs. the extension function:

val string: String? = ...
val port = string?.toHttpUrl()?.port ?: 80

The safe-call operator makes the extension function a better choice. And Kotlin’s powerful deprecation mechanism also makes the change fast and safe for callers to adopt.

Metrics for OkHttp’s Kotlin Upgrade

We’re upgrading OkHttp’s implementation language from Java to Kotlin. It’s a big process, especially as we’re maintaining strict compatibility with OkHttp 3.x. Fortunately we’ve done it before and we’re following the strategy Egor & I presented last year.

Today we reached a nice milestone: 100% of the production code in the OkHttp module is Kotlin!

We haven’t made any behavior changes so it’s a rare opportunity to compare Java vs. Kotlin while holding everything else constant¹.

Code Size

Java: 25,775 lines
Kotlin: 24,114 lines

7% fewer lines of code is underwhelming. But by doing a strict conversion we’re stuck with all of the Java ceremony we’d otherwise do without. For example, our ConnectionSpec class spends 100 lines on accessors, equals(), hashCode(), toString() and its Builder. Without these this class would be 40% fewer lines of code.

Compile Time

Java: 2.4 seconds
Kotlin: 10.2 seconds

These times are for a full compile of the code above. It’s consistent with what Uber recently reported. Kotlin wants incremental builds and small modules!

Binary Size

Java: 415 KiB
Kotlin: 670 KiB

Seeing a 60% larger binary surprised me.

Syntactic Sugar

In comparing programming languages I’ve found myself anchoring on what I’m comfortable with and seeing everything else as either “low level and verbose” or “full of syntactic sugar and magical”.

I’ve recently gone from using mostly Java to using mostly Kotlin and I’ve learned that syntactic sugar is fucking awesome and the term doesn’t do justice to the big positive impact it has on my programs.

I’d like to illustrate with an example. I’ve been visiting the library lots lately so I’ll write a program to track which books I’ve borrowed:

data class Book(val title: String, val author: String)  
interface LibraryBooksDb {  
  fun takeOut(book: Book, due: LocalDate)
  fun putBack(book: Book)
  fun dueSoon(duration: Duration = Duration.ofDays(4)): Set<Book>
@Test fun dueSoon() {
  val bookA = Book("Jurassic Park", "Michael Crichton")
  val bookB = Book("Skin in the Game", "Nicholas Taleb")

  clock.setNow(LocalDate.of(2018, 3, 2))
  db.takeOut(bookA, LocalDate.of(2018, 4, 2))
  db.takeOut(bookB, LocalDate.of(2018, 3, 16))

  // Initially nothing is due.

  // Extend what 'soon' means to include more books.

Toehold Test

Let’s write a small class that has potential to grow.

data class ZipCode(val code: String) {  
  init {
    require(code.matches(Regex("""\d{5}"""))) {
      "not a zip code: $code"

Should you write a unit test for this? Turbo test-driven developers do because they obsess over test coverage and test everything! But what about us pragmatic developers who are in a hurry, and who aren’t obligated by process?

I claim that we should! Not to defend against regressions, but instead to serve as a toehold for further tests. Someday somebody may extend this and it’ll be helpful to have a test to build upon.

This is particularly worthwhile when the test requires setup. If your obviously-correct code needs a fake clock or a temporary directory to be tested, the toehold-test’s job is to configure that stuff. That way there’s no friction to testing when it’s most useful.

If you need inspiration, name the toehold test happyPath()!


My recent work requires coordinating teams to build their own pieces of a larger puzzle. We’re going to replace old system 𝒂 with new systems 𝔁, 𝔂, and 𝒛, and that means each team needs to land their contribution on schedule.

But in my heart I know that software hates schedules! We’re inventing as we go and all kinds of risks can wreck the timeline. Here’s some recent ones that impacted my team:

  • A critical team member left the company.
  • A Java 8 bug blocked feature development ’til we upgraded to Java 11.
  • Random packet loss between our datacenter and AWS blocked migration.

How do we coordinate anything done with so much uncertainty?!

This clarified things for me: Deadlines aren’t predictions; they’re constraints. Software projects are elastic in scope. Replace “when will the whole thing be done?” with “how much can we land by April?”

I’m still uncomfortable going more than a few months into the future. That’s when the risks compound!

Live Forever

I don’t have a fountain of youth but instead a surprising approximation. You know the expression, “time flies while you’re having fun?” It’s almost right. Your brain’s perception of time flies when you’re doing something familiar. And most importantly, your perception of time slows when you’re doing something new and novel.

Belle Beth Cooper’s post explains this idea further. Try new uncomfortable things and live a rich life!


If you lose 10 pounds, where do those pounds go? It’s weird trivia that I never learned in school. Do you poop it out? pee? sweat?

A parallel question clarifies: where does the gasoline goes when you drive your car? The car’s internal combustion engine turns oxygen and petrol into energy and CO₂. The air leaving a car’s muffler is heavier than the air that entered its radiator! This is unintuitive because air seems so... weightless.

Your body works the same way. You convert oxygen and calories into energy and CO₂. Breathing while you sleep means you’ll weigh less waking up than you did falling asleep! And aerobic exercise runs the process harder so naturally it burns more calories.

NPR has details on the process. I find it all fascinating.

SQL Multiple-Column IN Clause

The IN clause is handy. I use it all of the time.

  make IN ('Ford', 'Subaru') AND
  price < 5000;

| make   | model   | year | color  | price |
| Ford   | Focus   | 2007 | Black  |  1100 |
| Ford   | Mustang | 2005 | Yellow |  4000 |
| Ford   | Fiesta  | 2011 | Yellow |  4500 |
| Subaru | Legacy  | 2003 | Yellow |   900 |
| Subaru | Impreza | 2005 | Red    |  1400 |

Today I came across a two-column IN clause in a code review:

  (make, color) IN (
    ('Ford', 'Yellow'), 
    ('Subaru', 'Red')
  ) AND
  price < 5000;

| make   | model   | year | color  | price |
| Ford   | Mustang | 2005 | Yellow |  4000 |
| Ford   | Fiesta  | 2011 | Yellow |  4500 |
| Subaru | Impreza | 2005 | Red    |  1400 |

How’d I go my whole life without this? Good stuff.

Developer Identity & Multiplatform

We don’t self-identify as software developers but as web developers, backend developers, Android developers, or iOS developers. Many factors reinforce this specialization.

I’m a Droid

Building systems builds experience. Android developers learn technologies that have no analog on other platforms: activities, intents, and XML layouts. Once we’ve mastered the quirks of Android’s lifecycles that’s a superpower for writing even more Android code.

We build communities around these common skills. We’ve got conferences, meetups, Slack channels, and open source. These communities aren’t strictly technical; we also make friends and even get jobs through them.

And we’ve been tribal. Years ago it wasn’t clear how many mobile platforms would thrive. Windows Mobile, Palm, and Blackberry all had a chance. We didn’t want to develop for iPhone’s confined sandbox. Android is open!

iOS and Android have Converged

Our steady state is iOS and Android. Kotlin and Swift are more similar than Java and Objective-C. Our UIs were flattened and we’ve even stopped complaining about apps that look like iOS.

But our two platform steady-state sucks. Product teams have to build everything twice. Not only do the two apps need to work,

URL Encoding Is Material

Lots of OkHttp and Retrofit users have reported bugs complaining that URL special characters (like + ; | = * ; ; | or *) weren’t encoded as they expected.

Why can’t HttpUrl just encode ; as %3B?

Extra escaping is safe in most programming languages and document formats. For example, in HTML there’s no behavior consequence to replace a non-delimiter " character with its escape sequence &quot;. Or in JSON, it’s safe to replace the string "A" with "\u0041".

But URLs are different because URL encoding is semantic: you cannot encode a URL without changing it. This is weird!

Too Much Encoding

Suppose we’re looking up 100% on DuckDuckGo. Since the code point for % is 0x25, that character encodes as %25 and the whole URL is

But what if we encode the already-encoded URL of that query? We would double-encode the % as %2525 and end up searching for 100%25. Yuck:

Too Little Encoding

Next we’ll search for #1 on Google. We’ll encode # as %23 and get this URL:

What if we forget to encode the # in the query? Since # is used as

A Clever, Flawed OkHttp Interceptor Hack

All of OkHttp’s configuration is on the OkHttpClient instance:

OkHttpClient client = new OkHttpClient.Builder()  
    .readTimeout(2_000, TimeUnit.MILLISECONDS)
    .writeTimeout(2_000, TimeUnit.MILLISECONDS)
    .cache(new Cache(cacheDirectory, cacheSize))

This design is minimal and simple. There aren’t any precedence rules or hidden settings to be surprised by. To customize a particular option for a particular call, derive a new client from an existing one:

OkHttpClient longTimeoutClient = client.newBuilder()  
    .readTimeout(60_000, TimeUnit.MILLISECONDS)
    .writeTimeout(60_000, TimeUnit.MILLISECONDS)

This minimal API feels too simple when the OkHttpClient instance is encapsulated within another framework. For example, consider Retrofit:

OkHttpClient client = ...  
Retrofit retrofit = new Retrofit.Builder()  
EmojiService emojiService = retrofit.create(EmojiService.class);  

To extend the timeout for one endpoint I need to create a new OkHttpClient, a new Retrofit, and a new EmojiService. Ick. We’re planning a proper fix for this. But until that’s ready, there’s this ridiculous other thing you can do.

public class CheatingInterceptor implements Interceptor {  
  volatile OkHttpClient clientOverride;

  @Override public Response intercept(Chain chain)
      throws IOException {
    OkHttpClient override = clientOverride;
    if (override != null) {
      return override.newCall(chain.request()).execute();

    return chain.proceed(chain.request());

This interceptor breaks the

Canonical URLs for Javadocs

We publish separate Javadocs for each major release of OkHttp: 1.x, 2.x, 3.x. This is intended to help you out when you’re using an old version. But it’s had an adverse side-effect: Googling for “responsebody okhttp” only returns results for old versions. You see the same problem when you search for “LinkedHashMap” and get Java 7 instead of Java 8.

On Paul’s recommendation, a couple weeks ago I updated the old version’s docs to point at their modern counterparts with a canonical URL tag:

<link rel="canonical" href=""/>  

Google has since reindexed our docs and now it prefers the current versions in query results. Nice.

Story Code

Designing APIs is hard. One technique that helps me is to tell a story with the code: I’ll make a sequence of calls to show how things fit together. I find this helps me to discover what methods I need and what I can leave out. Using features together shows me how they integrate and reveals inconsistencies in naming and behavior.

Where does this exploration live? Usually I just sketch it out in IntelliJ as a main method or test case. For example, to build the API for a parking meter I might start with this:

public final class ParkingMeterTest {  
  FakeClock clock = new FakeClock();
  ParkingMeter parkingMeter = new ParkingMeter(clock);

  @Test public void testParkingMeter() {
    // This meter charges 25 cents for 15 minutes.
    parkingMeter.setRate(25, 15);

    // Initially the parking meter is expired.
    assertEquals("00:00", parkingMeter.display());

    // A customer puts in 50 cents to get 30 minutes.
    assertEquals("00:30", parkingMeter.display());

    // After 29 minutes elapses there's still one minute left.
    clock.advance(29, TimeUnit.MINUTES);
    assertEquals("00:01", parkingMeter.display());

    // After 1 more minute the meter is expired.
    clock.advance(1, TimeUnit.MINUTES);

Name Your Threads

I work on a big Java service that does lots of things. When I snapshot the application’s threads I can see it’s got lots going on:

  • Talking RPC and HTTP
  • Running cron jobs and job queue jobs
  • Persisting to MySQL
  • Coordinating with ZooKeeper
  • Collecting garbage

At a glance I can see what the service is doing: what’s blocked on I/O, what’s executing, what’s waiting for locks, and what’s idle.

Analysis is easier if the threads have descriptive names:

  • connection-mgmt-[]
  • job-queue-outgoing-email-0
  • zk-lb-lease/publisher-outgoing_sms-0

And it’s difficult otherwise:

  • pool-1-thread-3
  • pool-21-thread-99
  • pool-2-thread-1

Naming Threads

The best names help you to know out which class started the thread (connection-mgmt) and what that thread is currently doing (

If you’re using Guava, just use ThreadFactoryBuilder. Otherwise use this:

public static ThreadFactory threadFactory(  
    final String name, final boolean daemon) {
  return new ThreadFactory() {
    @Override public Thread newThread(Runnable runnable) {
      Thread result = new Thread(runnable, name);
      return result;

When your runnable has more context than it’s shared executor, you can use something like OkHttp’s NamedRunnable:

executor.execute(new NamedRunnable("OkHttp Window Update %s", hostname) {  
  @Override public void execute(

Seductive Code

It’s careful work balancing tradeoffs when writing code and designing APIs. Here’s some everyday Java code:

for (Protocol protocol : protocols) {  
  if (protocol != Protocol.HTTP_1_0) {

On Android—where garbage collector costs aren’t necessarily negligible—I make my code slightly uglier to save an implicit Iterator allocation:

for (int i = 0, size = protocols.size(); i < size; i++) {  
  Protocol protocol = protocols.get(i);
  if (protocol != Protocol.HTTP_1_0) {

Java 8 invites me to make the opposite tradeoff: to use streams and lambdas like a functional programmer:  
    .filter(protocol -> protocol != Protocol.HTTP_1_0)
    .forEach(protocol -> {

Here we’ve got three perfectly-reasonable ways to write the same code, and therefore the perfect opportunity to have a disagreement on how this loop should be written.

When a programming language, API, or design pattern is seductive its cosmetic beauty hides its structural limitations. I’m frustrated when making my code read better harms how efficiently it runs or how maintainable it is.

Seductive and Slow


Jesse, Learning in Anger

I’m using an open source library and it crashes in an unexpected way. The crash makes me grumpy because it prevents me from getting my real work done.

I don’t want anyone to face this indignity ever again! And so I proceed to report the bug to the library’s maintainers. Since I’m grumpy it’s not enough to say “your shit’s broke”. I have to make it crystal clear how and where it’s broken. I need to shame them for writing imperfect code.

So I attempt to write the simplest program that demonstrates this insidious bug. I start with my initial codebase with all of its moving parts. I attempt to remove distractions and unrelated features until all I’m left with is a trigger for the bug.

But as a side effect of isolating the bug I end up learning the internals of this library that I’d previously been treating as a black box. Studying this program in anger has the same effects as studying anything: I learn it.

I learn why their code is complicated. Over here it’s because in 2011 they had to workaround a bug in the Eclipse

Charles 4 has HTTP/2

Karl von Randow has released Charles 4.

“With Charles 4 you can now see HTTP 2 working, and you can use all of your familiar tools; Repeat, Breakpoints, and so on. You’ll spot HTTP 2 hosts in Charles as they use a different icon—with a lightning bolt!”

I just took it for a quick spin. The updated HTTP/2 support works as advertised.

If you’d like to try out Charles new HTTP/2 support with OkHttp, it’s three steps to configure OkHttp to trust Charles’ MITM certificate.

Export the certificate from Charles

From the Help menu, pick SSL Proxying and then Save Charles Root Certificate. Save it as a .pem file somewhere, then open it in your favorite text editor. You’ll see something like this:


Import the certificate into OkHttp

OkHttp has an executable custom trust example that we’ll start with. Remove the example’s certificates. Paste the contents of the .pem file instead.

  private InputStream trustedCertificatesInputStream() {
    String charlesRootCa = ""
        + "-----BEGIN CERTIFICATE-----\n"
        + "IFByb3h5IEN1c3RvbSBSb290IENlcnRpZmljYXR\n"
        + "...\n"
        + "ieHLSeZtdIrL7cI45ILT4TkahmPVeZmVVCRwQ==\n"
        + "-----END CERTIFICATE-----\n";
    return new Buffer()

Point OkHttp at the Proxy

The custom trust example

Java’s new HTTP client is upside down

One of Java 9’s new features is a replacement for HttpURLConnection. And while I’m thrilled to get rid of that old garbage its replacement has its own surprises.

The Good

The API is small. The new package is and the Javadoc shows only 12 new HTTP types plus 6 more for websockets.

It implements HTTP/2. There’s NIO and java.util.concurrent APIs throughout so it might be efficient for many parallel requests.

There’s builders! And an HttpClient type. Java’s built in TLS stack has been upgraded to support ALPN which means it can negotiate HTTP/2 without the awkward jetty-alpn bootclasspath trick.

The Bad

There’s an HttpHeaders type, but it’s an interface and not an immutable value object. There’s no builder for the headers, only for the HttpRequest.

Though HttpURLConnection is now unnecessary, this new client continues to rely on several of its obsolete support classes. The most frustrating of these is URI, which can’t represent real-world URLs such as those in Google’s image charts. And if you want query parameters you have to concatenate strings.

Many useful knobs and features are absent from the API.

The Last HttpURLConnection

An awkward API

OkHttp 1.0 started out as an optimized implementation of HttpURLConnection. This old API is awkward to implement because there is an implicit state machine that corresponds to the underlying network I/O.

GET / HTTP/1.1  
Accept: text/html

HTTP/1.1 200 OK  
Content-Length: 300

<head><title>Public Object</title></head>  

For example, calling getResponseCode() forbids future calls to setRequestProperty() because request headers can’t be edited after they’ve been transmitted.

HttpURLConnection connection =;  
int responseCode = connection.getResponseCode();

// This fails with an exception at runtime!
connection.setRequestProperty("Accept", "text/html");  

What’s safe to call is especially awkward because the state machine itself is dynamic: setFixedLengthStreamingMode() and setChunkedStreamingMode() cause request body writes to lock in request headers.

An uncomfortable implementation

With OkHttp 2.0 we introduced a new API to complement HttpURLConnection. Instead of an implicit state machine the new API uses types to make an explicit model: Request has the inputs, Response has the outputs, and Call does the action.

Request request = new Request.Builder()  
    .header("Accept", "text/html")

Call call = client.newCall(request)

The Open Source Maintainer’s Dilemma

We’re in a golden age of reusable open source code. With GitHub and Maven Central it’s never been easier to create and share code.

This is excellent! Android developers have access to a steady stream of new projects. I keep up by following some Android developers on Twitter and by subscribing to Android Weekly and #AndroidDev Digest.

Releasing a new open source project is fun. Take your most reusable code, polish it off, and publish it to the world! Give back to the development community and earn your reputation.

Free as in puppy

There’s a catch. When you release an open source library you implicitly volunteer to be the ongoing maintainer of that library. It’s an unpaid job that imposes real time commitments.

The work as maintainer is to earn trust. This comes by implementing features, fixing bugs, answering Stack Overflow questions, and by responding to (often inane) GitHub issues. If you succeed your userbase will grow and hopefully it’s mostly fun.

Another option is to not do the work. This feels bad in the same way that ignoring street poverty feels bad. Users of my code ask me for things “Please help with this

Disable Cleartext in OkHttp

Alex Klyubin posted instructions on disabling cleartext networking in Android’s built-in HTTP stack.

Ideally, your app should use secure traffic only, such as by using HTTPS instead of HTTP. Such traffic is protected against eavesdropping and tampering.

Unfortunately that approach requires Android 6 or better. But if you’re using OkHttp you can disable cleartext networking for all versions of Android. Just configure your client’s connection specs:

OkHttpClient client = new OkHttpClient.Builder()  

If you want even more control, the HTTPS page on OkHttp’s wiki shows you how.

Deliberate Disobedience

Some friends and I do regular boardgame nights. Our favorite is Tichu. The first few times we played we got the rules wrong: we thought certain plays were legal but they weren’t. By playing more, studying the rules, and Googling the edge cases, we eventually got the rules right. We played the right way for a long time! But after years of doing it by the book we came to agree that one of the rules made the game worse. So collectively we decided to ignore it! And we’ve been enjoying Tichu immensely ever since.

Our understanding of Tichu followed this progression:

  1. Fail to follow the rules because we don’t know them.
  2. Strictly follow the rules.
  3. Deeply understand the rules and deliberately disobey the one we don’t like.

Though we aren’t following the rules in either the first or third cases, the reasons why are quite different. #1 comes from a lack of understanding while #3 comes from an abundance of it. I’ve seen this pattern elsewhere.


Software developers have no shortage of guidelines to follow spanning all aspects of our craft. Some favorites are Effective Java, Google’s Java Style Guidelines, and

Reflection-friendly Value Objects

There’s plenty of good advice on how to do value objects well in Java. Ryan Harter’s AutoValue intro is particularly handy.

When I’m not using AutoValue, I like to do my builders as recommended in Item 2 of Effective Java Second Edition. In it Josh Bloch recommends a private constructor that accepts the Builder as a constructor parameter:

public final class Pizza {  
  public final Size size;
  public final List<Topping> toppings;
  public final Cheese cheese;

  private Pizza(Builder builder) {
    this.size = builder.size;
    this.toppings = immutableList(builder.toppings);
    this.cheese = builder.cheese;

  public static final class Builder {
    private Size size = Size.MEDIUM;
    private List<Topping> toppings = new ArrayList<>();
    private Cheese cheese = Cheese.MOZZA;

    // …setters…

    public Pizza build() {
      return new Pizza(this);

This example also assigns default values in the builder. But these defaults are lost when Moshi or Gson use reflection to decode a pizza from JSON. This problem is explained in Moshi’s readme:

If the class doesn’t have a no-arguments constructor, Moshi can’t assign the field’s default value, even if it’s specified in the field declaration. Instead, the field’s default is always 0 for