Create nested objects without creating class in Java - java

I want to create the following object for the response but I don't want to create the class for this. Is there any way I can achieve this using map or other util classes?
"conferenceData": {
"createRequest": {
"conferenceSolutionKey": {
"type": "hangoutsMeet"
},
"requestId": "RANDOM_STRING2"
}
}

I think below is the solution you are looking for...
Map<String, Object> conferenceData = new HashMap<>();
Map<String, Object> createRequest = new HashMap<>();
Map<String, Object> keyAndRequestId= new HashMap<>();
Map<String, String> type = new HashMap<>();
type.put("type", "hangoutsMeet");
keyAndRequestId.put("conferenceSolutionKey", type);
keyAndRequestId.put("requestId", "RANDOM_STRING2");
createRequest.put("createRequest", keyAndRequestId);
conferenceData.put("conferenceData", createRequest);

Try to use :
Map<String,Object> result = new ObjectMapper().readValue(JSON_SOURCE, HashMap.class);
Or if you are using org.json, JSONObject has a method toMap(). You can easily do :
Map<String, Object> myMap = myJsonObject.toMap();

Related

Guava getting one map for differences

I'm using guava to compare two JSON files together and have done the following:
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> type =
new TypeReference<HashMap<String, Object>>() {};
Map<String, Object> leftMap = mapper.readValue(leftJson, type);
Map<String, Object> rightMap = mapper.readValue(rightJson, type);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
System.out.println(difference.entriesDiffering());
Output
package=([{Name=Sarah}], [{Name=Conor}])
Expected output
package=([{Name=Conor}])
Does anyone know how to manipulate the output to just show one side?
I assume that you want to end up with another Map<String,Object>, but taking the value of keys with differing values from the right (or maybe the left, you don't say).
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Map<String, Object> left = Map.of("name", "sarah");
Map<String, Object> right = Map.of("name", "connor");
MapDifference<String, Object> result = Maps.difference(left, right);
Map<String,Object> f = result.entriesDiffering().entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().rightValue()));
System.out.println(f);
}
}
MapDifference#entriesDiffering() returns Map<K,​MapDifference.ValueDifference<V>>, so please read ValueDifference and make use of its API.
Here's a sample MRE:
#Test
public void shouldShowDifferences() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> type =
new TypeReference<HashMap<String, Object>>() {};
String leftJson = "{\"package\": [{\"Name\": \"Sarah\"}]}";
String rightJson = "{\"package\": [{\"Name\": \"Connor\"}]}";
Map<String, Object> leftMap = mapper.readValue(leftJson, type);
Map<String, Object> rightMap = mapper.readValue(rightJson, type);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
System.out.println(difference.entriesDiffering());
// {package=([{Name=Sarah}], [{Name=Connor}])}
difference.entriesDiffering().forEach(
(key, valueDifference) -> System.out.printf(
"key: '%s'; values: left: '%s', right: '%s'",
key, valueDifference.leftValue(), valueDifference.rightValue()));
// key: 'package'; values: left: '[{Name=Sarah}]', right: '[{Name=Connor}]'
}

Create Event in AEM 6.4

How can I create an programatically Event for UnitTests in AEM 6.4 after EventPropertiesMap has been removed?
List<EventPropertiesMap> fakeModifications = new ArrayList<>();
fakeModifications.add(PageModification.deleted(pagePath,
StringUtils.EMPTY).getEventProperties());
Map eventProps = new HashMap();
eventProps.put("modifications", fakeModifications);
return new Event("com/day/cq/wcm/core/page", eventProps);
I came up with this solution hoping to share the pain of an upgrade with others :-)
If you got a better solution I'm more than welcome!
List<Map<String, ?>> fakesList = new ArrayList<Map<String, ?>>();
Map<String, ?> fakeModifications = PageModification.deleted(pagePath, StringUtils.EMPTY).getEventProperties();
fakesList.add(fakeModifications);
Map<String, List<Map<String, ?>>> eventProps = new HashMap<String, List<Map<String, ?>>>();
eventProps.put("modifications", fakesList);
return new Event("com/day/cq/wcm/core/page", eventProps);

Format List<Map<String,String>> using jackson

