Re: [jackson-user] Field level Custom Annotation for JsonPointer expression
On Tue, Sep 19, 2023 at 7:19 AM Aditya Pant wrote: > > I have removed all lombok annotations from Person and Address classes. Then > added getters and setters. > > As earlier it reached to JsonPointerPropertyIntrospector and created > instance, however it didn't invoke > JsonPointerPropertyDeserializer.deserialize(). Similar behavior with > ContextualDeserilizer. It seems very odd that an instance was created but not used. Could you file an issue for jackson-databind Github project, including a minimal reproduction of method not getting called -- it's ok if code wouldn't do quite what it supposed to as long as it's clear method is not called. > > Another challenge, in the input json "requestModel" contains mixed data > (address, product, person). During deserialization they need to be set on > individual member (objects) on a person object. @JsonProperty("requestModel") > only works for one field. Adding it to address and product not allowed it > seems. "Conflicting getter definitions for property 'requestModel' " I'd need to see full class definition for this to make sure I understand the issue. You can add that to the issue filed. -+ Tatu +- > > I hope there is a way to combine JsonPath and Jackson behavior > > On Tuesday, September 19, 2023 at 11:12:55 PM UTC+10 Aditya Pant wrote: >> >> Thank you Tatu for your insights. Appreciate it. >> You are right it could be annotations are not copied during annotation >> processing. >> Definitely I will give it a try without lombok annotations. >> >> >> >> On Tuesday, September 19, 2023 at 2:27:49 PM UTC+10 Tatu Saloranta wrote: >>> >>> On Sun, Sep 17, 2023 at 9:39 PM Aditya Pant wrote: >>> > >>> > Hello Jackson community, >>> > >>> > The input Json have nested fields and different field names. I am looking >>> > for a way to deserilize using JsonPointer espression (because it allows >>> > path lookup). >>> > >>> > I have tried several approaches but none of them worked so far. >>> > >>> > - Tried using AnnotationIntrospector = introspector gets invoked which >>> > returns a custom deserializer from overridden findDeserializer(). >>> > However, custom JsonDeserialiser.deserialize() never invoked on >>> > mapper.readValue() >>> > >>> > - Tried using ContextualDeserilizer = it gets invoked which returns a >>> > custom deserializer. However, custom JsonDeserialiser.deserialize() never >>> > invoked on mapper.readValue() >>> >>> Those both should work. I didn't see anything obviously wrong in your >>> code, but there are 2 things that might be problematic: I'll add notes >>> below. >>> >>> > >>> > The customer deserialiser only invoked when it is declared on the class >>> > (not on field). >>> >> Following are classes: >>> > Using jackson with lombok >>> >>> This might be problematic -- possibly annotations might not be copied >>> into generated classes? >>> Either way, trying things out with regular POJO could rule out Lombok >>> as being problematic >>> (Jackson should work just fine with Lombok but there have been some >>> issues in the past) >>> >>> > >>> > // custom annotation >>> > >>> > @Target({ElementType.FIELD}) >>> > @Retention(RetentionPolicy.RUNTIME) >>> > @Documented >>> > public @interface JsonPointerProperty { >>> > >>> > String value(); >>> > } >>> > >>> > // Person POJO >>> > >>> > @Data >>> >>> >>> > @NoArgsConstructor >>> > @AllArgsConstructor >>> > @JsonIgnoreProperties(ignoreUnknown = true) >>> >>> ^^^ I always recommend removing this annotation when troubleshooting, >>> it can easily mask problems. >>> >>> > public class Person { >>> > private String name; >>> > private Address address; >>> > } >>> > >>> > // Address POJO >>> > >>> > @Data >>> > @NoArgsConstructor >>> > @AllArgsConstructor >>> > @JsonIgnoreProperties(ignoreUnknown = true) >>> > public class Address { >>> > >>> > // using custom annotation >>> > @JsonPointerProperty("/requestModel/streetName") >>> > private String street; >>> > private String city; >>> > private String postcode; >>> > } >>> > >>> > // introspector >>> > >>> > public class JsonPointerPropertyIntrospector >>> > extends NopAnnotationIntrospector { >>> > >>> > @Override >>> > public Object findDeserializer(Annotated am) { >>> > >>> > final JsonPointerProperty jsonPointerProperty = >>> > am.getAnnotation(JsonPointerProperty.class); >>> > if (jsonPointerProperty != null) { >>> > return new JsonPointerPropertyDeserializer( >>> > jsonPointerProperty.value(), >>> > am.getType().getRawClass() >>> > ); >>> > } >>> > >>> > return super.findDeserializer(am); >>> > } >>> > } >>> > >>> > // custom deserializer >>> > public class JsonPointerPropertyDeserializer >>> > extends JsonDeserializer { >>> > >>> > private final String jsonPath; >>> > private final Class clazz; >>> > >>> > public JsonPointerPropertyDeserializer() { >>> > this(null, null); >>> > } >>> > >>> > public JsonPointerPropertyDeserializer(String jsonPath, >>> > Class clazz) { >>> > this.jsonPath = jsonPath; >>> > this.clazz = clazz; >>>
Re: [jackson-user] Field level Custom Annotation for JsonPointer expression
I have removed all lombok annotations from Person and Address classes. Then added getters and setters. As earlier it reached to JsonPointerPropertyIntrospector and created instance, however it didn't invoke JsonPointerPropertyDeserializer.deserialize(). Similar behavior with ContextualDeserilizer. Another challenge, in the input json "requestModel" contains mixed data (address, product, person). During deserialization they need to be set on individual member (objects) on a person object. @JsonProperty("requestModel") only works for one field. Adding it to address and product not allowed it seems. "Conflicting getter definitions for property 'requestModel' " I hope there is a way to combine JsonPath and Jackson behavior On Tuesday, September 19, 2023 at 11:12:55 PM UTC+10 Aditya Pant wrote: > Thank you Tatu for your insights. Appreciate it. > You are right it could be annotations are not copied during annotation > processing. > Definitely I will give it a try without lombok annotations. > > > > On Tuesday, September 19, 2023 at 2:27:49 PM UTC+10 Tatu Saloranta wrote: > >> On Sun, Sep 17, 2023 at 9:39 PM Aditya Pant wrote: >> > >> > Hello Jackson community, >> > >> > The input Json have nested fields and different field names. I am >> looking for a way to deserilize using JsonPointer espression (because it >> allows path lookup). >> > >> > I have tried several approaches but none of them worked so far. >> > >> > - Tried using AnnotationIntrospector = introspector gets invoked which >> returns a custom deserializer from overridden findDeserializer(). However, >> custom JsonDeserialiser.deserialize() never invoked on mapper.readValue() >> > >> > - Tried using ContextualDeserilizer = it gets invoked which returns a >> custom deserializer. However, custom JsonDeserialiser.deserialize() never >> invoked on mapper.readValue() >> >> Those both should work. I didn't see anything obviously wrong in your >> code, but there are 2 things that might be problematic: I'll add notes >> below. >> >> > >> > The customer deserialiser only invoked when it is declared on the class >> (not on field). >> >> Following are classes: >> > Using jackson with lombok >> >> This might be problematic -- possibly annotations might not be copied >> into generated classes? >> Either way, trying things out with regular POJO could rule out Lombok >> as being problematic >> (Jackson should work just fine with Lombok but there have been some >> issues in the past) >> >> > >> > // custom annotation >> > >> > @Target({ElementType.FIELD}) >> > @Retention(RetentionPolicy.RUNTIME) >> > @Documented >> > public @interface JsonPointerProperty { >> > >> > String value(); >> > } >> > >> > // Person POJO >> > >> > @Data >> >> >> > @NoArgsConstructor >> > @AllArgsConstructor >> > @JsonIgnoreProperties(ignoreUnknown = true) >> >> ^^^ I always recommend removing this annotation when troubleshooting, >> it can easily mask problems. >> >> > public class Person { >> > private String name; >> > private Address address; >> > } >> > >> > // Address POJO >> > >> > @Data >> > @NoArgsConstructor >> > @AllArgsConstructor >> > @JsonIgnoreProperties(ignoreUnknown = true) >> > public class Address { >> > >> > // using custom annotation >> > @JsonPointerProperty("/requestModel/streetName") >> > private String street; >> > private String city; >> > private String postcode; >> > } >> > >> > // introspector >> > >> > public class JsonPointerPropertyIntrospector >> > extends NopAnnotationIntrospector { >> > >> > @Override >> > public Object findDeserializer(Annotated am) { >> > >> > final JsonPointerProperty jsonPointerProperty = >> am.getAnnotation(JsonPointerProperty.class); >> > if (jsonPointerProperty != null) { >> > return new JsonPointerPropertyDeserializer( >> > jsonPointerProperty.value(), >> > am.getType().getRawClass() >> > ); >> > } >> > >> > return super.findDeserializer(am); >> > } >> > } >> > >> > // custom deserializer >> > public class JsonPointerPropertyDeserializer >> > extends JsonDeserializer { >> > >> > private final String jsonPath; >> > private final Class clazz; >> > >> > public JsonPointerPropertyDeserializer() { >> > this(null, null); >> > } >> > >> > public JsonPointerPropertyDeserializer(String jsonPath, >> > Class clazz) { >> > this.jsonPath = jsonPath; >> > this.clazz = clazz; >> > } >> > >> > @Override >> > public Object deserialize(JsonParser parser, DeserializationContext >> ctx) >> > throws IOException, JacksonException { >> > >> > // not reaching here >> > JsonNode jsonNode = parser.readValueAs(JsonNode.class); >> > JsonNode at = jsonNode.at(jsonPath); >> > >> > String value = ctx.readTreeAsValue(jsonNode, String.class); >> > >> > System.out.println(value); >> > >> > return null; >> > } >> > } >> > >> > >> > // Unit test >> > >> > class PersonTest { >> > String json; >> > >> > @BeforeEach >> >
Re: [jackson-user] Field level Custom Annotation for JsonPointer expression
Thank you Tatu for your insights. Appreciate it. You are right it could be annotations are not copied during annotation processing. Definitely I will give it a try without lombok annotations. On Tuesday, September 19, 2023 at 2:27:49 PM UTC+10 Tatu Saloranta wrote: > On Sun, Sep 17, 2023 at 9:39 PM Aditya Pant wrote: > > > > Hello Jackson community, > > > > The input Json have nested fields and different field names. I am > looking for a way to deserilize using JsonPointer espression (because it > allows path lookup). > > > > I have tried several approaches but none of them worked so far. > > > > - Tried using AnnotationIntrospector = introspector gets invoked which > returns a custom deserializer from overridden findDeserializer(). However, > custom JsonDeserialiser.deserialize() never invoked on mapper.readValue() > > > > - Tried using ContextualDeserilizer = it gets invoked which returns a > custom deserializer. However, custom JsonDeserialiser.deserialize() never > invoked on mapper.readValue() > > Those both should work. I didn't see anything obviously wrong in your > code, but there are 2 things that might be problematic: I'll add notes > below. > > > > > The customer deserialiser only invoked when it is declared on the class > (not on field). > >> Following are classes: > > Using jackson with lombok > > This might be problematic -- possibly annotations might not be copied > into generated classes? > Either way, trying things out with regular POJO could rule out Lombok > as being problematic > (Jackson should work just fine with Lombok but there have been some > issues in the past) > > > > > // custom annotation > > > > @Target({ElementType.FIELD}) > > @Retention(RetentionPolicy.RUNTIME) > > @Documented > > public @interface JsonPointerProperty { > > > > String value(); > > } > > > > // Person POJO > > > > @Data > > > > @NoArgsConstructor > > @AllArgsConstructor > > @JsonIgnoreProperties(ignoreUnknown = true) > > ^^^ I always recommend removing this annotation when troubleshooting, > it can easily mask problems. > > > public class Person { > > private String name; > > private Address address; > > } > > > > // Address POJO > > > > @Data > > @NoArgsConstructor > > @AllArgsConstructor > > @JsonIgnoreProperties(ignoreUnknown = true) > > public class Address { > > > > // using custom annotation > > @JsonPointerProperty("/requestModel/streetName") > > private String street; > > private String city; > > private String postcode; > > } > > > > // introspector > > > > public class JsonPointerPropertyIntrospector > > extends NopAnnotationIntrospector { > > > > @Override > > public Object findDeserializer(Annotated am) { > > > > final JsonPointerProperty jsonPointerProperty = > am.getAnnotation(JsonPointerProperty.class); > > if (jsonPointerProperty != null) { > > return new JsonPointerPropertyDeserializer( > > jsonPointerProperty.value(), > > am.getType().getRawClass() > > ); > > } > > > > return super.findDeserializer(am); > > } > > } > > > > // custom deserializer > > public class JsonPointerPropertyDeserializer > > extends JsonDeserializer { > > > > private final String jsonPath; > > private final Class clazz; > > > > public JsonPointerPropertyDeserializer() { > > this(null, null); > > } > > > > public JsonPointerPropertyDeserializer(String jsonPath, > > Class clazz) { > > this.jsonPath = jsonPath; > > this.clazz = clazz; > > } > > > > @Override > > public Object deserialize(JsonParser parser, DeserializationContext ctx) > > throws IOException, JacksonException { > > > > // not reaching here > > JsonNode jsonNode = parser.readValueAs(JsonNode.class); > > JsonNode at = jsonNode.at(jsonPath); > > > > String value = ctx.readTreeAsValue(jsonNode, String.class); > > > > System.out.println(value); > > > > return null; > > } > > } > > > > > > // Unit test > > > > class PersonTest { > > String json; > > > > @BeforeEach > > void setup() throws IOException { > > json = "{ 'address': { 'requestModel': { 'streetName': 'some street', > 'cityName': 'some city' }}}" > > .replace( > > "'", > > "\"" > > ); > > } > > > > @Test > > void testPerson() throws JsonProcessingException { > > ObjectMapper mapper = new ObjectMapper(); > > mapper.setAnnotationIntrospector(new JsonPointerPropertyIntrospector()); > > > > final Person person = mapper.readValue(json, Person.class); > > > > assertEquals("some street", person.getAddress().getStreet(), "Street > mismatch"); > > } > > } > > > > There is some error parsing `requestModel`, but I was hoping it would at > least reach to customer deserializer. > > > > Any suggestions or point me what I am doing wrong? > > I suspect Lombok might be relevant here; annotations not being copied > into generated classes. > > -+ Tatu +- > -- You received this message because you are subscribed to the Google Groups "jackson-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user+unsubscr...@googlegroups.com. To view this discussion
Re: [jackson-user] Field level Custom Annotation for JsonPointer expression
On Sun, Sep 17, 2023 at 9:39 PM Aditya Pant wrote: > > Hello Jackson community, > > The input Json have nested fields and different field names. I am looking for > a way to deserilize using JsonPointer espression (because it allows path > lookup). > > I have tried several approaches but none of them worked so far. > > - Tried using AnnotationIntrospector = introspector gets invoked which > returns a custom deserializer from overridden findDeserializer(). However, > custom JsonDeserialiser.deserialize() never invoked on mapper.readValue() > > - Tried using ContextualDeserilizer = it gets invoked which returns a custom > deserializer. However, custom JsonDeserialiser.deserialize() never invoked on > mapper.readValue() Those both should work. I didn't see anything obviously wrong in your code, but there are 2 things that might be problematic: I'll add notes below. > > The customer deserialiser only invoked when it is declared on the class (not > on field). >> Following are classes: > Using jackson with lombok This might be problematic -- possibly annotations might not be copied into generated classes? Either way, trying things out with regular POJO could rule out Lombok as being problematic (Jackson should work just fine with Lombok but there have been some issues in the past) > > // custom annotation > > @Target({ElementType.FIELD}) > @Retention(RetentionPolicy.RUNTIME) > @Documented > public @interface JsonPointerProperty { > > String value(); > } > > // Person POJO > > @Data > @NoArgsConstructor > @AllArgsConstructor > @JsonIgnoreProperties(ignoreUnknown = true) ^^^ I always recommend removing this annotation when troubleshooting, it can easily mask problems. > public class Person { > private String name; > private Address address; > } > > // Address POJO > > @Data > @NoArgsConstructor > @AllArgsConstructor > @JsonIgnoreProperties(ignoreUnknown = true) > public class Address { > > // using custom annotation > @JsonPointerProperty("/requestModel/streetName") > private String street; > private String city; > private String postcode; > } > > // introspector > > public class JsonPointerPropertyIntrospector > extends NopAnnotationIntrospector { > > @Override > public Object findDeserializer(Annotated am) { > > final JsonPointerProperty jsonPointerProperty = > am.getAnnotation(JsonPointerProperty.class); > if (jsonPointerProperty != null) { > return new JsonPointerPropertyDeserializer( > jsonPointerProperty.value(), > am.getType().getRawClass() > ); > } > > return super.findDeserializer(am); > } > } > > // custom deserializer > public class JsonPointerPropertyDeserializer > extends JsonDeserializer { > > private final String jsonPath; > private final Class clazz; > > public JsonPointerPropertyDeserializer() { > this(null, null); > } > > public JsonPointerPropertyDeserializer(String jsonPath, >Class clazz) { > this.jsonPath = jsonPath; > this.clazz = clazz; > } > > @Override > public Object deserialize(JsonParser parser, DeserializationContext ctx) > throws IOException, JacksonException { > > // not reaching here > JsonNode jsonNode = parser.readValueAs(JsonNode.class); > JsonNode at = jsonNode.at(jsonPath); > > String value = ctx.readTreeAsValue(jsonNode, String.class); > > System.out.println(value); > > return null; > } > } > > > // Unit test > > class PersonTest { > String json; > > @BeforeEach > void setup() throws IOException { > json = "{ 'address': { 'requestModel': { 'streetName': 'some street', > 'cityName': 'some city' }}}" > .replace( > "'", > "\"" > ); > } > > @Test > void testPerson() throws JsonProcessingException { > ObjectMapper mapper = new ObjectMapper(); > mapper.setAnnotationIntrospector(new > JsonPointerPropertyIntrospector()); > > final Person person = mapper.readValue(json, Person.class); > > assertEquals("some street", person.getAddress().getStreet(), "Street > mismatch"); > } > } > > There is some error parsing `requestModel`, but I was hoping it would at > least reach to customer deserializer. > > Any suggestions or point me what I am doing wrong? I suspect Lombok might be relevant here; annotations not being copied into generated classes. -+ Tatu +- -- You received this message because you are subscribed to the Google Groups "jackson-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/jackson-user/CAL4a10isLGpc%3DmeV80J9YvaLHpv9x86wvCFkEZnx0F3TZau1Mw%40mail.gmail.com.