Flattening an object graph to a map - java

I'm trying to flatten an object graph completely to a map.
Complex objects should also be flattened to the top level using "namespaces". So if the object A contains an int i, a string pid and another object B that contains a string id, the resulting Map would look like {i=1, pid="test", B.id="test1"}.
I also want to be able to reconstruct the original object from a given map.
I've searched around for libraries that do this. But I'm not quite getting what I'm looking for. I see stuff that maintains the hierarchy but nothing that completely flattens the structure.
I do see something in Spring Integration that looks like what I want to do:
http://static.springsource.org/spring-integration/api/org/springframework/integration/transformer/ObjectToMapTransformer.html#ObjectToMapTransformer%28%29
But I can't get it to work.
Any help would be appreciated.
Thanks.

The Apache BeanUtils library has a describe() method that does something similar to what I was looking for.
Another possible solution would be via the Jackson JSON library, since JSON objects are essentially key-value pairs.
Related discussions: How to convert a Java object (bean) to key-value pairs (and vice versa)?

Have you considered using Protobufs?

The json-flattener library solves exactly your problem

Related

Map from JSON to java object with different structure

I have a JSON string representing an object, and I want to put its information into a Java object B with a different structure. Currently the solution I am taking is creating a Java Object A with a structure identical to the JSON object, made the conversion from JSON to A using Jackson and later, made the mapping from A to B using Dozer with XML mappings. Is there anyway to avoid having the A objects?
Making it short, currently I have this:
JSON--Jackson-->A--Dozer(XML mappings)-->B
and I would like to achieve this
JSON--???-->B
You may know this already, but Jackson can use loosely structure types like Map, or JsonNode as target, so you can do, say:
JsonNode root = mapper.readTree(jsonSource);
Map<String,Object> asMap = mapper.readValue(jsonSource, Map.class);
and then construct your B. Jackson has only limited amount of structural conversions (simple unwrapping), by design, although there is extensive set of scalar conversions (non-structural conversions), so if you do need structural changes it may make sense to use a library that is focused on structural changes.

Flexjson unable to deserialize LinkedHashMap

I am deserialising a json object as below
{
"b":"value1",
"a":"value2",
"d":"value3",
"c":"value4",
"f":"value5",
"e":"value6"
}
But i am getting ClassCastException as below
java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.LinkedHashMap
My deserialisation code is
LinkedHashMap<String, String> map = new JSONDeserializer<LinkedHashMap<String, String>>().deserialize(JSONstring);
But when i use HashMap instead of LinkedHashMap it works but output gets sorted as below (Its not original order).
{
a=value2,
b=value1,
c=value4,
d=value3,
e=value6,
f=value5
}
I want to get the output in original order.
I found this related link
Flex JSON unable to properly serialize/deserialize LinkedHashMap
but didn't get how to use ObjectFactory.
I would appreciate any help!
Thanks in advance!
(Disclaimer: I just downloaded flexjson and debugged through its source code, so my answer might be slightly incomplete.)
In short:
You generally cannot get the entries in original order using flexjson.
Even writing a custom ObjectFactory will not work.
This is most likely intended and correct.
In detail:
First, the use of generics in new JSONDeserializer<LinkedHashMap<String,String>>() only affects the compilable code, flexjson cannot use this information to actually return a LinkedHashMap<String,String> (this is because the compiler removes the generic and the implementing class has no information of this generic type at runtime).
So, looking deeper into what happens during deserialization, it seems that during parsing the input string, the data is automatically converted to the correct type (string, date, number, list, etc.). This is done using some kind of autodetection of the required data type, because JSON does not provide type information in its data, so flexjson has a build-in list to support data types. It can also use custom mappings to assign values to object properties when proper class information is given (on serialization, flexjson adds a field class to the data to store this type information; or you can manually set this, see documentation).
But the main point is that - according to http://json.org -
An object is an unordered set of name/value pairs.
flexjson internally uses an (unordered) map to store the temporary object keys and values. Even if you tell flexjson to return the data as a LinkedHashMap the data is yet put into a HashMap before it will be converted to a LinkedHashMap, so the original order is not available at that point. (This might be fixed by replacing the map creation in flexjson.JSONTokener, line 442 with a LinkedHashMap but I didn't try that myself.)
Conclusion:
It looks like this behaviour even cannot be changed by providing a custom ObjectFactory, so as far as I understand the code, you cannot retain the original field order. (May I ask why this is important for your project?)
So, if anybody finds a solution anyway, don't hesitate to correct me.

Converting only the first level of object tree using Jackson ObjectMapper

Is it possible to make ObjectMapper convert only the actual object without converting the rest of the object tree recursively ?
So that :
Map<String,Object> props = new ObjectMapper().convertValue(obj, Map.class);
results in a map of [field, value] where values are the actual references to instances of the fields of obj instead of Maps ?
There is no such feature right now with Jackson. You can probably achieve this with a custom Serializer/Deserializer pair that could share some data and "protocol". But, why bother doing this when the easier (and a LOT faster) way would be to have a generic way to go from POJO to Map, probably using reflection.
I am not sure I understand what you are really trying to do here.
But one thing that may help is to keep in mind that java.lang.Object type (as well as JsonNode) can be freely included in the structure, to get sort of "untyped" binding deeper in the structure. With these types, you can avoid rigid data-binding for some subsets of the object model; and possibly convert to POJOs using ObjectMapper.convertValue() more dynamically.

Create Object vs Reading Json

I'm working on an Android app. The app gets the data as JSON string (name of universities and student lists) and manipulate the app according to the data.
What will be a better approach?
Create a new Object and parse the JSON string into it, and work with the object, or
Keep the JSON string, and just use JSONObject whenever I need to grab information from the string
Or any other way?
If I'm using the new Object, how can I transfer (or share) the object with other activities in the app?
I know that for string we can use putextra().
Use objects.
I would suggest to use Jackson library,
be cause it is very fast and easy to ingrate.
You can find code examples here :
http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
P.S. : Jackson is not the only library for this approach > Jackson Vs. Gson
I almost always parse the JsonObject into a specific object E.g. class University.
One benefit of doing this, is you can put it nicely into collections. E.g. HashMaps, Set or just straight List. When dealing with it as a JsonObject you won't be able to as easily work with it.
You can do things like sort it if you Object inherits Comparable, and can define equals/toString/hashCode.
There are a number of other benefits, but I think you'll find holding that data in a real data structure will give you the most benefit
I would recommend parsing the string (or using a library to do this for you!) and filling an object. This way, your model object can control the data and how it is shared with other objects, and use internal data structures to optimize usage. If you stuck with the JSON string you'd end up parsing it multiple times to pull out data.
However you decide to share the object/string across activities shouldn't affect your decision for how to model the data. You'll likely end up passing it across activities in any case.
I suggest that you use objects too.
You can use Gson library to do any conversion between json string and objects. It is very, very easy to use. http://code.google.com/p/google-gson/
To transfer the data between other activities you can make your object implement the Serializable interface, this way you can use the .putExtra() and pass it forward.

Using HashMap as Collection in Java

JAXB doesn't let you unmarshal already existing xml structures into HashMaps if they are not exactly the way JAXB expects them.
JAXB is fine with handling e.g. LinkedLists and filling them.
I was thinking of creating a interface with a getKey() method and a wrapper around the HashMap taking all objects that implement that interface. The wrapper can then use the getKey() method for all key related features of the map. The wrapper could then easily implement the Collection or List interface.
Because this idea doesn't seem to innovative to me I presume that it already exists in some package, but I'm not googling correctly for it... Can someone please name a good lib that can do this, or do I have to code this myself?
You might consider extending ForwardingList of guava, and using a HashMap in the back. I don't know of any implementation that will leave you only the actual mapping.
Another alternative is creating JAXB XmlAdapter to adapt the values to your map. I think this one is more appropriate.
If all you are trying to pass the information content of a Map as a Collection, use Map.entrySet(). That gives you a Set<Map.EntrySet<K,V>> object; i.e. a collection whose elements are the key/value pairs of the Map. To reconstruct a Map from the collection, you will need to iterate the set and perform an put for each element.

Categories