I want to map an object to json to look like this:
{"MyClass" :
[
{"key" : "value"},
{"key" : "value"}
]}
However my code is giving me:
{"MyClass" : {
"list" : {
"key" : "value",
"key" : "value"
}
And my code is like this:
public class MyClass {
private List<Map<String,String>> list;
//getters & setters......
}
And:
Map<String, String> map1 = new HashMap<String,String>();
map1.put("key", "value");
Map<String,String> map2 = new HashMap<String,String>();
map2.put("key","value");
List<Map<String,String> list = new ArrayList<Map<String,String>();
list.add(map1);
list.add(map2);
And I am using ObjectMapper to map the values. What can I do to get the layout I want?
using your code
class MyClass {
#JsonProperty("MyClass")
public List<Map<String,String>> list;
public static void main(String[] args) throws JsonProcessingException {
Map<String, String> map1 = new HashMap<String,String>();
map1.put("key", "value");
Map<String,String> map2 = new HashMap<String,String>();
map2.put("key","value");
List<Map<String,String>> list = new ArrayList<Map<String,String>>();
list.add(map1);
list.add(map2);
MyClass d = new MyClass();
d.list = list;
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(d);
System.out.println(json);
}
}
output
{"MyClass":[{"key":"value"},{"key":"value"}]}
I used #JsonProperty to change the name but you can also change the name of the var from list to whatever
Note: this is just draft implementation... don't use public class vars, and such...

Parse JSON tag name and value to map using Retrofit

I need to parse such kind of JSON:
{
"commodities": {
"39": "GOLD",
"41": "SILVER",
"42": "PLATINUM-APR16",
"85": "SUGAR (11) ",
"108": "WHEAT",
"116": "OIL-MAR16 (WTI CRUDE)",
"130": "CORN ",
"158": "COFFEE ",
"180": "ORANGE S.A.",
"282": "GOLD/JPY",
"304": "GOLD/EUR",
"332": "GOLD/TRY",
"468": "CRB INDEX",
"508": "COPPER",
...and a LOT more...
},
"currencies": {
"2": "USD/JPY",
"35": "AUD/USD",
"38": "USD/ILS",
...and a LOT more...
},
How is it possible to save this JSON to Map? So I could use it like this:
String value = mapCommodities.get(key);
String value = mapCommodities.get(39) //value equals "GOLD"
The problem is I don't know how to parse this index tag from JSON as integer value. I think it's needed to write custom Deserealizer but not really have an idea how.
create a custom deserializer
public class CustomDeserializer implements JsonDeserializer<List<Map<Integer, String>>>{
#Override
public List<Map<Integer, String>> deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<Map<Integer, String>> randomList = new ArrayList<>();
JsonObject parentJsonObject = element.getAsJsonObject();
Map<Integer, String> childMap;
for(Map.Entry<String, JsonElement> entry : parentJsonObject.entrySet()){
childMap = new HashMap<>();
for(Map.Entry<String, JsonElement> entry1 : entry.getValue().getAsJsonObject().entrySet()){
childMap.put(Integer.parseInt(entry1.getKey()), entry1.getValue().toString());
}
randomList.add(childMap);
}
return randomList;
}
}
use it by
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(new TypeToken<ArrayList<Map<Integer, String>>>() {}.getType(), new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
List<Map<Integer, String>> randomList = gson.fromJson(String.valueOf(object), new TypeToken<ArrayList<Map<Integer, String>>>() {}.getType());
you can use it by
randomList.get(index).get(39);
If you want the it Map<Map<Integer, String>>, that can also be done. Will update that also. But I would't recomment that for very large data set. HashMaps will consume a considerable amount of memory
EDIT:
you can do it this way also
public class CityListDeserializer implements JsonDeserializer<Map<String, Map<Integer, String>>>{
#Override
public Map<String, Map<Integer, String>> deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Map<String, Map<Integer, String>> randomList = new HashMap<>();
JsonObject parentJsonObject = element.getAsJsonObject();
Map<Integer, String> childMap;
for(Map.Entry<String, JsonElement> entry : parentJsonObject.entrySet()){
childMap = new HashMap<>();
for(Map.Entry<String, JsonElement> entry1 : entry.getValue().getAsJsonObject().entrySet()){
childMap.put(Integer.parseInt(entry1.getKey()), entry1.getValue().toString());
}
randomList.put(entry.getKey(), childMap);
}
return randomList;
}
}
use it
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(new TypeToken<Map<String, Map<Integer, String>>>() {}.getType(), new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
Map<String, Map<Integer, String>> randomList = gson.fromJson(String.valueOf(object), new TypeToken<Map<String, Map<Integer, String>>>() {}.getType());
access the value by
randomList.get("commodities").get(39);
this will return you GOLD
All this was for normal json parsing. Not sure but I guess just giving the typetoken like I gave will make it work for Retrofit also
This is what you can do :)
First convert the response to JSONARRAY using
JSONArray jsonArray = new JSONArray("your string");
Then you can iterate or because you know the structre of the respobnse you can simply access it like :)
JSON commodityJSON = jsonArray.getJSONObject(0);
JSON currencies = jsonArray.getJSONObject(1);
Once you get the JSON objects access it using
commodityJSON.getString("39");
commodityJSON.getString("41");
EDIT
As per your comment :) You can do something like this i believe :)
for (int i = 0; i < jsonArray.length(); ++i) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Iterator<String> objectKeys = jsonObject.keys();
for( String s : yourKeys){
System.out.println(jsonObject.getString(s));
}
}
Will it help buddy :) Happy coding buddy :)

