Home > OS >  Convert json string to objects without key
Convert json string to objects without key

Time:12-10

There's a json string without key for each objects like

[
    {
        "name": "A",
        "number": 1,
        "age": 20
    },
    {
        "name": "B",
        "number": 2,
        "age": 30
    },
    {
        "name": "C",
        "number": 3,
        "age": 40
    }
]

and I only need name and number, so I have a class like below trying to encode the json string into it

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@EqualsAndHashCode(callSuper = true)
public class FooResClass extends BaseResModel {

 private static final long serialVersionUID = -6398045272254450504L;

 private List<AData> aDataList;

  @Data
  @JsonIgnoreProperties(ignoreUnknown = true)
  public class AData {
    @JsonProperty("number")
    private Long number;
    @JsonProperty("name")
    private String name;
  }

then it says

jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of

am I doing anything wrong?

CodePudding user response:

TL;DR

Your JSON and POJO don't match, and there are several ways to resolve the problem:

  • parse JSON as List<FooResClass.AData> and then instantiate FooResClass;
  • define a custom Deserializer (that allows to reuse the parsing logic and would be a preferred way if you would choose to change the code);
  • change the structure of your JSON.

Details

Firstly, if AData is nested, it should be static (otherwise an instance of the enclosing class would be required for instantiation and parsing would fail).

Secondly, the JSON you have represents an Array of JSON-objects that correspond to the AData class. I.e. it's not a JSON-object but a JSON-array, which matches a List<AData>, but not to the instance of enclosing class FooResClass.

For instance, the following parsing would succeed:

String json = // your json data
ObjectMapper mapper = new ObjectMapper();

List<AData> aData = mapper.readValue(json,  new TypeReference<List<FooResClass.AData>>(){});
FooResClass fooRes = new FooResClass(aDataList); // assuming that all-args constructor was defined

In order to obtain an instance of FooResClass with your current code, the JSON should be structured in the following way:

{
   "aDataList":[
      {
         "name":"A",
         "number":1,
         "age":20
      },
      {
         ...
      },
      {
         ...
      }
   ]
}

If you can't change the structure of the JSON you need to customize the deserialization of the FooResClass.

Deserializer

For that, you can define a custom Deserializer by extending StdDeserializer and overriding its abstract method deserialize().

That's how it might be implemented:

public class FooResClassDeserializer extends StdDeserializer<FooResClass> {

    public FooResClassDeserializer() {
        this(null);
    }

    public FooResClassDeserializer(Class<FooResClass> vc) {
        super(vc);
    }

    @Override
    public FooResClass deserialize(JsonParser p,
                                   DeserializationContext ctxt) throws IOException, JacksonException {
        
        ObjectMapper mapper = new ObjectMapper();
        List<FooResClass.AData> aDataList = mapper.readValue(p, new TypeReference<>() {});
        return new FooResClass(aDataList);
    }
}

To instruct Jackson that this Desirializer should be used while pasing FooResClass, you need to annotate this class with @JsonDeserialize and specify the class of Desirializer thought the using attribute.

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@JsonDeserialize(using = FooResClassDeserializer.class)
public static class FooResClass extends BaseResModel {

    private static final long serialVersionUID = -6398045272254450504L;

    @JsonProperty("aDataList")
    private List<AData> aDataList;

    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class AData {
        @JsonProperty("number")
        private Long number;
        @JsonProperty("name")
        private String name;
    }
}

With this change, you'll be able to parse the current unaltered JSON into an instance of FooResClass (I've tested this solution by removing the extends clause, since you haven't provided BaseResModel class).

  • Related