简体   繁体   中英

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.

The problem here is not the enum , it's the Set and the Field interfaces.

You need to tell Jackson what kind of Set and what kind of Field you want, and you can do that by annotating that property with:

@JsonDeserialize(as = EnumSet.class, contentAs = BField.class)

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM