2
{
  "key1": {
    "parameter1": "String1",
    "parameter2": "String2"
  },
  "key2": {
    "parameter1": "String3",
    "parameter2": "String4"
  },
  "key3": {
    "parameter1": "String5",
    "parameter2": "String6"
  }
}

I have the above JSON (/Users/user1/Desktop/responseMap.json) which is basically a Map<String, MockResponse> where MockResponse is the below POJO:

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

Now, I have another POJO - TestCase, and another JSON - testCase.json as below:

public class TestCase {

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

testCase.json

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

What I am able to do is first map testCase.json to TestCase using Jackson, then map responseMap.json to Map<String, MockResponse>, then in my code search for mockResponseKey in the map.

But what I want to do is when I map testCase.json to TestCase using Jackson, I want the value of variable mockResponse to set automatically based on the value of variable mockResponseKey using the first JSON map.

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
Pankaj Vatsa
  • 2,599
  • 5
  • 24
  • 28

3 Answers3

1

Tweaking the getter setter in your Test class and marking the field as private I was able to make it dynamic (Imports are from org.codehaus.jackson package)

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 + "]";
    }
}

and Running below code

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);

    }

output will be

TestCase [responseMapFileLocation=/Users/user1/Desktop/responseMap.json, mockResponseKey=key1, mockResponse=MockResponse [parameter1=String1, parameter2=String2]]
Amit Kumar Lal
  • 5,537
  • 3
  • 19
  • 37
1

You need to write custom deserialiser for TestCase class. In custom deserialiser you can parse basic properties: responseMapFileLocation, mockResponseKey and load mockResponse from other file. To deserialiser MockResponse you can use new ObjectMapper instance. Below code shows how this concept could be implemented:

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);
    }
}

You need to implement only toString method for each POJO class. Above code prints:

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

Both JSON files are in resource folder.

See also:

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
0

What you are asking for is not possible with just Jackson. Jackson is primarily a marshalling/unmarshalling tool, converting JSONs to Objects and vice versa. In other words, the value of the object must be known at the time of unmarshalling.

However you can unmarshal your json as a HashMap using the code:

new JSONObject(map);

search for the MockResponse-as-a-string using the mockResponseKey and then unmarshal that code into a new MockResponse.