Saeed Rajabi Saeed Rajabi - 2 months ago 24
Java Question

How to deserialize json to enum with jackson in java?

I have an interface with name Field as below:

public interface Field {
}


This interface is in the module A.
I have an enum called BField which is in module B and is implemented as below:

public enum BField implements Field {
SOME_FIELD
}


There is a class named C in the module A as below:

public class C implements Serializable {
private Set<Field> f;

public Set<Field> getF() { return f; }
public void setF(Set<Field> f) { this f = f; }
}


I have a REST method as below:

@RequestMapping(method=RequestMethod.Post, value="/save")
@ResponseBody
public void save (@RequestBody C c) {
//save c
}


I send this JSON object to this method:

{
"f": ["SOME_FIELD"]
}


then I get HTTP 400 bad request error code with the following exception log:


abstract types can only be instantiated with additional type
information


The hierarchy of the modules is module B is dependent to module A. I tried to use @JsonTypeInfo but the dependency between modules works as a limit and does not let me to use BField.class in the @JsonSubTypes annotation for the field f in class C.

Answer

At last I find the solution.

  1. I remove <mvc:annotation-driven/> in my context
  2. Add @JsonDeserialize(as = EnumSet.class) annotation for field private Set<Field> f; in class C.
  3. create a class called JsonBFieldDeserializer in module B as below:

    public class JsonBFieldDeserializer extends StdDeserializer<Field> {
        public JsonBFieldDeserializer() {
            this(null);
        }
        public JsonBFieldDeserializer(Class<?> vc) {
            super(vc);
        }
        @Overrid
        public Field deserialize(JsonParser jsonParser, DeserializationContext dC) throws IOException, JsonProcessingException {
            JsonNode node = jsonParser.getCodec().readTree();
            String text = node.asText();
            return BField.valueOf(text);
        }
    }
    
  4. Create a class called BConfiguration in module B as below:

    @Configuration
    public class BConfiguration extends WebMVCConfigurationSupport {
        protected void configureMessageConverters(List<HttpMessageConverters<?>> converters){
            converters.add(convert());
            addDefaultHttpMessageConverters(converters);
        }
        @Bean
        MappingJackson2HttpMessageConverter convert(){
            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            ObjectMapper objectMapper = new ObjectMapper();
            SimpleModule module = new SimpleModule();
            module.addDeserializer(Field.class, new JsonBFieldDeserializer());
            objectMapper.registerModule(module);
            converter.setObjectMapper(objectMapper);
            return converter;
        }
    }
    
  5. Be careful to use fasterxml jackson not codehaus library!