【问题标题】:Map a JSON field (to a value) based on another field (which is a key) using Jackson使用 Jackson 基于另一个字段(这是一个键)映射一个 JSON 字段(到一个值)
【发布时间】:2019-05-24 17:56:27
【问题描述】:
{
  "key1": {
    "parameter1": "String1",
    "parameter2": "String2"
  },
  "key2": {
    "parameter1": "String3",
    "parameter2": "String4"
  },
  "key3": {
    "parameter1": "String5",
    "parameter2": "String6"
  }
}

我有上面的JSON (/Users/user1/Desktop/responseMap.json),它基本上是一个Map<String, MockResponse>,其中MockResponse 是下面的POJO

public class MockResponse {
    public String parameter1;
    public String parameter2;
} 

现在,我有另一个POJO - TestCase 和另一个JSON - testCase.json,如下所示:

public class TestCase {

    public String responseMapFileLocation;
    public String mockResponseKey;
    public MockResponse mockResponse;
}

testCase.json

{
  "responseMapFileLocation": "/Users/user1/Desktop/responseMap.json",
  "mockResponseKey": "key1",
  "mockResponse": null
}

我能做的是首先使用JacksontestCase.json 映射到TestCase,然后将responseMap.json 映射到Map<String, MockResponse>,然后在我的代码中搜索地图中的mockResponseKey

但是我想做的是,当我使用JacksontestCase.json 映射到TestCase 时,我希望变量mockResponse 的值根据变量mockResponseKey 的值使用第一个@ 自动设置987654344@地图。

【问题讨论】:

  • 以上json是Map类型,查看json如何映射到map。
  • 如果可以选择添加库,ModelMapper 值得一看。
  • @Pankaj 我已经发布了一个答案看看让我知道它是否适合你
  • 你解决了这个问题吗?以下答案有帮助吗?

标签: java jackson deserialization json-deserialization objectmapper


【解决方案1】:

您需要为TestCase 类编写自定义反序列化器。在自定义反序列化器中,您可以解析基本属性:responseMapFileLocationmockResponseKey 并从其他文件加载mockResponse。要反序列化 MockResponse,您可以使用新的 ObjectMapper 实例。下面的代码展示了如何实现这个概念:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.MapType;

import java.io.File;
import java.io.IOException;
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();

        System.out.println(mapper.readValue(jsonFile, TestCase.class));
    }
}

class MockResponse {
    public String parameter1;
    public String parameter2;
}

@JsonDeserialize(using = TestCaseFromExternalFileDeserializer.class)
class TestCase {

    public String responseMapFileLocation;
    public String mockResponseKey;
    public MockResponse mockResponse;
}

class TestCaseFromExternalFileDeserializer extends JsonDeserializer<TestCase> {

    private final ObjectMapper mapper;
    private final MapType mapType;

    public TestCaseFromExternalFileDeserializer() {
        mapper = new ObjectMapper();
        mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, MockResponse.class);
    }

    @Override
    public TestCase deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        TreeNode treeNode = p.readValueAsTree();

        TestCase testCase = new TestCase();
        testCase.responseMapFileLocation = ((JsonNode) treeNode.get("responseMapFileLocation")).asText();
        testCase.mockResponseKey = ((JsonNode) treeNode.get("mockResponseKey")).asText();
        parseMockResponse(testCase);

        return testCase;
    }

    private void parseMockResponse(TestCase testCase) throws IOException {
        Map<String, MockResponse> map = mapper.readValue(new File(testCase.responseMapFileLocation), mapType);

        testCase.mockResponse = map.get(testCase.mockResponseKey);
    }
}

您只需为每个POJO 类实现toString 方法。以上代码打印:

TestCase{responseMapFileLocation='./resource/responseMap.json', mockResponseKey='key1', mockResponse=MockResponse{parameter1='String1', parameter2='String2'}}

JSON 两个文件都在 resource 文件夹中。

另见:

【讨论】:

    【解决方案2】:

    在您的 Test 类中调整 getter setter 并将该字段标记为私有我能够使其动态化(导入来自 org.codehaus.jackson 包)

    class TestCase {
    
        private String responseMapFileLocation;
    
        private String mockResponseKey;
    
        @JsonIgnore
        private MockResponse mockResponse; //else value will be override in json value
    
        public String getResponseMapFileLocation() {
            return responseMapFileLocation;
        }
        public void setResponseMapFileLocation(String responseMapFileLocation) {
            this.responseMapFileLocation = responseMapFileLocation;
        }
        public String getMockResponseKey() {
            return mockResponseKey;
        }
        public void setMockResponseKey(String mockResponseKey1) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            Map<String, MockResponse> map = mapper.readValue(new File("C:\\Users\\Json1.json"), TypeFactory.mapType(HashMap.class, String.class, MockResponse.class));
            this.mockResponse = map.get(mockResponseKey1);
            this.mockResponseKey = mockResponseKey1;
        }
        public MockResponse getMockResponse() {
            return mockResponse;
        }
    
        @Override
        public String toString() {
            return "TestCase [responseMapFileLocation=" + responseMapFileLocation + ", mockResponseKey=" + mockResponseKey
                    + ", mockResponse=" + mockResponse + "]";
        }
    }
    
    
    class MockResponse {
        public String parameter1;
        public String parameter2;
        @Override
        public String toString() {
            return "MockResponse [parameter1=" + parameter1 + ", parameter2=" + parameter2 + "]";
        }
    }
    

    并在代码下方运行

    public static void main(String[] args) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            TestCase testCase = mapper.readValue(new File("C:\\UsersJson2.json"), TestCase.class);
            System.out.println(testCase);
    
        }
    

    输出将是

    TestCase [responseMapFileLocation=/Users/user1/Desktop/responseMap.json, mockResponseKey=key1, mockResponse=MockResponse [parameter1=String1, parameter2=String2]]
    

    【讨论】:

      【解决方案3】:

      您所要求的仅靠杰克逊是不可能的。 Jackson 主要是一个编组/解组工具,将 JSON 转换为对象,反之亦然。换句话说,对象的值在解组时必须是已知的。

      但是,您可以使用以下代码将 json 解组为 HashMap:

      new JSONObject(map);
      

      使用 mockResponseKey 搜索 MockResponse-as-a-string,然后将该代码解组为新的 MockResponse。

      【讨论】:

        猜你喜欢
        • 2020-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-12
        • 1970-01-01
        • 2010-11-13
        • 1970-01-01
        相关资源
        最近更新 更多