I am using Jackson for JSON parsing.
What is the difference between JsonNode and ObjectNode?
And which to use for mapping JSON in string format.
Quick answer
JsonNode: Abstract class, used when reading a JSON document.
ObjectNode: Concrete implementation, used when building or modifying a JSON document.
Keep reading for a more detailed answer.
JsonNode
JsonNode is an abstract class used as the base class for all JSON nodes, which form the basis of JSON Tree Model that Jackson implements.
Quoting the JsonNode documentation:
As a general design rule, most accessors (getters) methods are included in this base class, to allow for traversing structure without type casts.
Mutators methods (setters), however, need to be accessed through specific sub-classes (such as ObjectNode and ArrayNode).
This seems sensible because proper type information is generally available when building or modifying trees, but less often when reading a tree (newly built from parsed JSON content).
The JsonNode concrete implementations can be found in the com.fasterxml.jackson.databind.node package.
ObjectNode
ObjectNode is a concrete implementation of JsonNode that maps a JSON object, and a JSON object is defined as following:
An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
Related
I am trying to convert GSON to jackson I have a method that returns a gson JsonObject. However it only creates a JsonArray, and returns that so I assume there is a simple casting there. So what would be the Jackson Equivalent? Now the method only adds one string at a time. So I need something like this:
JsonNode node = new JsonNode();
node.add("String 1");
node.add("String 2');
but would come out like this:
["String 1","String 2"]
I could create a List and map it from there, but I want to do this raw.
This seems too simple as google has given me many suggestions that are far beyond what this simple exercise requires.
And if anyone has a nice blog to tutorial on how to convert Gson to Jackson that would be great.
it is a bit tricky - you create an array node through JsonNode factory method:
ArrayNode arrNode = (ArrayNode)new JsonNode().withArray("my_array"); // arg is arrray propertry name
arrNode.add("String 1");
arrNode.add("String 2');
If you just want to create ArrayNode, ObjectMapper has method createArrayNode(), along with createObjectNode(). You can then add entries to it, as well as add node itself into other arrays, or as property in ObjectNode.
Actual construction of nodes by mapper is done using configurable JsonNodeFactory; default implementation of which simple constructs one of standard implementation types like ObjectNode and ArrayNode.
I'm using Protostuff in an attempt to serialize/deserialize objects of several different types for which no protobuf sources are available (it's a server-server RPC scenario). Serialization goes OK because I know the type of the object to serialize and can create the schema:
Schema schema = RuntimeSchema.getSchema(object.getClass());
Now, I use ProtobufIOUtil.toByteArray and get a byte array which I then pass to a remote server. However, I can't seem to deserialize this byte array in the remote server because I have no way to create a schema for an object of "unknown" type. Is there any way I can get past this and use Protostuff in the same way I would use Java's native serialization?
There are few solutions with common idea - serialize name of the class together with the data.
First one requires protostuff-runtime. You should create wrapper class with one field of type Object:
public class Wrapper {
public Object data;
}
Then you put your object to data field and serialize wrapper, protostuff-runtime will append class name to serialized form automatically, and later use it for deserialization.
If you want more control, then you can do similar thing without protistuff-runtime.
First, you need a wrapper class:
public class Wrapper {
public String clazz;
public byte[] data;
}
Then you should serialize your data to byte array, store it to wrapper, and then serialize wrapper instance.
On remote side, you deserialize Wrapper first, then get clazz field - it is the class you should use to deserialize data.
I would like to leverage the Jackson infrastructure to transform an untyped Map/List structure into a POJO hierarchy.
What I need is pretty close to
jsonNode = objectMapper.valueToTree(MapHierarchy) followed by
pojoTree = objectMapper.treeToValue(jsonNode)
...except that I need to modify the field names on the fly: the names found in the source Map/List hierarchy are declared as custom annotations on the POJO class.
Here is a complete example:
public class Cat
{
#MapField("attr:col")
#JsonProperty("color")
private String _color;
}
... and the source Map:
{
"attr:col" -> "black"
}
... from which I would like to obtain a Cat instance.
I am sure there has got to be an elegant way to achieve this with the Jackson APIs, but I can't quite figure out how... any suggestions? Obviously I don't want to create a second parallel class hierarchy just to describe the deserialization of the Map through annotations.
An extra bonus would be to be able to transform the Map without going through stringified JSon which I believe is how valueToTree works.
I am looking at this API ArrayListMultiMap which implements the Serializable interface. Does that mean I can serialize this object ? Are all Multimap objects serialized ?
The meaning of Serializable is always the same: If an object isn't serializable, it can't be serialized. If it is, it may work or not... Especially in case of collections (including maps and multimaps), it depends on their content.
As an example, you can surely serialize ArrayList<String> as ArrayList.class is serializable and so is each member of the list. OTOH trying to serialize ArrayList<Object> may or may not work: If all contained objects are e.g. strings, it will work. If any member is not serializable, you'll get an exception.
Does it mean I can serialize this object?
If all keys and values are serializable, you can.
Are all multiMap object serializable?
No, the interface Multimap doesn't extend Serializable, so there may be non-serializable implementation. Indeed, you can get such an instance via e.g. Multimaps.filterEntries.
ArrayListMultimap and HashMultimap are Serializable BUT the Collection views (in asMap() for example) are not.
This problem is answered here:
To use the map returned by asMap(), you can re-create a new map and wrap the Multimap Collection views into other collections (for example a Set), that will make the new map Serializable:
Multimap<MyClass, MyOtherClass> myMultiMap = HashMultimap.create();
// ... build your multimap
Map<MyClass, Set<MyOtherClass>> map = myMultiMap.asMap().entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
(entry) -> ImmutableSet.copyOf(entry.getValue())
));
Or java 7 compliant code:
Multimap<MyClass, MyOtherClass> myMultiMap = HashMultimap.create();
// ... build your multimap
Map<MyClass, Set<MyOtherClass>> map = Maps.newHashMap();
for (Map.Entry<MyClass, Collection<MyOtherClass>> entry :
myMultiMap.asMap().entrySet()) {
map.put(entry.getKey(), ImmutableSet.copyOf(entry.getValue()));
}
I've written a implementation of Converter that uses Jackson JSON to serialize a list of deeply structured objects to JSON, but it's not being called. Am I doing this correctly?
#Converter(name="arrayList", converterClass=ArrayListJsonSerializedObjectConverter.class)
private List<DeeplyStructuredObject> deeplyStructuredObjects= new ArrayList<DeeplyStructuredObject>();
Additionally, I'd like to know whether or not one can use a ReadTransfomer in addition to a
Converter on the same property, e.g.
#Converter(name="arrayList", converterClass=ArrayListJsonSerializedObjectConverter.class)
#ReadTransformer(method="someMethod")
private List<DeeplyStructuredObject> deeplyStructuredObjects= new ArrayList<DeeplyStructuredObject>();