Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@JsonProperty annoation not respected for booleans in constructor. #52

Closed
gregschlom opened this issue Dec 16, 2016 · 25 comments
Closed

Comments

@gregschlom
Copy link

gregschlom commented Dec 16, 2016

Hello,

The @JsonProperty annotation doesn't work as expected for Boolean properties.

  • When used on a constructor property, it doesn't work
  • When used on a class property, it works but the original property name is serialized too.

See example below:

fun test() {
    val mapper = jacksonObjectMapper()

    println(mapper.writeValueAsString(Test()))
    
    //output: {"is_lol":"sdf","foo":true,"bar":true,"is_foo":true}
}

class Test(
        // This gets serialized as "is_lol", as expected. No issues here.
        @JsonProperty("is_lol")
        val lol: String = "sdf",

        // This gets serialized as "bar", even though we asked for "is_bar". This is an issue.
        @JsonProperty("is_bar")
        val isBar: Boolean = true) {

    // This gets serialized as both "foo" and "is_foo", although we only asked for "is_foo". Also an issue.
    @JsonProperty("is_foo")
    val isFoo: Boolean = true
}

EDIT: It works if we use @get:JsonProperty()

So in the example above, using @get:JsonProperty("is_bar") gives me the correct results.

Therefore, maybe close this ticket but improve README by mentioning this?

@gregschlom gregschlom changed the title @JsonProperty annonation not respected for booleans in constructor. @JsonProperty annoation not respected for booleans in constructor. Dec 16, 2016
@otomatik
Copy link

@gregschlom thanks for your solution but do you use proguard? Because I do and I encounter a problem with this special annotation while I specified the -keepattributes *Annotation* (which works for "classic annotations")
Thanks again

@gregschlom
Copy link
Author

@otomatik no, I do not use proguard.

@memfis19
Copy link

Hi, I have kind of similar issue. I have custom generic Optional:

data class Optional<T> (
	var value: T? = null
) {
	@JsonCreator
	constructor(): this(null)
}

and class where it used with Boolean inside:

@JsonIgnoreProperties(ignoreUnknown = true)
data class ChangeEventModelUpdate (	
	var isAllDay: Optional<Boolean>? = null
)  {
	@JsonCreator
	constructor(): this(null)
}

and after serialization ObjectMapper().writeValueAsString(ChangeEventModelUpdate(Optional(true))) I have string with empty object in result.

@Kinmarui
Copy link

You really should change behavior or add example on Readme in Caveats because this thread is more than half year old and I just hit this problem.

@apatrida
Copy link
Member

apatrida commented Feb 3, 2018

I'm looking at this to see if there is a way to resolve it. If not, will document workarounds.

@apatrida
Copy link
Member

apatrida commented Feb 3, 2018

For reference, this class:

    class Test(
        @JsonProperty("is_lol")
        val lol: String = "sdf",

        @JsonProperty("is_bar")
        val bar: Boolean = true,

        @JsonProperty("is_bar2")
        val isBar2: Boolean = true
   )  {
       // class body

        @JsonProperty("is_foo")
        val foo: Boolean = true

        @JsonProperty("is_foo2")
        val isFoo2: Boolean = true
    }

which has part of the values in the constructor (meaning the annotations might go on the parameter instead of the getter), and part of the values in the body (meaning the annotations might go on the field instead of the getter).

generates this bytecode (summarized):

public final class com/fasterxml/jackson/module/kotlin/test/Github52$Test {


  // access flags 0x12
  private final Z foo = true
  @Lcom/fasterxml/jackson/annotation/JsonProperty;(value="is_foo")

  // access flags 0x11
  public final getFoo()Z
  ...

  // access flags 0x12
  private final Z isFoo2 = true
  @Lcom/fasterxml/jackson/annotation/JsonProperty;(value="is_foo2")

  // access flags 0x11
  public final isFoo2()Z
     ... 

