Json and Guava Multimap - jackson

I would like to create a multimap, convert it to JSON and back again. The problem here is, that single values still shown as collection/array.
Here is what I have
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new GuavaModule());
Multimap<String, String> map = ArrayListMultimap.create();
map.put("Cheesecake", "mummy");
map.put("Cookie", "PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43");
map.put("Cookie", "yummy_cookie=choco; tasty_cookie=strawberry");
System.out.println(map);
System.out.println("---");
String json = objectMapper.writeValueAsString(map);
System.out.println("JSON:");
System.out.println(json);
System.out.println("---");
JsonNode node = objectMapper.readTree(json);
Multimap<String, String> multimap = objectMapper.readValue(
objectMapper.treeAsTokens(node),
objectMapper.getTypeFactory().constructMapLikeType(
Multimap.class, String.class, String.class));
System.out.println(multimap);
Output:
{Cookie=[PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43, yummy_cookie=choco; tasty_cookie=strawberry], Cheesecake=[mummy]}
---
JSON:
{"Cookie":["PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43","yummy_cookie=choco; tasty_cookie=strawberry"],"Cheesecake":["mummy"]}
---
{Cookie=[PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43, yummy_cookie=choco; tasty_cookie=strawberry], Cheesecake=[mummy]}
I would like to have sth like:
JSON:
{"Cookie":["PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43","yummy_cookie=choco; tasty_cookie=strawberry"],"Cheesecake":"mummy"}
//or even better
JSON:
{"Cookie":"PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43","Cookie":"yummy_cookie=choco; tasty_cookie=strawberry","Cheesecake":"mummy"}
So "mummy" is a string value instead inside json array.
Any idea how to archive this?

You could use Multimpap#asMap() view and serialize it with SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED to achieve the first out of your desired formats. Note that you'd need DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY to deserialize map-like object with this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new GuavaModule());
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
objectMapper.enable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
Multimap<String, String> map = ArrayListMultimap.create();
map.put("Cheesecake", "mummy");
map.put("Cookie", "PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43");
map.put("Cookie", "yummy_cookie=choco; tasty_cookie=strawberry");
System.out.println(map);
System.out.println("---");
String json = objectMapper.writeValueAsString(map.asMap());
System.out.println("JSON:");
System.out.println(json);
System.out.println("---");
JsonNode node = objectMapper.readTree(json);
Multimap<String, String> multimap = objectMapper.readValue(
objectMapper.treeAsTokens(node),
objectMapper.getTypeFactory().constructMapLikeType(
Multimap.class, String.class, String.class));
System.out.println(multimap);
Output:
{Cookie=[PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43, yummy_cookie=choco; tasty_cookie=strawberry], Cheesecake=[mummy]}
---
JSON:
{"Cookie":["PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43","yummy_cookie=choco; tasty_cookie=strawberry"],"Cheesecake":"mummy"}
---
{Cookie=[PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43, yummy_cookie=choco; tasty_cookie=strawberry], Cheesecake=[mummy]}
If you want to serialize and deserialize second desired format, you need to write custom Jackson serializer / deserializer.

Related

How to alternate and serialize entries from 2 Lists using JAXB

I'm using Apache CXF with JAXB and I need to alternate 2 lists in SOAP response. Lets say I have a BankDto class:
#XmlAccessorType(XmlAccessType.FIELD)
class BankDto
{
#XmlElement(nillable = true)
String name;
#XmlElement(nillable = true)
List<String> employeeName;
#XmlElement(nillable = true)
List<String> employeeRank;
}
Which serializes into following data in SOAP response:
...
<ns4:employeeName>Alex</ns4:employeeName>
<ns4:employeeName>Bob</ns4:employeeName>
<ns4:employeeName>Sam</ns4:employeeName>
<ns4:employeeRank>A</ns4:employeeRank>
<ns4:employeeRank>B</ns4:employeeRank>
<ns4:employeeRank>A</ns4:employeeRank>
...
Is there a way to alternate employeeName and employeeRank to have similar output:
...
<ns4:employeeName>Alex</ns4:employeeName>
<ns4:employeeRank>A</ns4:employeeRank>
<ns4:employeeName>Bob</ns4:employeeName>
<ns4:employeeRank>B</ns4:employeeRank>
<ns4:employeeName>Sam</ns4:employeeName>
<ns4:employeeRank>A</ns4:employeeRank>
...
I read about interceptors in CXF and it looks like what I need, but I just want to check if there is a better approach.

How to assertion automation selenium to compare json only on key without value

Wants to compare that both 2 endpoint have same keys even the values are different.
Response on endpoint A
{"name":"Anna", "age":20}
Response on endpoint B
{"name":"Anna", "age":null}
For now I tried using objectmapper like this, it can't
ObjectMapper mapper = new ObjectMapper();
ResponseApi<AResponse> aResponse = aController.getA();
ResponseApi<BResponse> bResponse = bController.getB();
String aReadResponse = String.valueOf(mapper.readTree(String.valueOf(aResponse)));
String bReadResponse = String.valueOf(mapper.readTree(String.valueOf(bResponse)));
assertEquals(mapper.readTree(aReadResponse), mapper.readTree(bReadResponse));
Thanks in advance

