Moshi: Moshi-kotlin doesn't respect @field:Json annotations in JUnit tests

Created on 26 Feb 2018  路  10Comments  路  Source: square/moshi

Using moshi and moshi-kotlin 1.5.

When using moshi kotlin, the kotlin data class constructor variables are to be marked with @field:Json for them to be recognized correctly by the reflection library on obfuscated builds. I noticed that in my unit tests, this doesn't work. In unit tests, the only way to get moshi to recognize the field and parse it is to annotate it as @Json (notice that the @field prefix isn't added).

This means that my models must have both the annotations @field:Json and @Json.

Example:

Moshi instance:

return new Moshi.Builder()
                .add(new KotlinJsonAdapterFactory())
                .build();

User class:

data class User(
        @field:Json(name = "user")
        var inner: UserInner? = null)

Parsed in app code (obfuscated):

User user = moshi.adapter(User.class).fromJson(jsonString);
Log.d("User", user.getInner().toString());
// user.getInner() is not null

Fails when parsed in unit tests:

@RunWith(JUnit4.class)
class UserTest extends junit.framework.TestCase {
    @Test
    public void testUser() {
          User user = moshi.adapter(User.class).fromJson(jsonString);
          assertNotNull(user.getInner()); // fails!
     }
}

When I update the user class to include both annotations:

data class User(
        @Json(name = "user") @field:Json(name = "user")
        var inner: UserInner? = null)

Now the tests pass.

My unit tests are standard JUnit4 unit tests written in java:

ProGuard documentation

Most helpful comment

I suspect we need a really good ProGuard section on our README.

All 10 comments

Edit:

The json adapter doesn't find the annotation because the jsonAnnotation is null when accessed here in this line:
https://github.com/square/moshi/blob/master/kotlin/src/main/java/com/squareup/moshi/kotlin/KotlinJsonAdapter.kt#L223

However, when running a proguarded build on jdk 1.7 on an android device, the annotation is present.
Only in unit tests (jdk 1.8) the annotation is null if denoted with @field:Json.

Could this be related to the environment that runs the moshi adapter, particularly the VM?

Just use @Json? There should be no need to use @field:Json when using the KotlinJsonAdapter.
I'm surprised this works on JDK 1.7, though...

@NightlyNexus @Json doesn't work. See https://github.com/square/moshi/issues/315

Have a failing test case?
From your code above, this passes.

data class User(@Json(name = "user") val name: String)

@Test fun user() {
  val user = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
      .adapter(User::class.java)
      .fromJson("""{"user":"jw"}""")
  assertThat(user).isEqualTo(User("jw"))
}

@NightlyNexus it passes because you added the @Json annotation. The code you posted will fail on an android device when the build is obfuscated with proguard

@NightlyNexus if you use the @field:Json annotation and run the unit test, it will fail. But @field:Json is required if you want moshi-kotlin to work with proguard according to the discussion here: https://github.com/square/moshi/issues/315.

I suspect we need a really good ProGuard section on our README.

So what is the final solution ? I still have to use both @Json and @field:Json if I want it to work both in Debug and Release with obfuscation. I used the proguard rules given in the README but it still does not work.

@suchet-q that's right - I have to use both annotations for this to work properly.

I have found the solution, you can use the annotation on top of your data class @JsonClass(generateAdapter = true), which can be found in the moshi-kotlin-codegen depedence.

This way you just need the @Json annotation, and it works perfectly fine in release with proguard obfuscation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rephiscorth picture rephiscorth  路  5Comments

vpotvin picture vpotvin  路  4Comments

Speedrockracer picture Speedrockracer  路  4Comments

cdongieux picture cdongieux  路  4Comments

ayedo picture ayedo  路  4Comments