2

I'm trying to start using Kotlin in my existing Java project, but Jackson is not detecting the @JsonProperty in my Kotlin objects (whereas it works perfectly with Java objects).

Any way to configure Jackson to make this work for Kotlin like it works for Java?

Here is the Java class:

public class TestJavaObj {
    @JsonProperty
    private String includeMe;
    private String dontIncludeMe;

    public TestJavaObj(String includeMe, String dontIncludeMe) {
        this.includeMe = includeMe;
        this.dontIncludeMe = dontIncludeMe;
    }
}

and the Kotlin class:

class TestKotlinObj(
    @JsonProperty val includeMe: String,
    val dontIncludeMe : String?
)

Here is the test code:

public static void main(String[] args) throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper()
            .registerModule(new KotlinModule()) //jackson-module-kotlin
            .configure(MapperFeature.AUTO_DETECT_GETTERS, false)
            .configure(MapperFeature.AUTO_DETECT_CREATORS, false)
            .configure(MapperFeature.AUTO_DETECT_FIELDS, false)
            .configure(MapperFeature.AUTO_DETECT_IS_GETTERS, false)
            .configure(MapperFeature.AUTO_DETECT_SETTERS, false);

    TestJavaObj javaObj = new TestJavaObj("hello", "world");
    TestKotlinObj kotlinObj = new TestKotlinObj("hello", "world");

    System.out.println("Expected: " + mapper.writeValueAsString(javaObj));
    System.out.println("Got: " + mapper.writeValueAsString(kotlinObj));
}

And here is the output:

Expected: {"includeMe":"hello"}
Got: {}

Version numbers from my gradle file:

kotlin_version = '1.3.72'
...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" 
...
apply plugin: 'kotlin'
...
compile('com.fasterxml.jackson.core:jackson-annotations:2.10.3')
compile('com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8')
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
Tom G
  • 2,025
  • 3
  • 21
  • 32
  • try this link https://stackoverflow.com/questions/12046786/jackson-json-custom-serialization-for-certain-fields – unzila Apr 18 '20 at 18:36
  • @unzila that seems to be about adding custom serializers to the bean classes. What I'm trying to do is have the Kotlin class serialization work in the same way the Java serialization already works. – Tom G Apr 18 '20 at 19:34

2 Answers2

3

Specify annotation use-site target:

class TestKotlinObj(
        @get:JsonProperty val includeMe: String,
        val dontIncludeMe : String
)

Result:

Expected: {"includeMe":"hello"}
Got: {"includeMe":"hello"}

Background:

The class translated to Java bytecode has only a constructor parameter annotated:

public final class TestKotlinObj {
   @NotNull // no annotation here
   private final String includeMe;
   @NotNull
   private final String dontIncludeMe;

   @NotNull // nor here
   public final String getIncludeMe() {
      return this.includeMe;
   }

   @NotNull
   public final String getDontIncludeMe() {
      return this.dontIncludeMe;
   }
                     // but here
                     // vvvv 
   public TestKotlinObj(@JsonProperty @NotNull String includeMe, @NotNull String dontIncludeMe) {
      Intrinsics.checkParameterIsNotNull(includeMe, "includeMe");
      Intrinsics.checkParameterIsNotNull(dontIncludeMe, "dontIncludeMe");
      super();
      this.includeMe = includeMe;
      this.dontIncludeMe = dontIncludeMe;
   }
}

Which is not taken into account when serializing the object.

See related issue: Kotlin data class Jackson @JsonProperty not honored

Denis Zavedeev
  • 7,627
  • 4
  • 32
  • 53
  • Thanks, this is super helpful. Out of curiosity, is there an easy way to see what the Java equivalent of a Kotlin class is? Or you just know that that's how it works? – Tom G Apr 18 '20 at 22:10
  • 1
    No problem, sure. If you are using Intellij IDEA you can: open the file, go to Tools -> Kotlin -> Show Kotlin Bytecode -> Decompile. See also [this](https://stackoverflow.com/q/50895662/6486622) question – Denis Zavedeev Apr 18 '20 at 22:16
1

Try changing the Kotlin class to this:

class TestKotlinObj {
    @JsonProperty
    val includeMe: String;
    val dontIncludeMe : String;

    constructor(includeMe: String, dontIncludeMe: String) {
      this.includeMe = includeMe;
      this.dontIncludeMe = dontIncludeMe;
    }
}

It may be that the current Kotlin class you have is equivalent to this in java (which would obviously not work):

public class TestJavaObj {
    public String includeMe;
    public String dontIncludeMe;

    public TestJavaObj(@JsonProperty String includeMe, String dontIncludeMe) {
        this.includeMe = includeMe;
        this.dontIncludeMe = dontIncludeMe;
    }
}
Šimon Kocúrek
  • 1,591
  • 1
  • 12
  • 22