I am working on consuming external API in spring boot application. I have written my JSON response that is coming from external API using RestTemplate and exchange() method of HttpEntity.
Below is the response:
String json = """
{
"links": {
"RCDSO - Production Environment Cost": {
"href": "href 1"
},
"RCDSO - Development & UAT Environment Cost": {
"href": "href 2"
},
"RCDSO - Total Cost for Prod - Compugen Managed": {
"href": "href 3"
},
"RCDSO - Virtual Machine Cost": {
"href": "href 4"
},
"RCDSO - Azure File Storage Cost": {
"href": "href 5"
},
"RCDSO - Azure Backup and Site Recovery": {
"href": "href 6"
},
"RCDSO - Azure App Services Cost": {
"href": "href 7"
}
}
}
""";
Map<String, Map<String, String>> links = JsonPath.read(json, "$.links");
links.forEach((key, value) -> {
System.out.println("k = " key);
System.out.print("v = ");
value.forEach((key2, value2) -> {
System.out.println("key = " key2 " : value = " value2);
});
});
In above code, I tried to get values from Map. Now I want to convert into my POJO class.
Below is my Pojo named OlapCustomReportResponse.java:
public class OlapCustomReportResponse {
private String name;
private String href;
}
I extracted key from outer loop and on the basis of key I extracted value from inner loop as below:
Key 1 = RCDSO - Production Environment Cost
Key 2 = href : Value 2 = some url related to key 1
Key 2 = RCDSO - Development & UAT Environment Cost
Key 2 = href : Value 2 = some url related to key 2
Key 3 = RCDSO - Total Cost for Prod - Compugen Managed
Key 2 = href : Value 2 = some url related to key 3
Key 4 = RCDSO - Virtual Machine Cost
Key 2 = href : Value 2 = some url related to key 4
.... and so on
I want my OlapCustomReportResponse.java should look something like below:
[
{
"href" : "some url of key 1",
"name" : "key 1"
},
{
"href" : "some url of key 2",
"name" : "key 2"
},
{
"href" : "some url of key 3",
"name" : "key 3"
},
{
"href" : "some url of key 4",
"name" : "key 4"
}
...... and so on...
]
So my main motive is to map or convert that result to my POJO class. How should I do or what would be the possible approach?
CodePudding user response:
I am actually using com.fasterxml.jackson.databind.ObjectMapper and it is really fast, strong and a good json parser
ObjectMapper objectMapper = new ObjectMapper();
TypeReference<HashMap<String, Map<String, String>>> typeRef = new TypeReference<HashMap<String, Map<String, String>>>() {};
Map<String, Map<String, String>> results = objectMapper.readValue(file, typeRef);
CodePudding user response:
With the few given:
Map<String, Map<String, String>> links = // from somewhere
and (e.g) constructor:
public OlapCustomReportResponse(String name, String href) {
this.name = name;
this.href = href;
}
, we could just (do the transformation with streaming api):
List<OlapCustomReportResponse> result = new ArrayList<>(); // alternatively: Set(?)
links.forEach((key, value) -> {
result.add(new OlapCustomReportResponse(
key, value.get("href")
));
});
Test:
// import static org.assertj.core.api.Assertions.assertThat;
// import static org.junit.jupiter.api.Assertions.*;
...
assertNotNull(result);
assertThat(result).isNotEmpty();
result.forEach(
(ocrr) -> {
assertNotNull(ocrr); // not null
assertThat(ocrr.getName()).isNotBlank(); // according to test data
assertThat(ocrr.getHref()).isNotBlank(); // ...
assertTrue(links.containsKey(ocrr.getName())); // result(x) -> links(x):
assertEquals(links.get(ocrr.getName()).get("href"), ocrr.getHref()); // result(x).getHref() -> links(x).get("href")
}
);
// links(x) <- result(x):
assertEquals(links.size(), result.size());
Alternative approaches:
links.entrySet().stream().collect(...)
(with identic code, "combination"(!?)):List<OlapCustomReportResponse> result = links.entrySet().stream().collect( ArrayList::new, // <- supplier (list, entry) -> { // <- accumulator list.add( new OlapCustomReportResponse( entry.getKey(), entry.getValue().get("href") ) ); }, (first, second) -> { // <- combiner (for more complex use cases) first.addAll(second); } );
- traditional loop...
Assumptions:
- receiving response (format) from external api.
- forwarding of (internal)
result
via default(jackson)/custom http converters. - With
to mimic(/use) "spring defaults" on (e.g.):// import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper om = new ObjectMapper();// or @Autowired from spring context ;) om.writeValue(System.err, result);
prints (unformatted/according to your@ResponseBody List<OlapCustomReportResponse> serveSome(// ...
spring.jackson.*
/context OM settings):[ {"name":"RCDSO - Production Environment Cost","href":"href 1"}, {"name":"RCDSO - Development & UAT Environment Cost","href":"href 2"}, {"name":"RCDSO - Total Cost for Prod - Compugen Managed","href":"href 3"}, {"name":"RCDSO - Virtual Machine Cost","href":"href 4"}, {"name":"RCDSO - Azure File Storage Cost","href":"href 5"}, {"name":"RCDSO - Azure Backup and Site Recovery","href":"href 6"}, {"name":"RCDSO - Azure App Services Cost","href":"href 7"} ]
Problems:
- (Only) when
links
orvalue
(for anyvalue
inlikns.getValues()
) isnull
!