Can't make Jackson and Lombok work together

后端 未结 14 1266
伪装坚强ぢ
伪装坚强ぢ 2020-11-27 13:48

I am experimenting in combining Jackson and Lombok. Those are my classes:

package testelombok;

import com.fasterxml         


        
相关标签:
14条回答
  • 2020-11-27 14:22

    I struggled with this for a moment as well. But looking through the documentation here I can see that the onConstructor annotation parameter is considered experimental and is not supported well on my IDE (STS 4). According to the Jackson documentation, private members are not (de)serialized by default. There are quick ways to resolve this.

    Add JsonAutoDetect annotation and set it appropriately to detect protected/private members. This is convenient for DTOs

    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
    public class SomeClass
    

    Add a factory function with @JsonCreator annotation, this works best if you need some object validation or additional transforms.

    public class SomeClass {
    
       // some code here
    
       @JsonCreator
       public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) {
          return new SomeClass();
       }
    }
    

    Of course you could just manually add the constructor in yourself also as well.

    0 讨论(0)
  • 2020-11-27 14:23

    Immutable + Lombok + Jackson can be achieved in next way:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.AccessLevel;
    import lombok.AllArgsConstructor;
    import lombok.NoArgsConstructor;
    import lombok.Value;
    
    @Value
    @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
    @AllArgsConstructor
    public class LocationDto {
    
        double longitude;
        double latitude;
    }
    
    class ImmutableWithLombok {
    
        public static void main(String[] args) throws Exception {
            ObjectMapper objectMapper = new ObjectMapper();
    
            String stringJsonRepresentation = objectMapper.writeValueAsString(new LocationDto(22.11, 33.33));
            System.out.println(stringJsonRepresentation);
    
            LocationDto locationDto = objectMapper.readValue(stringJsonRepresentation, LocationDto.class);
            System.out.println(locationDto);
        }
    }
    
    0 讨论(0)
  • 2020-11-27 14:23

    I tried several of the above and they were all temperamental. What really worked for me is the the answer I found here.

    on your project's root directory add a lombok.config file (if you haven't done already)

    lombok.config

    and inside paste this

    lombok.anyConstructor.addConstructorProperties=true
    

    Then you can define your pojos like the following:

    @Data
    @AllArgsConstructor
    public class MyPojo {
    
        @JsonProperty("Description")
        private String description;
        @JsonProperty("ErrorCode")
        private String errorCode;
    }
    
    0 讨论(0)
  • 2020-11-27 14:23

    I had a different issue and it was with the boolean primitive types.

    private boolean isAggregate;
    

    It was throwing the following error as a result

    Exception: Unrecognized field "isAggregate" (class 
    

    Lambok converts isAggregate to isAggregate() as a getter making the property internally to lombok as aggregate instead isAggregate. The Jackson library doesn't like it and it needs isAggregate property instead.

    I updated the primitive boolean to Wrapper Boolean to work around this issue. There are other options for you if you are dealing with boolean types, see the reference below.

    Sol:

    private Boolean isAggregate;
    

    ref: https://www.baeldung.com/lombok-getter-boolean

    0 讨论(0)
  • 2020-11-27 14:25

    If you want immutable but a json serializable POJO using lombok and jackson. Use jacksons new annotation on your lomboks builder @JsonPOJOBuilder(withPrefix = "") I tried this solution and it works very well. Sample usage

    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
    import lombok.Builder;
    import lombok.Value;
    
    @JsonDeserialize(builder = Detail.DetailBuilder.class)
    @Value
    @Builder
    public class Detail {
    
        private String url;
        private String userName;
        private String password;
        private String scope;
    
        @JsonPOJOBuilder(withPrefix = "")
        public static class DetailBuilder {
    
        }
    }
    

    If you have too many classes with @Builder and you want don't want the boilerplate code empty annotation you can override the annotation interceptor to have empty withPrefix

    mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
            @Override
            public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac) {
                if (ac.hasAnnotation(JsonPOJOBuilder.class)) {//If no annotation present use default as empty prefix
                    return super.findPOJOBuilderConfig(ac);
                }
                return new JsonPOJOBuilder.Value("build", "");
            }
        });
    

    And you can remove the empty builder class with @JsonPOJOBuilder annotation.

    0 讨论(0)
  • 2020-11-27 14:30

    From Jan Rieke's Answer

    Since lombok 1.18.4, you can configure what annotations are copied to the constructor parameters. Insert this into your lombok.config:

    lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
    

    Then just add @JsonProperty to your fields:

    ...

    You'll need a @JsonProperty on every field even if the name matches, but that is a good practice to follow anyway. You can also set your fields to public final using this, which I prefer over getters.

    @ToString
    @EqualsAndHashCode
    @Wither
    @AllArgsConstructor(onConstructor=@__(@JsonCreator))
    public class TestFoo {
        @JsonProperty("xoom")
        public final String x;
        @JsonProperty("z")
        public final int z;
    }
    

    It should also work with getters (+setters) though.

    0 讨论(0)
提交回复
热议问题