As I indicated in the comment to the question here is the test that shows how to do this:

public class JSONTest {

  public static class FullyTypedThing {
    public int id;
    public String name;
    public List<Photos> photos = Lists.newArrayList();
    public String username;

    public static class Photos {
      public String name;
      public String url;
    }
  }

  private static final String json = "[ { \"id\" : 33147,    \"name\" : \"Refinancing\", \"photos\" : [ {"
    + "\"name\" : \"347.png\", \"url\" : \"/loans/568/photos/092\"  } ],"
    + "\"username\" : \"zach1985\"} , {  \"id\" : 7693,  \"name\" : \"Stuff\","
    + "\"photos\" : [ {  \"name\" : \"newpic1.png\",  \"url\" : \"/loans/123446/photos/890\"  } ],"
    + "\"username\" : \"sengaia\"  } ]";

  @Test
  public void roundtrip() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<FullyTypedThing> res = Lists.newArrayList(
      mapper.readValue(json, FullyTypedThing[].class));
    assertEquals(2, res.size());
    assertEquals(33147, res.get(0).id);
    assertEquals("Refinancing", res.get(0).name);
    assertEquals("347.png", res.get(0).photos.get(0).name);
    assertEquals("/loans/568/photos/092", res.get(0).photos.get(0).url);
    assertEquals(7693, res.get(1).id);
    assertEquals("Stuff", res.get(1).name);
    assertEquals("newpic1.png", res.get(1).photos.get(0).name);
    assertEquals("/loans/123446/photos/890", res.get(1).photos.get(0).url);

    assertEquals("[{\"id\":33147,\"name\":\"Refinancing\",\"photos\":"
      + "[{\"name\":\"347.png\",\"url\":\"/loans/568/photos/092\"}],"
      + "\"username\":\"zach1985\"},{\"id\":7693,\"name\":\"Stuff\","
      + "\"photos\":[{\"name\":\"newpic1.png\",\"url\":\"/loans/123446/photos/890\"}],"
      + "\"username\":\"sengaia\"}]", mapper.writeValueAsString(res));

  }
}
Answer from Oleg Sklyar on Stack Overflow
๐ŸŒ
Baeldung
baeldung.com โ€บ home โ€บ json โ€บ jackson โ€บ jackson โ€“ unmarshall to collection/array
Jackson - Unmarshall to Collection/Array | Baeldung
April 26, 2024 - Reading the same JSON Array into a Java Collection is a bit more difficult โ€“ by default, Jackson will not be able to get the full generic type information and will instead create a collection of LinkedHashMap instances: @Test public void givenJsonArray_whenDeserializingAsListWithNoTypeInfo_thenNotCorrect() throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = new ObjectMapper(); List<MyDto> listOfDtos = Lists.newArrayList( new MyDto("a", 1, true), new MyDto("bc", 3, false)); String jsonArray = mapper.writeValueAsString(listOfDtos); List<MyDto> asList = mapper.readValue(jsonArray, List.class); assertThat((Object) asList.get(0), instanceOf(LinkedHashMap.class)); }
Top answer
1 of 1
2

As I indicated in the comment to the question here is the test that shows how to do this:

public class JSONTest {

  public static class FullyTypedThing {
    public int id;
    public String name;
    public List<Photos> photos = Lists.newArrayList();
    public String username;

    public static class Photos {
      public String name;
      public String url;
    }
  }

  private static final String json = "[ { \"id\" : 33147,    \"name\" : \"Refinancing\", \"photos\" : [ {"
    + "\"name\" : \"347.png\", \"url\" : \"/loans/568/photos/092\"  } ],"
    + "\"username\" : \"zach1985\"} , {  \"id\" : 7693,  \"name\" : \"Stuff\","
    + "\"photos\" : [ {  \"name\" : \"newpic1.png\",  \"url\" : \"/loans/123446/photos/890\"  } ],"
    + "\"username\" : \"sengaia\"  } ]";

  @Test
  public void roundtrip() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<FullyTypedThing> res = Lists.newArrayList(
      mapper.readValue(json, FullyTypedThing[].class));
    assertEquals(2, res.size());
    assertEquals(33147, res.get(0).id);
    assertEquals("Refinancing", res.get(0).name);
    assertEquals("347.png", res.get(0).photos.get(0).name);
    assertEquals("/loans/568/photos/092", res.get(0).photos.get(0).url);
    assertEquals(7693, res.get(1).id);
    assertEquals("Stuff", res.get(1).name);
    assertEquals("newpic1.png", res.get(1).photos.get(0).name);
    assertEquals("/loans/123446/photos/890", res.get(1).photos.get(0).url);

    assertEquals("[{\"id\":33147,\"name\":\"Refinancing\",\"photos\":"
      + "[{\"name\":\"347.png\",\"url\":\"/loans/568/photos/092\"}],"
      + "\"username\":\"zach1985\"},{\"id\":7693,\"name\":\"Stuff\","
      + "\"photos\":[{\"name\":\"newpic1.png\",\"url\":\"/loans/123446/photos/890\"}],"
      + "\"username\":\"sengaia\"}]", mapper.writeValueAsString(res));

  }
}
Discussions

Help deserializing a JSON array of arrays in DSL-JSON
I have no knowledge of dsl-json, but the ObjectMapper error is clear. Your input data is a List>. Is this really how it's supposed to look? Usually in Java you would create a class or record representing the data model and use mapper.readValue(jsonString, YourRecord.class), but with this type of data it's going to be tricky. Edit. Maybe you can deserialize it to Object[][].class More on reddit.com
๐ŸŒ r/javahelp
26
1
September 1, 2022
How to Deserialize Array of JSON Objects in Java - Stack Overflow
In case it is a JSON Array you can read it as array and create response object manually. Below you can find example custom deserialiser and BeanDeserializerModifier which is used to register custom deserialiser. More on stackoverflow.com
๐ŸŒ stackoverflow.com
September 26, 2019
java - How deserialize json object array as array of json strings? - Stack Overflow
Is there a way to configure Jackson serialization to keep companies array with raw json string with annotations only? (E.g. without writing custom deserializator) ... There is no annotation-only solution for your problem. Somehow you have to convert JSON Object to java.lang.String and you need ... More on stackoverflow.com
๐ŸŒ stackoverflow.com
April 7, 2020
Deserialize a JSON array into a Java object (Not a List nor a Collection) using Jackson - Stack Overflow
I was previously using Gson and decided to move to Jackson for practical reasons. Previously, I had a JSON deserializer that was deserializing an array of json objects into a single java object. Th... More on stackoverflow.com
๐ŸŒ stackoverflow.com
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ java โ€บ deserialize-json-array-to-a-single-java-object-with-jackson
Deserialize JSON Array to a Single Java Object with Jackson - GeeksforGeeks
July 23, 2025 - To deserialize an array to an object in Java, we typically use the Jackson library. Jackson unlocks diverse use cases, such as transforming API responses or manipulating structured data within an application. Note: Deserializing a JSON array into a single Java object directly with Jackson isn't ...
๐ŸŒ
Reddit
reddit.com โ€บ r/javahelp โ€บ help deserializing a json array of arrays in dsl-json
r/javahelp on Reddit: Help deserializing a JSON array of arrays in DSL-JSON
September 1, 2022 -

I want to deserialize this data:

[[ 1, 1, "Neil Peart", 67, "189 Carlton Street", "M5A 2K7", 21.12 ],
[ 2, 2, "Geddy Lee", 67, "189 Carlton Street", "M5A 2K7", -21.12 ],
[ 3, 3, "Alex Lifeson", 67, "189 Carlton Street", "M5A 2K7", 211.2 ]]

When I use this:

ObjectMapper mapper = new ObjectMapper();
byte[] input = jsonString.getBytes( StandardCharsets.US_ASCII );
com.google.gson.JsonObject dslObject1 = mapper.readValue( jsonString, com.google.gson.JsonObject.class );

It throws a JsonProcessingException with the message:

Cannot deserialize value of type `com.google.gson.JsonObject` from Array value (token `JsonToken.START_ARRAY`)

