1

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.

2 Answers 2

1

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) 
Sign up to request clarification or add additional context in comments.

3 Comments

Excuse me I forgot to note that the interface Field has multiple implementations. For example BField in module B and DField in module D.
Thank you. Your solution works when I test it with only one implementation of the interface Field, but I have to depend module A to module B, too. My problem is a little different. First I don't want depend module A to module B, second interface Field has multiple implementations in multiple modules.
What you want is probably only possible if you collect Jackson pieces from your modules and aggregate them; one example is how Druid allows you to register custom parsers and other stuff: druid.io/docs/latest/development/modules.html
0

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!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.