简体   繁体   中英

JSON to Java POJO not working for simple structure?

JSON:

{
  "246": {
    "test1": "one" 
  },
  "355": {
    "test2": "two"
  }
}

Java POJO

class POJO{
  private HashMap<String, SubPojo> subMap;

  @JsonAnySetter
  public void addToMap(String key, SubPojo val){ subMap.put(key, value); }
}

class SubPojo{
  private HashMap<String, String> map; 
  @JsonAnySetter
  public void addToMap(String key, String val) { map.put(key, value);}
}

In my code I do: (using Jackson )

POJO testing = (new ObjectMapper()).convertValue("path/to/json", POJO.class);

I get an exception saying:

"Unrecognized field `246`..."

Where am I going wrong?

Something like this:

public class Pojo {
    private Map<String,Object> map = new HashMap<>();

    @JsonAnySetter
    public void addToMap(String key, Object value) {
        this.map.put(key, value);
    }

    @JsonAnyGetter
    public Map<String,Object> getMap() {
        return map;
    }
}

There is an article on Baeldung which covers various Jackson annotations, including this one, and some basics on the Jackson wiki .

converValue method is used to convert objects. See JavaDoc :

Convenience method for doing two-step conversion from given value, into instance of given value type, if (but only if!) conversion is needed. If given value is already of requested type, value is returned as is. This method is functionally similar to first serializing given value into JSON, and then binding JSON data into value of given type, but should be more efficient since full serialization does not (need to) occur. However, same converters (serializers, deserializers) will be used as for data binding, meaning same object mapper configuration works.

For example, you can "convert" File to String like this:

mapper.convertValue(jsonFile, String.class)

Where jsonFile is an instance of File class. Example result could be: path/to/json .

To deserialise JSON payload use one from readValue method family.

You can create your POJO with constructor annotated JsonCreator :

class Pojo {

    private final Map<String, SubPojo> map;

    @JsonCreator
    public Pojo(Map<String, SubPojo> map) {
        this.map = map;
    }

    public Map<String, SubPojo> getMap() {
        return map;
    }

    @Override
    public String toString() {
        return "Pojo{" +
                "map=" + map +
                '}';
    }
}

class SubPojo {

    private Map<String, String> map;

    @JsonCreator
    public SubPojo(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public String toString() {
        return "SubPojo{" +
                "map=" + map +
                '}';
    }
}

And simple usage. To read JSON from file use readValue method:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        Pojo map = mapper.readValue(jsonFile, Pojo.class);
        System.out.println(map);
    }
}

Above code prints:

Pojo{map={246=SubPojo{map={test1=one}}, 355=SubPojo{map={test2=two}}}}

If you would like to stay with your data model use JsonAnySetter annotation. Your data model could look like this:

class Pojo {
    private Map<String, SubPojo> subMap = new HashMap<>();

    @JsonAnySetter
    public void addToMap(String key, SubPojo value) {
        subMap.put(key, value);
    }

    @Override
    public String toString() {
        return "POJO{" +
                "subMap=" + subMap +
                '}';
    }
}

class SubPojo {
    private Map<String, String> map = new HashMap<>();

    @JsonAnySetter
    public void addToMap(String key, String value) {
        map.put(key, value);
    }

    @Override
    public String toString() {
        return "SubPojo{" +
                "map=" + map +
                '}';
    }
}

Above usage example prints:

POJO{subMap={355=SubPojo{map={test2=two}}, 246=SubPojo{map={test1=one}}}}

You don't need to create any POJO classes to parse that JSON text, since it can be parsed into a Map<String, Map<String, String>> .

You will have to use a TypeReference to prevent loss of the generic type arguments.

Map<String, Map<String, String>> data = new ObjectMapper()
        .readValue(new File("test.json"),
                   new TypeReference<Map<String, Map<String, String>>>() {});

Printing that data map, using the JSON text in the question, will show:

{246={test1=one}, 355={test2=two}}

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