Java 如何将JSON反序列化为平面的映射式结构?

Java 如何将JSON反序列化为平面的映射式结构?,java,json,jackson,flatten,Java,Json,Jackson,Flatten,请记住,JSON结构之前是未知的,即它是完全任意的,我们只知道它是JSON格式 比如说, 下面是JSON { "Port": { "@alias": "defaultHttp", "Enabled": "true", "Number": "10092", "Protocol": "http", "KeepAliveTimeout": "20000", "ThreadPool": {

请记住,JSON结构之前是未知的,即它是完全任意的,我们只知道它是JSON格式

比如说,

下面是JSON

{
   "Port":
   {
       "@alias": "defaultHttp",
       "Enabled": "true",
       "Number": "10092",
       "Protocol": "http",
       "KeepAliveTimeout": "20000",
       "ThreadPool":
       {
           "@enabled": "false",
           "Max": "150",
           "ThreadPriority": "5"
       },
       "ExtendedProperties":
       {
           "Property":
           [                         
               {
                   "@name": "connectionTimeout",
                   "$": "20000"
               }
           ]
       }
   }
}
应反序列化为类似映射的结构,其键如下(为简洁起见,不包括上述所有键):

我目前正在调查杰克逊,因此我们有:

TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {};
Map<String, String> o = objectMapper.readValue(jsonString, typeRef);
而我需要使用“点表示法”的带展平键的平面贴图,如上图所示


我宁愿自己不去实现这一点,尽管目前我看不到任何其他方式

如果您事先知道该结构,您可以定义一个Java类并使用它将JSON解析为该类的实例:

YourClass obj = gson.fromJson(json, YourClass.class); 
如果不是,那我不知道你想做什么。显然,您不能动态定义类,因此使用点表示法访问解析后的JSON是不可能的

除非你想要像这样的东西:

Map<String, String> parsed = magicParse(json);
parsed["Port.ThreadPool.max"]; // returns 150
Map parsed=magicParse(json);
已分析[“Port.ThreadPool.max”];//返回150
如果是这样的话,那么遍历地图并构建“展平”地图似乎不是什么大问题


还是其他原因?

您可以使用以下示例中的as实现类似的效果:

import com.typesafe.config.*;
import java.util.Map;
public class TypesafeConfigExample {
  public static void main(String[] args) {
    Config cfg = ConfigFactory.parseString(
      "   \"Port\":\n" +
      "   {\n" +
      "       \"@alias\": \"defaultHttp\",\n" +
      "       \"Enabled\": \"true\",\n" +
      "       \"Number\": \"10092\",\n" +
      "       \"Protocol\": \"http\",\n" +
      "       \"KeepAliveTimeout\": \"20000\",\n" +
      "       \"ThreadPool\":\n" +
      "       {\n" +
      "           \"@enabled\": \"false\",\n" +
      "           \"Max\": \"150\",\n" +
      "           \"ThreadPriority\": \"5\"\n" +
      "       },\n" +
      "       \"ExtendedProperties\":\n" +
      "       {\n" +
      "           \"Property\":\n" +
      "           [                         \n" +
      "               {\n" +
      "                   \"@name\": \"connectionTimeout\",\n" +
      "                   \"$\": \"20000\"\n" +
      "               }\n" +
      "           ]\n" +
      "       }\n" +
      "   }\n" +
      "}");

    // each key has a similar form to what you need
    for (Map.Entry<String, ConfigValue> e : cfg.entrySet()) {
      System.out.println(e);
    }
  }
}
import com.typesafe.config.*;
导入java.util.Map;
公共类TypesafeConfigExample{
公共静态void main(字符串[]args){
Config cfg=ConfigFactory.parseString(
“\“端口\”:\n”+
“{\n”+
“\”@alias\:\“defaultHttp\”,\n”+
“\”启用\“:\”正确\“,\n”+
“\'Number\:\'10092\”,\n”+
“协议”:“http\,\n”+
“\'KeepAliveTimeout\”:\'20000\,\n”+
“\“线程池\”:\n”+
“{\n”+
“\“@enabled\”:\“false\”,\n”+
“最大值”:“150\,\n”+
“\”线程优先级\“:\”5\“\n”+
},\n+
“\“ExtendedProperties\”:\n”+
“{\n”+
“\”属性\“:\n”+
“[\n”+
“{\n”+
“\@name\:\“connectionTimeout\”,\n”+
“\“$\”:\“20000\”\n”+
“}\n”+
“]\n”+
“}\n”+
“}\n”+
"}");
//每个键都有一个类似于您所需的形式
对于(Map.Entry e:cfg.entrySet()){
系统输出打印ln(e);
}
}
}

您可以这样做来遍历树,并跟踪计算点符号属性名称的深度:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.junit.Test;

public class FlattenJson {
  String json = "{\n" +
      "   \"Port\":\n" +
      "   {\n" +
      "       \"@alias\": \"defaultHttp\",\n" +
      "       \"Enabled\": \"true\",\n" +
      "       \"Number\": \"10092\",\n" +
      "       \"Protocol\": \"http\",\n" +
      "       \"KeepAliveTimeout\": \"20000\",\n" +
      "       \"ThreadPool\":\n" +
      "       {\n" +
      "           \"@enabled\": \"false\",\n" +
      "           \"Max\": \"150\",\n" +
      "           \"ThreadPriority\": \"5\"\n" +
      "       },\n" +
      "       \"ExtendedProperties\":\n" +
      "       {\n" +
      "           \"Property\":\n" +
      "           [                         \n" +
      "               {\n" +
      "                   \"@name\": \"connectionTimeout\",\n" +
      "                   \"$\": \"20000\"\n" +
      "               }\n" +
      "           ]\n" +
      "       }\n" +
      "   }\n" +
      "}";

  @Test
  public void testCreatingKeyValues() {
    Map<String, String> map = new HashMap<String, String>();
    try {
      addKeys("", new ObjectMapper().readTree(json), map);
    } catch (IOException e) {
      e.printStackTrace();
    }
    System.out.println(map);
  }

  private void addKeys(String currentPath, JsonNode jsonNode, Map<String, String> map) {
    if (jsonNode.isObject()) {
      ObjectNode objectNode = (ObjectNode) jsonNode;
      Iterator<Map.Entry<String, JsonNode>> iter = objectNode.fields();
      String pathPrefix = currentPath.isEmpty() ? "" : currentPath + ".";

      while (iter.hasNext()) {
        Map.Entry<String, JsonNode> entry = iter.next();
        addKeys(pathPrefix + entry.getKey(), entry.getValue(), map);
      }
    } else if (jsonNode.isArray()) {
      ArrayNode arrayNode = (ArrayNode) jsonNode;
      for (int i = 0; i < arrayNode.size(); i++) {
        addKeys(currentPath + "[" + i + "]", arrayNode.get(i), map);
      }
    } else if (jsonNode.isValueNode()) {
      ValueNode valueNode = (ValueNode) jsonNode;
      map.put(currentPath, valueNode.asText());
    }
  }
}
去掉属性名中的
@
$
应该很容易,尽管您可能会在键名中出现冲突,因为您说JSON是任意的

怎么样:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.Gson;

/**
 * NOT FOR CONCURENT USE
*/
@SuppressWarnings("unchecked")
public class JsonParser{

Gson gson=new Gson();
Map<String, String> flatmap = new HashMap<String, String>();

public Map<String, String> parse(String value) {        
    iterableCrawl("", null, (gson.fromJson(value, flatmap.getClass())).entrySet());     
    return flatmap; 
}

private <T> void iterableCrawl(String prefix, String suffix, Iterable<T> iterable) {
    int key = 0;
    for (T t : iterable) {
        if (suffix!=null)
            crawl(t, prefix+(key++)+suffix);
        else
            crawl(((Entry<String, Object>) t).getValue(), prefix+((Entry<String, Object>) t).getKey());
    }
}

private void crawl(Object object, String key) {
    if (object instanceof ArrayList)
        iterableCrawl(key+"[", "]", (ArrayList<Object>)object);
    else if (object instanceof Map)
        iterableCrawl(key+".", null, ((Map<String, Object>)object).entrySet());
    else
        flatmap.put(key, object.toString());
}
}
import java.util.ArrayList;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.Map.Entry;
导入com.google.gson.gson;
/**
*不供同时使用
*/
@抑制警告(“未选中”)
公共类JsonParser{
Gson Gson=新的Gson();
Map flatmap=newhashmap();
公共映射解析(字符串值){
iterableCrawl(“”,null,(gson.fromJson(value,flatmap.getClass()).entrySet());
返回平面图;
}
私有void iterableCrawl(字符串前缀、字符串后缀、Iterable){
int键=0;
for(T:iterable){
if(后缀!=null)
爬网(t,前缀+(键+)+后缀);
其他的
爬网((Entry)t.getValue(),前缀+((Entry)t.getKey());
}
}
私有无效爬网(对象、字符串键){
if(ArrayList的对象实例)
iterableCrawl(键+“[”,“]”,(ArrayList)对象);
else if(映射的对象实例)
iterableCrawl(key+”,null,((Map)对象).entrySet());
其他的
flatmap.put(key,object.toString());
}
}

使用json扁平化器怎么样

顺便说一句,我是这个库的作者

String flattenedJson = JsonFlattener.flatten(yourJson);
Map<String, Object> flattenedJsonMap = JsonFlattener.flattenAsMap(yourJson);

// Result:
{
    "Port.@alias":"defaultHttp",
    "Port.Enabled":"true",
    "Port.Number":"10092",
    "Port.Protocol":"http",
    "Port.KeepAliveTimeout":"20000",
    "Port.ThreadPool.@enabled":"false",
    "Port.ThreadPool.Max":"150",
    "Port.ThreadPool.ThreadPriority":"5",
    "Port.ExtendedProperties.Property[0].@name":"connectionTimeout",
    "Port.ExtendedProperties.Property[0].$":"20000"
}
String flattedJSON=jsonflatter.flatte(yourJson);
Map flattedJSONMAP=jsonflatter.flattesMap(yourJson);
//结果:
{
“端口。@别名”:“defaultHttp”,
“Port.Enabled”:“true”,
“端口号”:“10092”,
“端口协议”:“http”,
“Port.KeepAliveTimeout”:“20000”,
“Port.ThreadPool.@enabled”:“false”,
“Port.ThreadPool.Max”:“150”,
“Port.ThreadPool.ThreadPriority”:“5”,
“Port.ExtendedProperties.Property[0]。@name:“connectionTimeout”,
“Port.ExtendedProperties.Property[0]。$”:“20000”
}
从生成所需的结果。 默认情况下,它将
shouldFlattKeys
属性设置为true并生成平面贴图(无嵌套,值始终为简单类型)。当
shouldFlattKeys=false时
会生成嵌套贴图

ObjectToMapTransformer旨在作为集成流的一部分使用,但以独立的方式使用它是非常好的。您需要使用转换输入的有效负载构建
org.springframework.messaging.Message
transform
方法返回有效负载为Map的
org.springframework.messaging.Message
对象

import org.springframework.integration.transformer.ObjectToMapTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;

Message message = new GenericMessage(value);
 ObjectToMapTransformer transformer = new ObjectToMapTransformer();
        transformer.setShouldFlattenKeys(true);
        Map<String,Object> payload = (Map<String, Object>) transformer
                .transform(message)
                .getPayload();
导入org.springframework.integration.transformer.ObjectToMapTransformer;
导入org.springframework.messaging.Message;
导入org.springframework.messaging.support.GenericMessage;
消息消息=新的GenericMessage(值);
ObjectToMapTransformer transformer=新ObjectToMapTransformer();
transformer.SetShouldKeys(正确);
映射有效负载=(映射)转换器
.transform(消息)
.getPayload();
旁注:仅仅为了使用单个类而将Spring集成添加到类路径中可能有些过分,但您可以检查这个类的实现并自己编写类似的解决方案。嵌套映射是由Jackson(
org.springframework.integration.support.json.JsonObjectMapper#fromJson(payload,map.class)
)生成的,然后映射被递归地转移,将所有集合值展平。

import com.alibaba.fastjson.JSONObject;
导入com.a
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.Gson;

/**
 * NOT FOR CONCURENT USE
*/
@SuppressWarnings("unchecked")
public class JsonParser{

Gson gson=new Gson();
Map<String, String> flatmap = new HashMap<String, String>();

public Map<String, String> parse(String value) {        
    iterableCrawl("", null, (gson.fromJson(value, flatmap.getClass())).entrySet());     
    return flatmap; 
}

private <T> void iterableCrawl(String prefix, String suffix, Iterable<T> iterable) {
    int key = 0;
    for (T t : iterable) {
        if (suffix!=null)
            crawl(t, prefix+(key++)+suffix);
        else
            crawl(((Entry<String, Object>) t).getValue(), prefix+((Entry<String, Object>) t).getKey());
    }
}

private void crawl(Object object, String key) {
    if (object instanceof ArrayList)
        iterableCrawl(key+"[", "]", (ArrayList<Object>)object);
    else if (object instanceof Map)
        iterableCrawl(key+".", null, ((Map<String, Object>)object).entrySet());
    else
        flatmap.put(key, object.toString());
}
}
String flattenedJson = JsonFlattener.flatten(yourJson);
Map<String, Object> flattenedJsonMap = JsonFlattener.flattenAsMap(yourJson);

// Result:
{
    "Port.@alias":"defaultHttp",
    "Port.Enabled":"true",
    "Port.Number":"10092",
    "Port.Protocol":"http",
    "Port.KeepAliveTimeout":"20000",
    "Port.ThreadPool.@enabled":"false",
    "Port.ThreadPool.Max":"150",
    "Port.ThreadPool.ThreadPriority":"5",
    "Port.ExtendedProperties.Property[0].@name":"connectionTimeout",
    "Port.ExtendedProperties.Property[0].$":"20000"
}
import org.springframework.integration.transformer.ObjectToMapTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;

Message message = new GenericMessage(value);
 ObjectToMapTransformer transformer = new ObjectToMapTransformer();
        transformer.setShouldFlattenKeys(true);
        Map<String,Object> payload = (Map<String, Object>) transformer
                .transform(message)
                .getPayload();

    //Json string to Map<String, Object>

    String data = "Your json as string"
    final ObjectMapper mapper = new ObjectMapper();
    final MapType type = mapper.getTypeFactory().constructMapType(
                Map.class, String.class, Object.class);
    final Map<String, Object> map = mapper.readValue(data, type);

    //Using springframework.vault flatten method

    Map<String, String> keyMap = JsonMapFlattener.flattenToStringMap(map);

    //Input

    {"key": {"nested": 1}, "another.key": ["one", "two"] }

    //Output

      key.nested=1
      another.key[0]=one
      another.key[1]=two

    <dependency>
        <groupId>org.springframework.vault</groupId>
        <artifactId>spring-vault-core</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>