Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

518
Views
CustomDeserializer no tiene un constructor predeterminado (sin argumento)

Estoy consumiendo una REST Api con RestTemplate. La respuesta que recibo de la API tiene muchos objetos anidados. Aquí hay un pequeño fragmento como ejemplo:

 "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\"}]}" } }

El problema que tengo es que la mayoría de las veces el "1" en realidad tiene contenido, al igual que "2", y Jackson simplemente lo analiza como una cadena en el objeto "efs". Pero a veces, al igual que en el fragmento de código, la API lo envía vacío y jackson lo toma como un Objeto, lo que me da un error que dice algo sobre START_OBJECT (no recuerdo el error exacto, pero no es importante para esta pregunta ).

Así que decidí hacer un deserializador personalizado para que cuando jackson lea "1", ignore el objeto vacío y simplemente lo analice como una cadena nula.

Aquí está mi deserializador personalizado:

 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); } }

Y esta es la forma en que lo estoy usando cuando recibo la respuesta de la 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);

Estoy recibiendo el error:

 CustomDeserializer has no default (no arg) constructor

Pero no se exactamente que estoy haciendo mal ni como solucionarlo. Gracias por la ayuda y disculpas por la pregunta larga, quería dar el mayor contexto posible.

about 4 years ago · Santiago Trujillo
2 answers
Answer question

0

También hay una trampa en la que los usuarios pueden caer (como yo). Si declara el deserializador como una clase interna (no una clase anidada estática) como:

 @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 usa Class#getDeclaredConstructor() sin argumentos (el método acepta vararg ), lo que significa: dame un constructor predeterminado (sin argumentos). El código anterior generará una excepción cuando Jackson intente crear DomainObjectDeserializer porque javac genera el constructor que acepta la referencia de clase adjunta. Técnicamente hablando, DomainObjectDeserializer no tiene un constructor predeterminado.

Por curiosidad, puede ejecutar DomainObjectDeserializer.class.getDeclaredConstructors() y asegurarse de que el método devuelva una matriz de un solo elemento que contenga una definición de constructor con una referencia de clase adjunta.

DomainObjectDeserializer debe declararse como una clase static .

Aquí hay una buena respuesta para leer con más detalles.

about 4 years ago · Santiago Trujillo Report

0

Se requiere que tenga un constructor predeterminado sin argumentos. Lo que puede hacer es crear uno (o reemplazar el otro si realmente no lo necesita):

 public class CustomDeserializer extends StdDeserializer<Efs> { public CustomDeserializer() { super(Efs.class); } ... }
about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!