at [Source: (String)"[[1,1,"Neil Peart",67,"189 Carlton Street","M5A 2K7",21.12]...

When I use this:

byte[] input = jsonString.getBytes( StandardCharsets.US_ASCII );
com.dslplatform.json.JsonObject dslObject2 = dslJson.deserialize( com.dslplatform.json.JsonObject.class, input, input.length );`

it throws an IOException with this message:

Unable to find reader for provided type: interface com.dslplatform.json.JsonObject and fallback serialization is not registered.

Any suggestions?

Top answer
1 of 3
1

This may help you:

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        String json = "[\r\n" + "    {\r\n" + "        \"example\": \"test\",\r\n" + "        \"is_valid\": true\r\n"
                + "    },\r\n" + "    {\r\n" + "        \"example\": \"test2\",\r\n" + "        \"is_valid\": true\r\n"
                + "    }\r\n" + "]";
        Example[] ex = mapper.readValue(json, Example[].class);

    }

}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "example", "is_valid" })
class Example {

    @JsonProperty("example")
    private String example;
    @JsonProperty("is_valid")
    private Boolean isValid;

    public String getExample() {
        return example;
    }

    @JsonProperty("example")
    public void setExample(String example) {
        this.example = example;
    }

    @JsonProperty("is_valid")
    public Boolean getIsValid() {
        return isValid;
    }

    @JsonProperty("is_valid")
    public void setIsValid(Boolean isValid) {
        this.isValid = isValid;
    }
}
2 of 3
1

When response is a JSON Object you can use default bean deserialiser. In case it is a JSON Array you can read it as array and create response object manually. Below you can find example custom deserialiser and BeanDeserializerModifier which is used to register custom deserialiser. BeanDeserializerModifier allows to use default deserialiser when JSON payload fits POJO model:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        SimpleModule module = new SimpleModule();
        module.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                if (beanDesc.getBeanClass() == Response.class) {
                    return new ResponseJsonDeserializer((BeanDeserializerBase) deserializer);
                }
                return super.modifyDeserializer(config, beanDesc, deserializer);
            }
        });

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(module);


        System.out.println(mapper.readValue(jsonFile, Response.class));
    }
}

class ResponseJsonDeserializer extends BeanDeserializer {

    private final BeanDeserializerBase baseDeserializer;

    protected ResponseJsonDeserializer(BeanDeserializerBase src) {
        super(src);
        this.baseDeserializer = src;
    }

    @Override
    public Response deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (p.currentToken() == JsonToken.START_OBJECT) {
            return (Response) baseDeserializer.deserialize(p, ctxt);
        }
        if (p.currentToken() == JsonToken.START_ARRAY) {
            CollectionType collectionType = ctxt.getTypeFactory().constructCollectionType(List.class, Item.class);
            JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(collectionType);
            List<Item> results = (List<Item>) deserializer.deserialize(p, ctxt);

            Response response = new Response();
            response.setCount(results.size());
            response.setResults(results);

            return response;
        }

        throw MismatchedInputException.from(p, Response.class, "Only object or array!");
    }
}

class Response {

    private int count;
    private List<Item> results;

    // getters, setters, toString
}

class Item {

    private String example;

    @JsonProperty("is_valid")
    private boolean isValid;

    // getters, setters, toString
}

Above code for JSON Object payload prints:

Response{count=5, results=[Item{example='test', isValid=true}, Item{example='test2', isValid=true}]}

And for JSON Array payload prints:

Response{count=2, results=[Item{example='test', isValid=true}, Item{example='test2', isValid=true}]}
๐ŸŒ
HowToDoInJava
howtodoinjava.com โ€บ home โ€บ gson โ€บ gson โ€“ parse json array to java array or list
Gson - Parse JSON Array to Java Array or List
April 4, 2023 - Gson parses JSON arrays as members without difficulty if they are non-root objects. We can use the fromJson() method in the usual manner and it will parse the JSON array correctly to the required java array or list. Java program to deserialize JSON array as member object โ€“ to Java array of ...
๐ŸŒ
Dirask
dirask.com โ€บ posts โ€บ Java-deserialize-JSON-array-to-java-object-with-Jackson-lib-from-json-string-to-java-object-p2GB8j
Java - deserialize JSON array to java object with Jackson lib (from json string to java object)
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Arrays; public class JacksonDeserializeArray { public static void main(String[] args) throws JsonProcessingException { String usersJson = "[{\"name\":\"Kate\",\"age\":24}," + "{\"name\":\"John\",\"age\":26}," + "{\"name\":\"Ann\",\"age\":25}]"; ObjectMapper objectMapper = new ObjectMapper(); User[] users = objectMapper.readValue(usersJson, User[].class); System.out.println(Arrays.toString(users)); } private static class User { private String name; private int age; //
Find elsewhere
๐ŸŒ
Rip Tutorial
riptutorial.com โ€บ deserialize json collection to collection of objects using jackson
Java Language Tutorial => Deserialize JSON collection to collection...
CollectionType mapType = factory.constructMapLikeType(Map.class, String.class, Person.class); List<Person> list = mapper.readValue(jsonString, mapType);
๐ŸŒ
W3Docs
w3docs.com โ€บ java
How to use Jackson to deserialise an array of objects
Create a Java class that represents the object you want to deserialize. For example: public class User { private int id; private String name; // add getters and setters } Use the ObjectMapper class from the Jackson library to deserialize the JSON array.
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 61077279 โ€บ how-deserialize-json-object-array-as-array-of-json-strings
java - How deserialize json object array as array of json strings? - Stack Overflow
April 7, 2020 - Implement com.fasterxml.jackson.databind.util.Converter interface and convert JsonNode to String. It is semi-annotational way to solve a problem but we do not implement the worst part - deserialisation. Let's go to point 2. right away. ... ObjectMapper mapper = new ObjectMapper(); mapper.addHandler(new DeserializationProblemHandler() { @Override public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg) throws IOException { if (targetType.getRawClass() == String.class) { // read as tree and convert to String return p.readValueAsTree().toString(); } return super.handleUnexpectedToken(ctxt, targetType, t, p, failureMsg); } });
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 75328730 โ€บ deserialize-a-json-array-into-a-java-object-not-a-list-nor-a-collection-using
Deserialize a JSON array into a Java object (Not a List nor a Collection) using Jackson - Stack Overflow
JsonNode array = mapper.readTree(json); for (JsonNode element : array) { Map<Permissionable, Permissions> map = new HashMap<>(); Permissionable p = switch (element.get("type").asInt()) { case 0 -> new Permissionable.MockPermissionable(element.get("id").asLong()); case 1 -> new Permissionable.MockPermissionable(element.get("id").asLong()); default -> throw new JsonParseException("Unknown permissionable type", null); }; Permissions perms = new Permissions(element.get("allow").asLong(), element.get("deny").asLong()); map.put(p, perms); } return new PermissionOverwrites(map);
๐ŸŒ
javathinking
javathinking.com โ€บ blog โ€บ how-to-use-jackson-to-deserialise-an-array-of-objects
How to Deserialize a JSON Array of Objects with Jackson in Java: Step-by-Step Guide โ€” javathinking.com
Deserializing a JSON array of objects into Java with Jackson is straightforward once you understand the basics: define a POJO matching the JSON structure, use ObjectMapper to parse the JSON, and handle edge cases like nested objects or custom formats with custom deserializers.
๐ŸŒ
Reddit
reddit.com โ€บ r/learnjava โ€บ trying to deserialize a json array using a jackson custom deserializer
r/learnjava on Reddit: Trying to deserialize a json array using a Jackson custom deserializer
June 9, 2022 -

I am getting a null pointer exception when trying to run the program.

Cannot invoke "java.util.Collection.add(Object)" because "this.contacts" is null
java.lang.NullPointerException: Cannot invoke "java.util.Collection.add(Object)" because "this.contacts" is null

I have a json file that is structured like this:

{
  "id": 1,
  "name": {
    "first": "Yong",
    "last": "Mook Kim"
  },
  "contact": [
    {
      "type": "phone/home",
      "ref": "111-111-1234"
    },
    {
      "type": "phone/work",
      "ref": "222-222-2222"
    }
  ]
}

ContactsCustomDeserializer.java

package jacksontreedeserializer;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import jacksontree.Contact;
import jacksontree.Contacts;
import java.io.IOException;

public class ContactsCustomDeserializer extends StdDeserializer<Contacts>  {



    public ContactsCustomDeserializer(){

        this(null);

    }

    public ContactsCustomDeserializer(Class clz){
        super(clz);
    }



    @Override
    public Contacts deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JacksonException {

        Contacts contacts = new Contacts();
        try {
            JsonNode root = parser.getCodec().readTree(parser);
            JsonNode contactRoot = root.path("contact");

            if(contactRoot.isArray()){
                for(JsonNode node: contactRoot){
                    String type = node.path("type").asText();
                    String ref = node.path("red").asText();
                    Contact contact = new Contact(type,ref);
                    contacts.addContact(contact);

                }

            }

        }


        catch(JsonGenerationException e){
            e.printStackTrace();
        }

        return contacts;

    }
}

Contact.java

package jacksontree;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import jacksontreedeserializer.ContactsCustomDeserializer;

public class Contact {


    @JsonProperty("type")
    private String type;


    @JsonProperty("ref")
    private String ref;


    public Contact() {}

    public Contact(String type, String ref) {
        this.type = type;
        this.ref = ref;
    }

    @Override
    public String toString() {
        return "Contact{" +
                "type='" + type + '\'' +
                ", ref='" + ref + '\'' +
                '}';
    }





}

Contacts.java

package jacksontree;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Collection;
import java.util.List;

public class Contacts {


    @JsonProperty("contacts")
    private Collection<Contact> contacts;


    public Contacts(Collection<Contact> contacts){
        this.contacts = contacts;
    }

    public Contacts(){}


    public void addContact(Contact contact){
        contacts.add(contact);
    }


    @Override
    public String toString() {
        return "Contacts{" +
                "contacts=" + contacts +
                '}';
    }

}

Main.java

   @Test
    void deserialize() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(Contacts.class, new ContactsCustomDeserializer());
        objectMapper.registerModule(simpleModule);
        Contacts contacts = objectMapper.readValue(new File("/Users/foo/Downloads/LearningJackson/src/main/resources/data/user.json"), Contacts.class);
        System.out.println(contacts);


    }
Top answer
1 of 2
2
ContactsCustomDeserializer.java line 43 you're calling the wrong Contacts constructor. You're calling Contacts line 19 which does not set the contacts property. Delete construction on line 19, use the other construction in ContactsCustomDeserializer and pass an instance of the collection type you want. Or delete constructor on line 15 and initialize the collection to new ArrayList() or new HashSet() or whatever's appropriate.
2 of 2
1
Please ensure that: Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions You include any and all error messages in full - best also formatted as code block You ask clear questions You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions. If any of the above points is not met, your post can and will be removed without further warning. Code is to be formatted as code block (old reddit/markdown editor: empty line before the code, each code line indented by 4 spaces, new reddit: https://imgur.com/a/fgoFFis ) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc. Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit. Code blocks look like this: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above. If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures. To potential helpers Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice. I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
๐ŸŒ
Javatpoint
javatpoint.com โ€บ deserialize-to-collection-and-array-in-jackson
Deserialize to Collection/Array in Jackson - javatpoint
s JSON Views is another important element of Jackson. JSON Views is also used for serializing and deserializing Java objects. We use @JsonView annotation for customizing the view at the time of serializing/deserializing.
Top answer
1 of 3
9

If json data is of the form:

[ {...}, {...}, {...} ]

You got to use add another class say 'wrapper':

@JsonIgnoreProperties(ignoreUnknown = true)
public class ListDto extends ArrayList<GroupDto> {

    public ListDto() {
    }
}

And use this class while deserailizing. This approach worked for me.

2 of 3
1

You just need to specify the @JsonDeserialize(contentAs=GroupDto.class) in your setter. Serialization is always on get desserialization is always on set, or if you prefer you can specify both on the field.

Documentation for Serialize and Deserialize

Code sample:

import java.io.IOException;
import java.util.List;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonDeserialize;

public class JacksonDeserialize {

    public static class ModelClass {

        private String name;

        public ModelClass() {
        }

        public String getName() {
            return name;
        }

        public void setName(final String name) {
            this.name = name;
        }

        public ModelClass(final String name) {
            super();
            this.name = name;
        }

        @Override
        public String toString() {
            return "ModelClass [name=" + name + "]";
        }

    }

    public static class ListModelClass {

        private List<ModelClass> list;

        @JsonDeserialize(contentAs = ModelClass.class)
        public void setList(final List<ModelClass> list) {
            this.list = list;
        }

        @Override
        public String toString() {
            return "ListModelClass [list=" + list + "]";
        }

    }

    public static void main(final String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.readValue("{\"list\":[{\"name\":\"name1\"},{\"name\":\"name2\"}]}",
                ListModelClass.class));
    }

}
Top answer
1 of 2
4

Thanks to bureaquete for suggestion to use custom Deserializer. But it was more suitable for me to register it with SimpleModule instead of @JsonDeserialize annotation. Below is complete JUnit test example:

@RunWith(JUnit4.class)
public class MapArrayToObjectTest {
    private static ObjectMapper mapper;

    @BeforeClass
    public static void setUp() {
        mapper = new ObjectMapper();
        SimpleModule customModule = new SimpleModule("ExampleModule", new Version(0, 1, 0, null));
        customModule.addDeserializer(Person.class, new PersonDeserializer());
        mapper.registerModule(customModule);
    }

    @Test
    public void wrapperDeserializationTest() throws IOException {
        //language=JSON
        final String inputJson = "{\"persons\": [[\"John\", \"Doe\"], [\"Jane\", \"Doe\"]]}";
        PersonsListWrapper deserializedList = mapper.readValue(inputJson, PersonsListWrapper.class);
        assertThat(deserializedList.persons.get(0).lastName, is(equalTo("Doe")));
        assertThat(deserializedList.persons.get(1).firstName, is(equalTo("Jane")));
    }

    @Test
    public void listDeserializationTest() throws IOException {
        //language=JSON
        final String inputJson = "[[\"John\", \"Doe\"], [\"Jane\", \"Doe\"]]";
        List<Person> deserializedList = mapper.readValue(inputJson, mapper.getTypeFactory().constructCollectionType(List.class, Person.class));
        assertThat(deserializedList.get(0).lastName, is(equalTo("Doe")));
        assertThat(deserializedList.get(1).firstName, is(equalTo("Jane")));
    }
}

class PersonsListWrapper {
    public List<Person> persons;
}

class Person {
    final String firstName;
    final String lastName;

    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

class PersonDeserializer extends JsonDeserializer<Person> {
    @Override
    public Person deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        JsonNode node = jp.readValueAsTree();
        return new Person(node.get(0).getTextValue(), node.get(1).getTextValue());
    }
}

Note that if you do not need wrapper object, you can deserialize JSON array [["John", "Doe"], ["Jane", "Doe"]] directly to List<Person> using mapper as follows:

List<Person> deserializedList = mapper.readValue(inputJson, mapper.getTypeFactory().constructCollectionType(List.class, Person.class));
2 of 2
1

It is easy to serialize, but not so easy to deserialize in such manner;

The following class can be serialized into an array of strings as in your question with @JsonValue;

public class Person {

    private String firstName;
    private String lastName;

    //getter,setter,constructors

    @JsonValue
    public List<String> craeteArr() {
        return Arrays.asList(this.firstName, this.lastName);
    }
}

But to deserialize, I had to create a wrapper class, and use custom deserialization with @JsonDeserialize;

public class PersonWrapper {

    @JsonDeserialize(using = CustomDeserializer.class)
    private List<Person> persons;

    //getter,setter,constructors
}

and the custom deserializer itself;

public class CustomDeserializer extends JsonDeserializer<List<Person>> {

    @Override
    public List<Person> deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
        JsonNode node = jsonParser.readValueAsTree();
        ObjectMapper mapper = new ObjectMapper();
        return IntStream.range(0, node.size()).boxed()
                .map(i -> {
                    try {
                        List<String> values = mapper.readValue(node.get(i).toString(), List.class);
                        return new Person().setFirstName(values.get(0)).setLastName(values.get(1));
                    } catch (IOException e) {
                        throw new RuntimeException();
                    }
                }).collect(Collectors.toList());
    }
}

You need to put proper validation in deserializer logic to check that each mini-array contains exactly two values, but this works well.

I'd rather use these steps, and maybe to hide @JsonDeserialize, I'd do the following;

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonDeserialize(using = CustomDeserializer.class)
public @interface AcceptPersonAsArray {}

So you can use some custom annotation in PersonWrapper

public class PersonWrapper {

    @AcceptPersonAsArray
    private List<Person> persons;

    //getter,setter,constructors
}
Top answer
1 of 1
1

The problem comes from this line in you custom deserializer:

Foo obj = new ObjectMapper().readValue(s, Foo.class);

When you do it like this your CustomDeserializer is called a second time, but now with a json in different format and it can't handle it. To be more precise, it can't find the property named value. So you have two options for fixing it:

  1. Create Foo and set fields manually
public class CustomDeserializer extends StdDeserializer<Foo> {

    public CustomDeserializer(Class<Foo> clazz) {
        super(clazz);
    }

    public CustomDeserializer() {
        this(null);
    }

    @Override
    public Foo deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser);
        JsonNode valueNode = jsonNode.get("value").get(0);
        Foo obj = new Foo();
        obj.setField1(valueNode.get("field1").asText());
        obj.setField2(valueNode.get("field2").asText());
        return obj;
    }
}
  1. To keep CustomDeserializer as is, you need to register your deserializer only with the ObjectMapper instance, which does the actual deserializing of the initial json and don't use annotations on Foo to specify deserializer.
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Foo.class, new CustomDeserializer());
mapper.registerModule(module);

As a side note, if you choose second option, Foo obj = new ObjectMapper().readValue(s, Foo.class); - this line creates new instance of ObjectMapper every time you deserialize. It would be better to keep an instance of ObjectMapper as a static field, for example.

๐ŸŒ
Tpoint Tech
tpointtech.com โ€บ deserialize-to-collection-and-array-in-jackson
Deserialize to Collection/Array in Jackson - Tpoint Tech
March 17, 2025 - Deserializing the JSON Array to a Java Array or Collection is one of the most important tasks when we work with APIs in Java.