List of array object iteration in java 8

I am setting the type for sql query result set as List in java. I am trying to convert it into
a dto.
When I see the List<Object[]> structure from query. It shows
resultList-ArrayList<E>
[0....9999]
[0..99]
[0]=Object[3]
[0]="jjj"
[1]="8787"
[2]="7686"
So is this expected. How can I access the object values here(jjj,8787...) by setting it to dto.
I tried something like this
List<Dto> dtoList = resultList.stream().map(obj->{
Dto dt = new Dto()
dt.setName(obj[0]);
).collect(Collectors.toList())
This is not correct as I am not able to access the object
Should I do another level of iteration in order to reach that object or is my generic type for result set is right
Thanks
Try this:
Object[] inner = new Object[]{"jjj", "8787", "7686"};
Object[] outer = new Object[]{inner};
List<Object[]> resultList = new ArrayList<>();
resultList.add(outer);
List<Dto> dtos;
dtos = resultList.stream()
.flatMap((Object[] objArr) -> {
Object[] subArr = (Object[]) objArr[0];
return Arrays.asList(subArr).stream()
.map(obj -> obj.toString());
})
.map(name -> {
Dto dto = new Dto();
dto.setName(name);
return dto;
})
.collect(Collectors.toList());

how to use serialization package

I want to convert my class to a Map so I'm using Serialization package. From the example it looks simple:
var address = new Address();
address.street = 'N 34th';
address.city = 'Seattle';
var serialization = new Serialization()
..addRuleFor(Address);
Map output = serialization.write(address);
I expect to see an output like {'street' : 'N 34th', 'city' : 'Seattle'} but instead it just output something I-don't-know-what-that-is
{"roots":[{"__Ref":true,"rule":3,"object":0}],"data":[[],[],[],[["Seattle","N 34th"]]],"rules":"{\"roots\":[{\"__Ref\":true,\"rule\":1,\"object\":0}],\"data\":[[],[[{\"__Ref\":true,\"rule\":4,\"object\":0},{\"__Ref\":true,\"rule\":3,\"object\":0},{\"__Ref\":true,\"rule\":5,\"object\":0},{\"__Ref\":true,\"rule\":6,\"object\":0}]],[[],[],[\"city\",\"street\"]],[[]],[[]],[[]],[[{\"__Ref\":true,\"rule\":2,\"object\":0},{\"__Ref\":true,\"rule\":2,\"object\":1},\"\",{\"__Ref\":true,\"rule\":2,\"object\":2},{\"__Ref\":true,\"rule\":7,\"object\":0}]],[\"Address\"]],\"rules\":null}"}
Serialization is not supposed to create human-readable output. Maybe JSON output is more what you look for:
import dart:convert;
{
var address = new Address();
..address.street = 'N 34th';
..address.city = 'Seattle';
var encoded = JSON.encode(address, mirrorJson);
}
Map mirrorJson(o) {
Map map = new Map();
InstanceMirror im = reflect(o);
ClassMirror cm = im.type;
var decls = cm.declarations.values.where((dm) => dm is VariableMirror);
decls.forEach((dm) {
var key = MirrorSystem.getName(dm.simpleName);
var val = im.getField(dm.simpleName).reflectee;
map[key] = val;
});
return map;
}
The new Address() creates a full prototype object which is what you are seeing. That being said, they could have done something to avoid part of those, but if you want to restore the object just the way it is, that's necessary.
To see the full content of an object you use the for() instruction in this way:
for(obj in idx) alert(obj[idx]);
You'll see that you get loads of data this way. Without the new Address() it would probably not be that bad.
Serialization won't help you here...
You might give a try to JsonObject library, and maybe go through this in depth explanation how to do what you are trying to do using mirrors.

Neo4j - How to formulate this query using executeCypher using params

I have a query like this
start n = node:node_auto_index('ids:"123", "456" ... ') return n
Here 123, 456 is a list of keys as a single param {list}. Now when I try to write this in Java
String q = " START n=node:node_auto_index('key:{ids}') return n "
Map<String, Object> map = new HashMap<String, Object>();
map.put("ids", keyList); // keyList is a list of strings
But somehow calling graphstoreclient.executeCypher(q, map) fails with parse error, can you point me to any documentation / correct syntax on this.
PS - This query works fine on console.
Since you're supplying a lucene query string, parameterize the entire string:
String q = " START n=node:node_auto_index({ids}) return n "
Map<String, Object> map = new HashMap<String, Object>();
map.put("ids", keyList);
keyList should now look like ids:"123", "456" ...