  // access flags 0x12
  private final Ljava/lang/String; lol
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x11
  public final getLol()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
     ...

  // access flags 0x12
  private final Z bar

  // access flags 0x11
  public final getBar()Z
      ...

  // access flags 0x12
  private final Z isBar2

  // access flags 0x11
  public final isBar2()Z
      ...

  // access flags 0x1
  public <init>(Ljava/lang/String;ZZ)V
    @Lcom/fasterxml/jackson/annotation/JsonProperty;(value="is_lol") // parameter 0
    @Lcom/fasterxml/jackson/annotation/JsonProperty;(value="is_bar") // parameter 1
    @Lcom/fasterxml/jackson/annotation/JsonProperty;(value="is_bar2") // parameter 2
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
      ...

  // access flags 0x1001
  public synthetic <init>(Ljava/lang/String;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
      ...

  // access flags 0x1
  public <init>()V
     ... 

...
}

@apatrida
Copy link
Member

apatrida commented Feb 3, 2018

produces:

{"is_lol":"sdf","is_bar":true,"bar2":true,"foo2":true,"is_foo":true,"is_foo2":true}

So the issue is that the constructor parameters are giving some fields their name is_lol, is_bar, and is_bar2, but then some JsonProperties fall onto the fields instead of the getters, making those fields rename to is_foo and is_foo2, so then the getters for these fields appear to be OTHER properties getFoo() becoming foo and isFoo2() becoming foo2, the other bar fields are ignored because they have no annotation, and their getters line up with the constructor parameters and therefore come out as the same properties.

This happens because Kotlin places the annotation on the first target in its priority list, and that is different for a constructor parameter than it is for a class member. So a annotation target must be applied to clarify where exactly you want it @get:JsonProperty being that target.

So this needs to be added to the caveats to make it clear.

The only other solution would be for @cowtowncoder to let me replace JsonProperty in Java, with the same written in Kotlin, it would be compatible with the Java version, but would add the Kotlin metadata that allows the targetting of the getter to be higher in precedence than the field. The Java @Target would be the same, but would include the kotlin specific targets as well that only Kotlin would see.

It could also be written in Java, but at compile time would need to add the Kotlin annotation (think that would work, doesn't need any Kotlin metadata, just need the Kotlin version of annotation targetting as well, see the Byte Code)...

Roughly something like:


enum class JsonPropertyAccess {
    AUTO,
    READ_ONLY,
    WRITE_ONLY,
    READ_WRITE
}

const val JSON_PROPERTY_USE_DEFAULT_NAME = ""
const val JSON_PROPERTY_INDEX_UNKNOWN = -1

@Target(
    AnnotationTarget.ANNOTATION_CLASS,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.FIELD,
    AnnotationTarget.FUNCTION,
    AnnotationTarget.VALUE_PARAMETER
)
@Retention(AnnotationRetention.RUNTIME)
@JacksonAnnotation
annotation class JsonProperty(
    val value: String = "",
    val required: Boolean = false,
    val index: Int = JSON_PROPERTY_INDEX_UNKNOWN,
    val defaultValue: String = JSON_PROPERTY_USE_DEFAULT_NAME,
    val access: JsonPropertyAccess = JsonPropertyAccess.AUTO
)

Which generates byte code compatible annotation, but that would act correctly for Kotlin:

// ================com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.class =================
// class version 50.0 (50)
// access flags 0x4031
// signature Ljava/lang/Enum<Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;>;
// declaration: com/fasterxml/jackson/module/kotlin/JsonPropertyAccess extends java.lang.Enum<com.fasterxml.jackson.module.kotlin.JsonPropertyAccess>
public final enum com/fasterxml/jackson/module/kotlin/JsonPropertyAccess extends java/lang/Enum  {


  // access flags 0x4019
  public final static enum Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess; AUTO

  // access flags 0x4019
  public final static enum Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess; READ_ONLY

  // access flags 0x4019
  public final static enum Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess; WRITE_ONLY

  // access flags 0x4019
  public final static enum Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess; READ_WRITE

  // access flags 0x8
  static <clinit>()V
    ICONST_4
    ANEWARRAY com/fasterxml/jackson/module/kotlin/JsonPropertyAccess
    DUP
    DUP
    ICONST_0
    NEW com/fasterxml/jackson/module/kotlin/JsonPropertyAccess
    DUP
    LDC "AUTO"
    ICONST_0
    INVOKESPECIAL com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.<init> (Ljava/lang/String;I)V
    DUP
    PUTSTATIC com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.AUTO : Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    AASTORE
    DUP
    ICONST_1
    NEW com/fasterxml/jackson/module/kotlin/JsonPropertyAccess
    DUP
    LDC "READ_ONLY"
    ICONST_1
    INVOKESPECIAL com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.<init> (Ljava/lang/String;I)V
    DUP
    PUTSTATIC com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.READ_ONLY : Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    AASTORE
    DUP
    ICONST_2
    NEW com/fasterxml/jackson/module/kotlin/JsonPropertyAccess
    DUP
    LDC "WRITE_ONLY"
    ICONST_2
    INVOKESPECIAL com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.<init> (Ljava/lang/String;I)V
    DUP
    PUTSTATIC com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.WRITE_ONLY : Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    AASTORE
    DUP
    ICONST_3
    NEW com/fasterxml/jackson/module/kotlin/JsonPropertyAccess
    DUP
    LDC "READ_WRITE"
    ICONST_3
    INVOKESPECIAL com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.<init> (Ljava/lang/String;I)V
    DUP
    PUTSTATIC com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.READ_WRITE : Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    AASTORE
    PUTSTATIC com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.$VALUES : [Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    RETURN
    MAXSTACK = 8
    MAXLOCALS = 0

  // access flags 0x101A
  private final static synthetic [Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess; $VALUES

  // access flags 0x4
  // signature ()V
  // declaration: void <init>()
  protected <init>(Ljava/lang/String;I)V
    @Ljava/lang/Synthetic;() // parameter 0
    @Ljava/lang/Synthetic;() // parameter 1
   L0
    LINENUMBER 6 L0
    ALOAD 0
    ALOAD 1
    ILOAD 2
    INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V
    RETURN
   L1
    LOCALVARIABLE this Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess; L0 L1 0
    LOCALVARIABLE $enum_name_or_ordinal$0 Ljava/lang/String; L0 L1 1
    LOCALVARIABLE $enum_name_or_ordinal$1 I L0 L1 2
    MAXSTACK = 3
    MAXLOCALS = 3

  // access flags 0x9
  public static values()[Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    GETSTATIC com/fasterxml/jackson/module/kotlin/JsonPropertyAccess.$VALUES : [Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    INVOKEVIRTUAL [Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;.clone ()Ljava/lang/Object;
    CHECKCAST [Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    ARETURN
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x9
  public static valueOf(Ljava/lang/String;)Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    LDC Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;.class
    ALOAD 0
    INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
    CHECKCAST com/fasterxml/jackson/module/kotlin/JsonPropertyAccess
    ARETURN
    MAXSTACK = 2
    MAXLOCALS = 1

  @Lkotlin/Metadata;(mv={1, 1, 9}, bv={1, 0, 2}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0010\n\u0002\u0008\u0006\u0008\u0086\u0001\u0018\u00002\u0008\u0012\u0004\u0012\u00020\u00000\u0001B\u0007\u0008\u0002\u00a2\u0006\u0002\u0010\u0002j\u0002\u0008\u0003j\u0002\u0008\u0004j\u0002\u0008\u0005j\u0002\u0008\u0006\u00a8\u0006\u0007"}, d2={"Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;", "", "(Ljava/lang/String;I)V", "AUTO", "READ_ONLY", "WRITE_ONLY", "READ_WRITE", "production sources for module jackson-module-kotlin"})
  // compiled from: KotlinAnnotation.kt
}


// ================com/fasterxml/jackson/module/kotlin/JsonProperty.class =================
// class version 50.0 (50)
// access flags 0x2601
public abstract @interface com/fasterxml/jackson/module/kotlin/JsonProperty implements java/lang/annotation/Annotation  {


  @Lkotlin/annotation/Target;(allowedTargets={Lkotlin/annotation/AnnotationTarget;.ANNOTATION_CLASS, Lkotlin/annotation/AnnotationTarget;.PROPERTY_GETTER, Lkotlin/annotation/AnnotationTarget;.PROPERTY_SETTER, Lkotlin/annotation/AnnotationTarget;.FIELD, Lkotlin/annotation/AnnotationTarget;.FUNCTION, Lkotlin/annotation/AnnotationTarget;.VALUE_PARAMETER})

  @Lkotlin/annotation/Retention;(value=Lkotlin/annotation/AnnotationRetention;.RUNTIME)

  @Lcom/fasterxml/jackson/annotation/JacksonAnnotation;()

  @Ljava/lang/annotation/Retention;(value=Ljava/lang/annotation/RetentionPolicy;.RUNTIME)

  @Ljava/lang/annotation/Target;(value={Ljava/lang/annotation/ElementType;.FIELD, Ljava/lang/annotation/ElementType;.METHOD, Ljava/lang/annotation/ElementType;.PARAMETER, Ljava/lang/annotation/ElementType;.ANNOTATION_TYPE})

  // access flags 0x401
  public abstract value()Ljava/lang/String;
    default=""

  // access flags 0x401
  public abstract required()Z
    default=false

  // access flags 0x401
  public abstract index()I
    default=-1

  // access flags 0x401
  public abstract defaultValue()Ljava/lang/String;
    default=""

  // access flags 0x401
  public abstract access()Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;
    default=Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;.AUTO

  @Lkotlin/Metadata;(mv={1, 1, 9}, bv={1, 0, 2}, k=1, d1={"\u0000$\n\u0002\u0018\u0002\n\u0002\u0010\u001b\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u000b\n\u0000\n\u0002\u0010\u0008\n\u0002\u0008\u0002\n\u0002\u0018\u0002\n\u0000\u0008\u0087\u0002\u0018\u00002\u00020\u0001B2\u0012\u0008\u0008\u0002\u0010\u0002\u001a\u00020\u0003\u0012\u0008\u0008\u0002\u0010\u0004\u001a\u00020\u0005\u0012\u0008\u0008\u0002\u0010\u0006\u001a\u00020\u0007\u0012\u0008\u0008\u0002\u0010\u0008\u001a\u00020\u0003\u0012\u0008\u0008\u0002\u0010\u0009\u001a\u00020\nR\u0009\u0010\u0009\u001a\u00020\n\u00a2\u0006\u0000R\u0009\u0010\u0008\u001a\u00020\u0003\u00a2\u0006\u0000R\u0009\u0010\u0006\u001a\u00020\u0007\u00a2\u0006\u0000R\u0009\u0010\u0004\u001a\u00020\u0005\u00a2\u0006\u0000R\u0009\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0000\u00a8\u0006\u000b"}, d2={"Lcom/fasterxml/jackson/module/kotlin/JsonProperty;", "", "value", "", "required", "", "index", "", "defaultValue", "access", "Lcom/fasterxml/jackson/module/kotlin/JsonPropertyAccess;", "production sources for module jackson-module-kotlin"})
  // compiled from: KotlinAnnotation.kt
}


// ================com/fasterxml/jackson/module/kotlin/KotlinAnnotationKt.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/fasterxml/jackson/module/kotlin/KotlinAnnotationKt {


  // access flags 0x19
  public final static Ljava/lang/String; JSON_PROPERTY_USE_DEFAULT_NAME = ""
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x19
  public final static I JSON_PROPERTY_INDEX_UNKNOWN = -1

  @Lkotlin/Metadata;(mv={1, 1, 9}, bv={1, 0, 2}, k=2, d1={"\u0000\u000e\n\u0000\n\u0002\u0010\u0008\n\u0000\n\u0002\u0010\u000e\n\u0000\"\u000e\u0010\u0000\u001a\u00020\u0001X\u0086T\u00a2\u0006\u0002\n\u0000\"\u000e\u0010\u0002\u001a\u00020\u0003X\u0086T\u00a2\u0006\u0002\n\u0000\u00a8\u0006\u0004"}, d2={"JSON_PROPERTY_INDEX_UNKNOWN", "", "JSON_PROPERTY_USE_DEFAULT_NAME", "", "production sources for module jackson-module-kotlin"})
  // compiled from: KotlinAnnotation.kt
}


// ================META-INF/production sources for module jackson-module-kotlin.kotlin_module =================
���������������	
9
#com.fasterxml.jackson.module.kotlin��KotlinAnnotationKt


@apatrida
Copy link
Member

apatrida commented Feb 3, 2018

so @cowtowncoder if you can compile annotations against Kotlin runtime, but as a compile-only dependency, you could add kotlin.annotation.Target annotation to JsonProperty with these values:

@Target(
    AnnotationTarget.ANNOTATION_CLASS,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.FIELD,
    AnnotationTarget.FUNCTION,
    AnnotationTarget.VALUE_PARAMETER
)

and then annotations are not required to be present at runtime so SHOULD (yes?) not break anything (I think at one point in Scala it did, but not presently?).

I could do a test and check all annotations in jackson annotations library and set the correct list for each, and do tests against them all.

The alternative is to allow some way to plug in Kotlin specific annotations for everything that have these, and maybe that is already possible with Annotation Inspector, I haven't checked.

Let me know the best way, and I'll check it out.

@cowtowncoder
Copy link
Member

I'd have to read this over a few times to make sure, but to be honest, I am not sure this would fly, and although possibly working, sounds quite fragile approach to me.

There are couple of practical problems (ideally jackson-annotations patch versions are identical; and with 3.x, there will not be patch versions), and so 2.9.0 having been done, I'd prefer no change.
I also do not like the idea of Kotlin dependency even for build time; partly since I fear some platform (or tool) might still barf on missing annotation.

So... not saying it's not going to happen, but feeling pessimistic at this point.

@apatrida
Copy link
Member

@cowtowncoder Is there a way to plugin custom annotations yet still provide the same information? So instead of reading these annotations directly, call something that collects them and returns the data they would be holding, that way you can use custom annotations as long as the module can understand them.

Alternatively, but fragile is an alternative build from Kotlin of the same using same packages and have it be drop-in replacement, but one dependency random ordering or dupe classes (Java 9) would break it.

@apatrida
Copy link
Member

I can do this already with: AnnotationInspector.findPropertyAliases yes? any annotation on a parameter will cause that to be called and I can have my own annotations that are more Kotlin friendly.

@apatrida
Copy link
Member

nope, this isn't called for all cases. close, but no.

@cowtowncoder
Copy link
Member

findPropertyAliases() should be called for all accessors, but it does not participate in reconciliation process same way, so perhaps this is the difference you see. That is, names are first resolved, reconciled, so that each accessor is only associated with one logical name. That name may then have aliases. There is further potential problem that I am not sure alias definitions from possibly distinct accessors are merged -- almost certainly they are not, since all (other) annotations are winner-takes-all, choose one with higher priority.

@cowtowncoder
Copy link
Member

One other possibility that might work but be somewhat cumbersome could be to post-process jackson-annotations from another repo, add annotations, republish as jackson-kotlin-annotations (or whatever name)? That has its downsides wrt Maven dependencies but would allow attaching necessary additions. Not sure how post-processing itself would work but seems like there should be tools for such things. Just an idea, not sure how good one. :)

@Murtowski
Copy link

Murtowski commented Feb 21, 2018

Hey I hope my issue is related to this topic
I'm using Kotlin @get:JsonProperty("NAME") - the only way that my field is send in RequestBody NAME instead of property's name.

After turining on ProGuard it makes something strange thing related with object mapper( other classes those properties haven't @get: annotation works fine).

String jackson = '2.9.1'
    implementation "com.fasterxml.jackson.core:jackson-core:${jackson}"
    implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson}"
    implementation "com.fasterxml.jackson.core:jackson-databind:${jackson}"
data class FormDocTankPermission  (
        @get:JsonProperty("fuelCardId")
        public val fuelCardId: Long,
        @get:JsonProperty("fuelType")
        public val fuelTypes: List<EnumFuelType>?,
        @get:JsonProperty("regNo")
        public val registrationNo: String,
        @get:JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
        @get:JsonProperty("validityDate")
        public val validityDate: Date)

I would like to showyou stacktrace:

java.lang.RuntimeException: Unable to convert FormDocTankPermission(fuelCardId=3, fuelTypes=[], registrationNo=C, validityDate=Thu Feb 22 00:00:00 GMT+00:00 2018) to RequestBody
[...]
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class pl.intenso.carefleet.e.j and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

@dphillipsprosper
Copy link

I am finding that when I use the annotated data class for both deserialization and serialization, that @get:JsonProperty("isSomething") is not sufficient. I must also annotate the constructor param with @param:JsonProperty("isSomething"), otherwise when I deserialize a JSON string into the data class, the field gets ignored.

@marshallpierce
Copy link

I'm not sure if I'm hitting this issue or possibly a different one?

When annotating a data class's boolean parameter with @JsonProperty to set the name when serialized, it works correctly if the boolean doesn't start with is. If it does start with is, then the @JsonProperty has no effect, and the serialized name is the property name with is removed.

Repro: https://bitbucket.org/marshallpierce/jackson-boolean-prop-name-repro/src/master/

@dphillipsprosper
Copy link

@marshallpierce yep that is the issue. Try annotating it like I have in my comment, and you'll see it properly serialize/deserialize.

The catch is you need to tell Kotlin where to put the @JsonProperty annotation. @get: tells Kotlin to put it on the getter, and @param: tells it to put it on the constuctor parameter.

With the annotation in both places, serialization and deserialization works correctly.

@marshallpierce
Copy link

But why does it change based on whether or not there is an is prefix?

@dphillipsprosper
Copy link

It's just how Jackson works. By default, if Jackson sees a property that starts with get or is, it strips that off when serializing. And it expects to deserialize the stripped field name.

There's probably a way to configure the ObjectMapper to not do this, but I don't know how.

@marshallpierce
Copy link

What I'm getting at is that having the presence or absence of is affect annotations seems like a bug: clearly the annotation is present and usable since it works without is, so it seems like that would mean this is a Jackson bug, not a Kotlin bytecode issue.

@codyoss
Copy link

codyoss commented Apr 25, 2019

Is there any plan to resolve this in Jackson(if it can be resolved)? Or is the official answer just to use @get:JsonProperty

@MaksimRT
Copy link

MaksimRT commented Oct 16, 2019

I am finding that when I use the annotated data class for both deserialization and serialization, that @get:JsonProperty("isSomething") is not sufficient. I must also annotate the constructor param with @param:JsonProperty("isSomething"), otherwise when I deserialize a JSON string into the data class, the field gets ignored.

It works but I have problem with openapi-generator-maven-plugin that generates only @JsonProperty("isSomething") annotation

@apatrida
Copy link
Member

@MaksimRT can you report an issue to that generator code to put the use-site target on it? It appears at this moment to be impossible to defeat Kotlin's choice of how it places annotations on the code it generates for properties. There is a big gap in what it does, from what we need. And no work-around above the programming adding those use-site targets.

@MaksimRT
Copy link

It will be fixed in 2.10.1 version by #256

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests