Use @JacksonInject with @JsonCreator on a top level map

Using the Jackson json library, you can deserialize the object using @JsonCreator and get a top-level map representing the json input as follows:

 class MyClass { final int field; @JsonCreator public MyClass(Map<String, Object> map) { this.field = (int) map.get("theInt"); } } 

or even using the static factory method:

 class MyClass { final int field; public MyClass(int theInt) { this.field = theInt; } @JsonCreator static MyClass create(Map<String, Object> map) { return new MyClass((int) map.get("theInt")); } } 

In the previous examples, you can handle the following json input:

 { "key1":"value1", "key2":"value2", "key3":"value3" } 

This is especially useful in my case, because I would like to deserialize json, which structure I don't know. Giving access to what I call a “top-level map” makes things simple.

I would like to deserialize my objects this way, since it also allows you to create immutable objects instead of using @JsonAnySetter , which does not allow this, and @JsonProperty , which I cannot use, since I do not know the name of the property in advance, as I mentioned earlier.

Then, to continue, I would like to add some configuration to my factory method, and Jackson resolves this with @JacksonInject and calling withInjectableValues(InjectableValues) on ObjectMapper .

In the end, this is the code I would like to use:

 class MyClass { final MyField[] myFields; public MyClass(MyField... myFields) { this.myFields = myFields; } @JsonCreator static MyClass create(@JacksonInject("conf") Conf conf, Map<String, Object> map) { MyFields[] myFields; // initialize myFields (or any other object) based on the content of map // and also make use of the inject conf return new MyClass(myFields); } } 

Unfortunately, Jackson throws the following exceptions:

  • when trying to use a constructor trick

JsonMappingException: Argument #1 of constructor [constructor for MyClass, annotations: { JsonCreator=@JsonCreator ()}] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator

  • when trying to use factory trick

JsonMappingException: Argument #1 of factory method [method create, annotations: { JsonCreator=@JsonCreator ()}] has no property name annotation; must have when multiple-paramater static method annotated as Creator

Does anyone know how I can solve the problem?

To summarize, I need:

  • access to top level map (don't know json property names in advance)
  • to create an immutable object (so you cannot use @JsonAnySetter )
  • to enter some conf into the constructor @JsonCreator decorated or factory

I cannot change the json input format, which looks like this:

 { "key1":"value1", "key2":"value2", "key3":"value3" } 

[EDIT]

This is a known issue: http://jira.codehaus.org/browse/JACKSON-711 (not yet fixed)

+6
source share
1 answer

That's right, you would like to use the "delegating" creator (the only argument into which the JSON input is first entered) - differs from the creator based on properties where a lot of named parameters are passed - and the value for injection (s). This should work perfectly, but I think it might not work at the moment. I think Jira is introduced for this, so you can check it out (http://jira.codehaus.org/browse/JACKSON).

Just to make sure: are you using version 1.9.2? There have been some fixes since 1.9.0; which, at least, will give a better error message.

+4
source

Source: https://habr.com/ru/post/902827/


All Articles