Jackson json to map and camelcase key name

我怕爱的太早我们不能终老 提交于 2020-12-29 06:10:58

问题


I want to convert json via jackson library to a map containing camelCase key...say...

from

{
    "SomeKey": "SomeValue",
    "AnotherKey": "another value",
    "InnerJson" : {"TheKey" : "TheValue"}
}

to this...

{
    "someKey": "SomeValue",
    "anotherKey": "another value",
    "innerJson" : {"theKey" : "TheValue"}
}

My Code...

public Map<String, Object> jsonToMap(String jsonString) throws IOException
{
    ObjectMapper mapper=new ObjectMapper();
    mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
    return mapper.readValue(jsonString,new TypeReference<Map<String, Object>>(){});
}

But this doesn't work...even other propertyNamingStrategy does not work on json...such as...

{
    "someKey": "SomeValue"
}

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.PascalCaseStrategy())

to

{
    "SomeKey": "SomeValue"
}

How to get the camelCase Map key name via jackson... or should I manually loop map and convert key or there are some other way???

Thanks in advance...


回答1:


As you are working with maps/dictionaries instead of binding the JSON data to POJOs (explicit Java classes that match the JSON data), the property naming strategy does not apply:

Class PropertyNamingStrategy ... defines how names of JSON properties ("external names") are derived from names of POJO methods and fields ("internal names")

Therefore, you have to first parse the data using Jackson and then iterate over the result and convert the keys.

Change your code like this:

public Map<String, Object> jsonToMap(String jsonString) throws IOException
{
    ObjectMapper mapper=new ObjectMapper();
    mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
    Map<String, Object> map = mapper.readValue(jsonString,new TypeReference<Map<String, Object>>(){});
    return convertMap(map);
}

And add these methods:

public String mapKey(String key) {
    return Character.toLowerCase(key.charAt(0)) + key.substring(1);
}

public Map<String, Object> convertMap(Map<String, Object> map) {
    Map<String, Object> result = new HashMap<String, Object>();
    for (Map.Entry<String, Object> entry : map.entrySet()) {
        String key = entry.getKey();
        Object value = entry.getValue();
        result.put(mapKey(key), convertValue(value));
    }
    return result;
}

public convertList(Lst<Object> list) {
    List<Object> result = new ArrayList<Object>();
    for (Object obj : list) {
        result.add(convertValue(obj));
    }
    return result;
}

public Object covertValue(Object obj) {
    if (obj instanceof Map<String, Object>) {
        return convertMap((Map<String, Object>) obj);
    } else if (obj instanceof List<Object>) {
        return convertList((List<Object>) obj);
    } else {
        return obj;
    }
}



回答2:


You always can iterate over the keys of the map and update them. However, if you are only interested in producing a JSON with camel case keys, you could consider the approach described below.

You could have a custom key serializer. It will be used when serializing a Map instance to JSON:

public class CamelCaseKeySerializer extends JsonSerializer<String> {

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException, JsonProcessingException {

        String key = Character.toLowerCase(value.charAt(0)) + value.substring(1);
        gen.writeFieldName(key);
    }
}

Then do as following:

String json = "{\"SomeKey\":\"SomeValue\",\"AnotherKey\":\"another value\",\"InnerJson\":"
            + "{\"TheKey\":\"TheValue\"}}";

SimpleModule simpleModule = new SimpleModule();
simpleModule.addKeySerializer(String.class, new CamelCaseKeySerializer());

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(simpleModule);

Map<String, Object> map = mapper.readValue(json, 
                                          new TypeReference<Map<String, Object>>() {});

String camelCaseJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);

The output will be:

{
  "someKey" : "SomeValue",
  "anotherKey" : "another value",
  "innerJson" : {
    "theKey" : "TheValue"
  }
}

With this approach, the keys of the Map won't be in camel case. But it will give you the desired output.




回答3:


The following will transform json with keys on any "case format" to using camelCased keys:

/**
 * Convert all property keys of the specified JSON to camelCase
 */
public static String toJsonWithCamelCasedKeys(String json) {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new SimpleModule()
      .addKeySerializer(String.class, new JsonSerializer<>() {
          @Override
          public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
              String key = CaseUtil.toCamelCase(value);
              gen.writeFieldName(key);
          }
      })
    );

    try {
        Map<String, Object> jsonMap = objectMapper.readValue(json, new TypeReference<>() {});
        return objectMapper.writeValueAsString(jsonMap);
    } catch (Exception e) {
        throw new JsonException("Error transforming JSON", e);
    }
}

...and a CaseUtil implementation could be something like this:

import java.util.Arrays;
import java.util.stream.Collectors;

public class CaseUtil {

    public static String toCamelCase(String s) {
        if (s == null) {
            return null;
        }
        else if (s.isBlank()) {
            return "";
        }

        return decapitaliseFirstLetter(
          String.join("", Arrays.stream(s.split("[-_\\s]"))
          .map(CaseUtil::capitaliseFirstLetter)
          .collect(Collectors.toList()))
        );
    }

    private static String capitaliseFirstLetter(String s) {
        return (s.length() > 0)
          ? s.substring(0, 1).toUpperCase() + s.substring(1)
          : s;
    }

    private static String decapitaliseFirstLetter(String s) {
        return (s.length() > 0)
          ? s.substring(0, 1).toLowerCase() + s.substring(1)
          : s;
    }

}

A unit test:

    @Test
    void jsonWithMiscCasedPropKeys_shouldConvertKeyToCamelCase() throws Exception {
        String inputJson =
            "{\"kebab-prop\": \"kebab\"," +
            "\"snake_prop\": \"snake\"," +
            "\"PascalProp\": \"pascal\"," +
            "\"camelCasedProp\": \"camel\"}";
        String expectedJson =
          "{\"kebabProp\": \"kebab\"," +
            "\"snakeProp\": \"snake\"," +
            "\"pascalProp\": \"pascal\"," +
            "\"camelCasedProp\": \"camel\"}";
        String actualJson = Json.toJsonWithCamelCasedKeys(inputJson);

        JSONAssert.assertEquals(expectedJson, actualJson, JSONCompareMode.LENIENT);
    }


来源:https://stackoverflow.com/questions/30727417/jackson-json-to-map-and-camelcase-key-name

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!