Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

521
Visualizações
CustomDeserializer has no default (no arg) constructor

I am consuming a REST Api with RestTemplate. The response I'm getting from the API has lots of nested objects. Here's a little snippet as an example:

"formularios": [
  {
    "form_data_id": "123006",
    "form_data": {
      "form_data_id": "123006",
      "form_id": "111",
      "efs": {
        "1": {},
        "2": "{\"t\":\"c\",\"st\":\"m\",\"v\":[{\"id\":\"3675\",\"l\":\"a) Just an example\",\"v\":\"1\"},{\"id\":\"3676\",\"l\":\"b) Another example.\",\"v\":\"2\"}]}"
      }
    }

The problem I'm having is that most of the times the "1" actually has content, just like "2", and the jackson just parses it as a String on the object "efs". But sometimes, just like in the code snippet, the API sends it empty, and jackson takes it as an Object, which gives me an error that says something about START_OBJECT (can't remember the exact error, but it's not important for this question).

So I decided to make a custom deserializer so when jackson reads "1", it ignores the empty object and just parses it as a null string.

Here's my custom deserializer:

public class CustomDeserializer extends StdDeserializer<Efs> {

 public CustomDeserializer(Class<Efs> t) {
     super(t);
 }

 @Override
 public Efs deserialize(JsonParser jp, DeserializationContext dc)
         throws IOException, JsonProcessingException {

     String string1 = null;
     String string2 = null;
     JsonToken currentToken = null;

     while ((currentToken = jp.nextValue()) != null) {
         if (currentToken.equals(JsonToken.VALUE_STRING)) {
             if (jp.getCurrentName().equals("1")) {
                 string1 = jp.getValueAsString();
             } else {
                 string2 = jp.getValueAsString();
             }

         } else {
             if (jp.getCurrentName().equals("2")) {
                 string2 = jp.getValueAsString();
             }

         }
     }
     return new Efs(string1, string2);

  }
 }

And this is the way I'm using it when receiving the response from the API:

    ObjectMapper mapper = new ObjectMapper();  
    SimpleModule mod = new SimpleModule("EfsModule");
    mod.addDeserializer(Efs.class, new CustomDeserializer(Efs.class));
    mapper.registerModule(mod);


    List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
    jsonMessageConverter.setObjectMapper(mapper);
    messageConverters.add(jsonMessageConverter);


    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setMessageConverters(messageConverters);

I'm getting the error:

 CustomDeserializer has no default (no arg) constructor

But I don't know exactly what I'm doing wrong nor how to solve it. Thanks for the help and apologies for the long question, I wanted to give as much context as possible.

about 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

There is also one trap that users can fall into (like my self). If you declare deserializer as a inner class (not a static nested class) like:

@JsonDeserialize(using = DomainObjectDeserializer.class)
public class DomainObject {
    private String key;

    public class DomainObjectDeserializer extends StdDeserializer<DomainObject> {
        public DomainObjectDeserializer() {
            super(DomainObject.class);
        }

        @Override
        public DomainObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            // code
        }
    }
}

Jackson uses the Class#getDeclaredConstructor() with no argument (method accepts vararg) which means: give me a default (no argument) constructor. Code above will throw exception when Jackson tries to create DomainObjectDeserializer because javac generates the constructor that accepts enclosing class reference. Technically speaking DomainObjectDeserializer does not have a default constructor.

For a curiosity sake you can execute DomainObjectDeserializer.class.getDeclaredConstructors() and ensure that method does return single element array containing constructor definition with enclosing class reference.

The DomainObjectDeserializer should be declared as a static class.

Here is a good answer to read in more details.

about 4 years ago · Santiago Trujillo Relatório

0

It is required that you have a default constructor without arguments. What you can do is create one (or replace the other one if you don't really need it):

public class CustomDeserializer extends StdDeserializer<Efs> {

   public CustomDeserializer() {
       super(Efs.class);
   }
   ...
}
about 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda