How to serialize Map<String, List<Object>> with FlexJSON - java

I have a object which I want to serialize to JSON. This object is a map with list of a specific objects. This looks similar to it:
Map<String, List<Object>> map = new Map<String, List<Object>>();
I am using FlexJSON. I can work only with flexjson.JSONSerializer. There are my tries:
JSONSerializer jsonSerializer = new JSONSerializer();
// jsonSerializer.include("map");
// jsonSerializer.include("map.myList.object");
jsonSerializer.transform(new MapTransformer(), "map");
jsonSerializer.exclude("*.class");
As you can see I am trying now with Transformer classes but I haven't succeeded. The commented lines will work, as I suppose, if my List<Object> has own name for example myList. But it doesn't haven own name, because it is values of my map.
How can I serialize such object to JSON with FlexJSON?

Quoi is correct, and most likely the answer you want to use. However, just so you can learn more about how it works you could do this:
new JSONSerializer().include("values.values").serialize( myMap );
Maps and Lists are containers and have special expressions for the elements contained within them. When you want to talk about the path of the values of a container you use "values" expression in the path. Map's two special expressions "keys" and "values". Other Collections have "values".
Another option is to use wildcards like so:
new JSONSerializer().include("values.*").serialize( myMap );
You can see wildcards used in Quoi's answer as well to exclude the class property.

Try
String jsonString = new JSONSerializer().exclude("*.class").deepSerialize(map);
deepSerialize method performs a deep serialization of the target instance. It will include all collections, maps, and arrays by default so includes are ignored except if you want to include something being excluded by an annotation.

Related

Is there a way to map a string to a method that returns a different type depending on the string?

I want to map a String to a method that builds a certain object, but not necessarily from the same class for every String. Looking around on here a nice solution was to have a Map<String, ObjectBuilder>, ObjectBuilder<T> being an interface with an abstract method T buildObject().
I then have multiple classes, let's say Object1Builder implements ObjectBuilder<Object1>, Object2Builder implements ObjectBuilder<Object2> and so on.
I can then construct my map like so :
stringToBuilder = new HashMap<String, ObjectBuilder>(){{
put(string1, Object1Builder);
put(string2, Object2Builder);
put(string3, Object3Builder);
}};
And I can then do Object1 myObject1 = stringToBuilder.get(string1).buildObject()
Problem is, I get an error
Raw use of parameterized class 'ObjectBuilder'
in IntelliJ when I instanciate and construct stringToBuilder and I understand it has something to do with not specifying the generic of the interface ObjectBuilder when constructing the map, but I don't see how I could circumvent this. Moreover, I'm not very satisfied with the fact that I'm storing these classes in a map, I wish I could access them through the map without having the whole instance in the map.
You've probably noticed I'm quite new to Java and all this but please be sure I'm trying my best. Thank you in advance :)
What you want will never be possible without explicit casts. The reason is that there is no direct relation between the map keys (strings) and values (ObjectBuilders).
If you can switch from strings to use the T values as map keys, this can be done with a little internal casting.
First, declare your map as Map<Class<?>, ObjectBuilder<?>>. Note the two wild-cards; the compiler cannot help us with enforcing that the keys and the values have the same generic type. That's what we need to do ourselves.
Next, initialize it as necessary. I dislike the anonymous class with initializer you use, so I'll use Map.of:
Map<Class<?>, ObjectBuilder<?>> classToBuilder = Map.of(
Object1.class, Object1Builder,
Object2.class, Object2Builder,
Object3.class, Object3Builder,
);
Finally, we need a method to get the builder:
#SuppressWarnings("unchecked")
private <T> getBuilder(Class<T> type) {
// Omitted: presence check
return (ObjectBuilder<T>) classToBuilder.get(type);
}
This can now be used as follows:
Object1 object1 = getBuilder(Object1.class).buildObject();

TypeToken on map and it's elements

I've got a map of the following structure Map<Identity, Boolean> which is to convert to gson new Gson().toJson(obj); To set up rules for converting Identity objects I use this construction new TypeToken<Identity>(){}.getType(); and this forks fine. But when i try to apply this one new TypeToken<Map<Identity, Boolean>>(){}.getType(); i got this {"Identity#23b5810f":true}. Is there any way to specify TypeToken for mapkey other than changing Identity's toString() method?
You do have Identity as key. What you see is String presentation of this Identity instance in your output.
In you code you should use these keys as Identity objects. It should work.
Maps as JSON arrays is the way it's possible to customize how the keys should be serialized.

converting json to java object giving wrong type of enum

I have a json which is something like following:
[{"type":"chair", "color":"red", "owners":["A","B"]},
{"type":"vase", "shape":"oval", "owners":["B", "C"]}]
As seen, both entries are different. So I need to deserialize this json and instantiate 2 objects Chair and Vase. The owners above should be List of enum in the appropriate object. The json can have many other different entries like that and in any order. So I am doing this:
List<Map<String, Object>> things = objectMapper.readValue(json,
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class));
things is a list of maps and each map will correspond to one thing. I iterate over the list and from each map check 'type' and instantiate the appropriate object.
Eg:
if map.get("type") == "chair" then new Chair(map.get("color"), map.get("owners"));
Now I have an enum OWNERS. So I do this:
List<OWNERS> owners = (ArrayList<OWNERS>) map.get("owners");
I do get the list properly. But when I verify like this:
assertEquals(OWNERS.A, owners.get(0));
I get error: 'expected java.lang.OWNERS("A") but got java.lang.String("A")'
As you can see type of owners is List.
What am I missing? Am I parsing the wrong way?
Try this
assertEquals(OWNERS.A.toString(), owners.get(0));
Also, this line
List<OWNERS> owners = (ArrayList<OWNERS>) map.get("owners");
at runtime works because of type erasure. It will crash if you try to read an element of the list and cast it to OWNERS (because it will be a list of strings in fact).
Check Java generics - type erasure - when and what happens
The problem comes from the Map<String, Object>. Your object mapper can't infer the type of the owners, it takes a guess and assumes it's a String.
One thing you could do is convert the string list to a list of owners.
A better solution would be to use something like jackson-databind and annotate your Chair and Vase classes. Jackson has annotations that let it infer the type of an object from a JSON field (like your type field).
Your code should look something like this:
#JsonTypeName("chair")
#JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="type")
public class Chair {
#JsonCreator
public Chair(#JsonProperty("color") String color,
#JsonProperty("owners") List<OWNERS> owners) { }
}
The JsonTypeInfo annotations tell jackson to use a name of your choice in the type JSON property to indentify your class. The JsonTypeName annotation specifies the name of your class.
If you don't want to bother with annotations you can use jackson's tree model. To load your json content through a Map like interface.
Using Jackson annotations was not an option for me. So I worked with the default that it considers i.e String. I did this:
List owners = (ArrayList) map.get("owners");
And now converted this to my enum by taking the corresponding enum valueOf that String:
OWNERS.valueOf(owners.get(0));

How can I store a set of URL parameters in Java?

Normally I would store URL parameters (GET request parameters) with a HashMap<String,String> but that doesnt account for URLs like test.php?request=id1&request=id2. Is there any data structure implemented in Java that can deal with this (and that I can query a parameter by name)? Alternatively, is there a single class somewhere that I can use (no libraries please)?
You can fake a multimap with something like this:
Map<String, List<String>> multimap = new HashMap<String, List<String>>();
See the 'MultiMap' section on this page for more information:
The Map Interface
If you are talking about using java to write servlet or something, as far as I know, the HttpServletRequest class comes with the parameter as a list, and for each parameter, the value is an array.
HttpServletRequest req=...
Enumeration<String> names=req.getParameterNames(); //
String para=names.getNextElement();//return "request"
String[] values=para.getParameterValues();// Should get["id1","id2"]
Now you certainly can use a list for it, like whiskeyspider suggested.
You can also make a wrapper on it before put into a hashMap,even just to serialize it. then we you need to use it, just unwrap it. But I would suggest use a list all the way, you can always just check the length to know if it is a single parameter or list.

Java analog for PHP's StdClass

I need something like a property bag to throw key value pairs into.
I want to create list of such objects, initialize them in bean and then use the list to render table in JSF template.
I know how to do it, but I want to avoid creating some special class for that case, like OrderLineItem and using List<OrderLineItem>.
I do not want to define new class.
In PHP I could use StdClass.
StdClass is a sparsely documented class in PHP which has no predefined members.
$object = new StdClass;
$object->foo = 'bar';
But, as far as I know, Primefaces <p:dataTable> list item must be an object with getter.
If I want to reference <h:outputText value="#{item.title}" />, my list object should have getTitle() method.
Is there any walkaround in my case or I really need to define special class to make life easier?
Thanks.
When you want a simple key/value table, then the HashMap might be what you are looking for.
Map<String, String> myMap = new HashMap<>();
myMap.put("foo", "bar");
System.out.println(myMap.get("foo")); // outputs "bar"
This example matches Strings to Strings, but you can use HashMaps to map any type to any other type. You can even create a Map<Object, Object> to create a weakly-typed map which maps anything to anything. But for most use-cases you would rather use a more specialized form.
What you need is a Map.
You can store key-value pairs in it pretty easy:
Map<KeyClass, ValueClass> myMap = new HashMap<KeyClass, ValueClass>();
Use the put method to put data in it. If you use simple String values it will be like this:
myMap.put("key", "value");
I don't know if I understood you well. But I think you mean SelectItem or JsfMap.
I would recommend to use an anonymous class:
return new HashMap<String, String>() {
{
this.put("key", "value");
}
};

Categories

Resources