Creating objects with Guava from property files

In our applications we are using property files very much. Since a few months I have started to learn Guava and I liked it a lot actually.
What is the best way to create a Map<String, Datasource> ?
The property file format is not strict. It can be changed if It can be expressed better with another format?
Sample property file:
datasource1.url=jdbc:mysql://192.168.11.46/db1
datasource1.password=password
datasource1.user=root
datasource2.url=jdbc:mysql://192.168.11.45/db2
datasource2.password=password
datasource2.user=root
The easiest thing is probably to use JSON rather than a properties file for this:
{
"datasources": [
{
"name": "datasource1",
"url": "jdbc:mysql://192.168.11.46/db1",
"user": "root",
"password": "password"
},
{
"name": "datasource2",
"url": "jdbc:mysql://192.168.11.46/db2",
"user": "root",
"password": "password"
}
]
}
Then you can just use a library such as Gson to convert that into objects:
public class DataSources {
private List<DataSourceInfo> dataSources;
public Map<String, DataSource> getDataSources() {
// create the map
}
}
public class DataSourceInfo {
private String name;
private String url;
private String user;
private String password;
// constructor, getters
}
Then to get the map:
Gson gson = new Gson();
Map<String, DataSource> dataSources = gson.fromJson(/* file or stream here */,
DataSources.class).getDataSources();
Properties class is a subclass of HashTable, which in turn implements Map.
You load it as usual with:
Properties properties = new Properties();
try {
properties.load(new FileInputStream("filename.properties"));
} catch (IOException e) {
}
edit: Ok so you want to transform it to Map<String, Datasource> ;)
//First convert properties to Map<String, String>
Map<String, String> m = Maps.fromProperties(properties);
//Sort them so that password < url < user for each datasource and dataSource1.* < dataSource2.*. In your case default string ordering is ok so we can take a normal treemap
Map<String, String> sorted = Maps.newTreeMap();
sorted.putAll(m);
//Create Multimap<String, List<String>> mapping datasourcename->[password,url, user ]
Function<Map.Entry<String, String>, String> propToList = new Function<String, Integer>() {
#Override
public String apply(Map.Entry<String, String> entry) {
return entry.getKey().split("\\.")[0];
}
};
Multimap<Integer, String> nameToParamMap = Multimaps.index(m.entrySet(), propToList);
//Convert it to map
Map<String, Collection<String>> mm = nameToParamMap.asMap();
//Transform it to Map<String, Datasource>
Map<String, Datasource> mSD = Maps.transformEntries(mm, new EntryTransformer<String, Collection<String>, DataSource>() {
public DataSource transformEntry(String key, Collection<String> value) {
// Create your datasource. You know by now that Collection<String> is actually a list so you can assume elements are in order: [password, url, user]
return new Datasource(.....)
}
};
//Copy transformed map so it's no longer a view
Map<String, Datasource> finalMap = Maps.newHashMap(mSD);
There's probably an easier way, but this should work :)
Still you're better off with json or xml. You can also load properties of different datasources from different files.
edit2: with less guava, more java:
//Sort them so that password < url < user for each datasource and dataSource1.* < dataSource2.*. In your case default string ordering is ok so we can take a normal SortedSet
SortedSet <String> sorted = new SortedSet<String>();
sorted.putAll(m.keySet);
//Divide keys into lists of 3
Iterable<List<String>> keyLists = Iterables.partition(sorted.keySet(), 3);
Map<String, Datasource> m = new HashMap<String, Datasource>();
for (keyList : keyLists) {
//Contains datasourcex.password, datasroucex.url, datasourcex.user
String[] params = keyList.toArray(new String[keyList.size()]);
String password = properties.get(params[0]);
String url = properties.get(params[1]);
String user = properties.get(params[2]);
m.put(params[0].split("\\.")[0], new DataSource(....)
}
If the file that you are using for configuration is not strict, you could use an XML file to store the defintion.
Example definition:
<resources>
<configuration>
<datasrouce>
<connection name="" url="" password="" user=""/>
<connection name="" url="" password="" user=""/>
</datasource>
</configuration>
</resources>
The using a Connection manager class you could just read the XML to obtain connection info and create an instance of connections and mange them.

Categories