Search code examples
javajsonjacksonbuilderlombok

How to use jackson with lombok Builder to deserialize a json-array?


I want to deserialize a primitive json-array into an Object. That Object is annotated with lombok's value and builder annotation. I can't get it to work:

The json looks like this:

["btcusd","ltcusd","ltcbtc"]

This is the call to get some json-array:

public CommandLineRunner run(RestTemplate restTemplate) {
  return args -> {
    Pair[] pairs = restTemplate
      .getForObject("https://api.bitfinex.com/v1/symbols", Pair[].class);
    log.info("List[" + Arrays.stream(pairs).map(Pair::getPairId).collect(
      Collectors.joining(", ")) + "]");
  };
}

And this is the Pair.class

@Value
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@JsonDeserialize(builder = Pair.PairBuilder.class)
public class Pair {
  @NonNull private String pairId;
  private String left;
  private String right;

  @Builder
  private Pair(String pairId) {
    this.pairId = pairId;
    left = pairId.substring(0, 3).toUpperCase(Locale.US);
    right = pairId.substring(3).toUpperCase(Locale.US);
  }

  @JsonPOJOBuilder(withPrefix = "")
  public static final class PairBuilder {
//    @JsonCreator
//    public PairBuilder pairID(@NonNull String pairId) {
//      this.pairId = pairId;
//      return this;
//    }
  }
}

I get this exception

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.rwest.bitcoinchecker.Pair$PairBuilder: no String-argument constructor/factory method to deserialize from String value ('btcusd')


Solution

  • You have already specified builder with lombok annotation, you don't have to create builder class yourself.

    Working example:.

    import org.springframework.web.client.RestTemplate;
    
    RestTemplate restTemplate = new RestTemplate();
    Pair[] pairs = restTemplate
            .getForObject("https://api.bitfinex.com/v1/symbols", Pair[].class);
    

    Pair class:

    import lombok.AccessLevel;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.NonNull;
    import lombok.Value;
    
    import java.util.Locale;
    
    @Value
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    public class Pair {
        @NonNull private String pairId;
        private String left;
        private String right;
    
        @Builder
        private Pair(String pairId) {
            this.pairId = pairId;
            left = pairId.substring(0, 3).toUpperCase(Locale.US);
            right = pairId.substring(3).toUpperCase(Locale.US);
        }
    }
    

    Result:

    Pair(pairId=btcusd, left=BTC, right=USD)
    Pair(pairId=ltcusd, left=LTC, right=USD)
    Pair(pairId=ltcbtc, left=LTC, right=BTC)
    ...
    ...