FasterXML / jackson-databind

General data-binding package for Jackson (2.x): works on streaming API (core) implementation(s)
Apache License 2.0
3.52k stars 1.38k forks source link

ACCEPT_SINGLE_VALUE_AS_ARRAY doesn't work on Guava ImmutableList #3986

Open JGergely opened 1 year ago

JGergely commented 1 year ago

Describe the bug When defining a Guava ImmutableList on org.immutables.value.Value.Immutable objects to correctly deserialize both from a single JSON object and also from an array with the ACCEPT_SINGLE_VALUE_AS_ARRAY annotation on the field it fails to do so.

In case of using a java.util.List instead of the Guava type it works. Not sure if issue is within Jackson itself or somewhere else, please advise.

Version information 2.14

To Reproduce To reproduce I created an Immutable type with a single list field which should accept both a single object and an array as a JSON input (set with ACCEPT_SINGLE_VALUE_AS_ARRAY).

@Value.Immutable
public interface ExampleInterface {
  @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
  ImmutableList<ExampleLine> getLines();
}

@Value.Immutable
public interface ExampleLineInterface {
  String getData();
}

class Scratch {
    public static void main(String[] args) {
         /*
            { 
                lines": 
                {
                    "data": "something"
                }
            }
         */
        String example = "{ " +
                "           \"lines\": \n" +
                "           {\n" +
                "             \"data\": \"something\"\n" +
                "           }" +
                "         }";
        try {
            Example actual = getObjectMapper().readValue(example, Example.class);
            System.out.println(actual);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    private static ObjectMapper getObjectMapper() {
        return JsonMapper.builder()
                .visibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
                .visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY)
                .visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
                .propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
                .enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
                .enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
                .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
                .enable(MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES)
                .disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .addModule(new GuavaModule())
                .addModule(new FormattedNumberIdModule())
                .addModule(new JavaTimeModule())
                .addModule(new Jdk8Module())
                .addModule(new ParameterNamesModule())
                .build();

    }
}

throws

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `com.google.common.collect.ImmutableList<java.lang.Object>` from Object value (token `JsonToken.START_OBJECT`)
 at [Source: (String)"{            "lines": 
           {
             "data": "something"
           }         }"; line: 2, column: 12] (through reference chain: com.picnic.supplierinterface.edeka.reddi.api.model.Example$Json["lines"])

while the same thing but with a java.util.List type:

@Value.Immutable
public interface ExampleInterface {
  @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
  List<ExampleLine> getLines();
}

deserializes correctly and prints:

Example{lines=[ExampleLine{data=something}]}
cowtowncoder commented 1 year ago

Ok, I strongly suspect this is not something Jackson handles, but things do get hairy with combinations of so many pieces.

One thing that might help would be to first see if direct use of ImmutableList (from Guava) would work, without Immutables framework. If not, it's likely Guava module's problem (and if so, should move/file issue there).

JGergely commented 1 year ago

Thanks, I'll check and report back!