Custom Jackson Deserializer to omit mapping of certain objects Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of Custom Jackson Deserializer to omit mapping of certain objects without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I have a large JSON file that is made up of structures that I am mapping into POJOs, and then storing in a Collection. The structure is similar to this:

[
{
    "id": 1234,
    "file": "C:\Programs\Program1.exe",
    "exists": true
}
{
    "id": 5678,
    "file": "C:\Programs\Program2.exe",
    "exists": false
}
...
]

Using the Jackson streaming API I have got all these structures read, and the POJOs stored in a Collection successfully. My POJO class looks like this:

public class Programs
{
    @JsonProperty("id")
    private Integer id;

    @JsonProperty("file")
    private String file;

    @JsonProperty("exists")
    private Boolean exists;

    @JsonGetter("id")
    public Integer getId()
    {
      return id;
    }

    @JsonGetter("file")
    public String getFile()
    {
      return file;
    }

    @JsonGetter("exists")
    public Boolean getExists()
    {
      return exists;
    }
}

However, I want to omit any structures that have "exists" set to false during the deserialization process so that no POJO is ever created for them. So I wrote a custom deserializer with the help of this SO question [ How do I call the default deserializer from a custom deserializer in Jackson ], with my overridden deserialize looking like:

@Override
public Programs deserialize(JsonParser parser, DeserializationContext context)
   throws IOException
{
    Programs programs = (Programs)defaultDeserializer.deserialize(parser, context);

    if (!programs.getExists())
    {
        throw context.mappingException("[exists] value is false.");
    }
    return programs;
}

However, when I run some unit tests, I get the following error:

"Can not deserialize instance of java.util.ArrayList out of START_OBJECT token"
message was "Class com.myprogram.serializer.ProgramsJsonDeserializer
has no default (no arg) constructor"

(Adding a no arg constructor gives the error that StdDeserializer does not have a default constructor.)

Is this the correct approach to achieving what I am trying to do? And does anyone know why I get this error message?

Answer

I want to omit any structures that have “exists” set to false during the deserialization process so that no POJO is ever created for them.

I think your objective is to retrieve a list of Programs instance that only have exists set to true after derserialization. A customized CollectionDeserializer to filter those unwanted instance may help:

public class ProgramsCollectionHandler extends SimpleModule {
    private static class ProgramsCollectionDeserializer extends CollectionDeserializer {

        public ProgramsCollectionDeserializer(CollectionDeserializer deserializer) {
            super(deserializer);
        }

        private static final long serialVersionUID = 1L;

        @Override
        public Collection<Object> deserialize(JsonParser parser, DeserializationContext context)
                throws IOException, JsonProcessingException {
            Collection<Object> result = super.deserialize(parser, context);
            Collection<Object> filteredResult = new ArrayList<Object>();
            for (Object o : result) {
                if (o instanceof Programs) {
                    final Programs programs = (Programs) o;
                    if (programs.exists) {
                        filteredResult.add(programs);
                    }
                }
            }
            return filteredResult;
        }

        @Override
        public CollectionDeserializer createContextual(
                DeserializationContext context,
                BeanProperty property) throws JsonMappingException {
            return new ProgramsCollectionDeserializer(super.createContextual(context, property));
        }
    }

    private static final long serialVersionUID = 1L;

    @Override
    public void setupModule(Module.SetupContext context) {
        super.setupModule(context);
        context.addBeanDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyCollectionDeserializer(
                    DeserializationConfig config, CollectionType type,
                    BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                if (deserializer instanceof CollectionDeserializer) {
                    return new ProgramsCollectionDeserializer(
                            (CollectionDeserializer) deserializer);
                }
                return super.modifyCollectionDeserializer(config, type, 
                        beanDesc, deserializer);
            }
        });
    }
}

After that, your can register it into your object mapper:

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

“Can not deserialize instance of java.util.ArrayList out of START_OBJECT token” message was “Class com.myprogram.serializer.ProgramsJsonDeserializer has no default (no arg) constructor” (Adding a no arg constructor gives the error that StdDeserializer does not have a default constructor.)

This may be because your constructor cannot be accessed. For example, your deserializer is implemented as a non-static inner class.

We are here to answer your question about Custom Jackson Deserializer to omit mapping of certain objects - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji