Need some insights: How to write proto file for serializing a java POJO class containing JSONObject as attribute with Protobuf serialization.
The JSON we have is fluid (keys keep changing).
Sample:
public class POJO {
private String atr1;
private long atr2;
private Map<String, String> atr3;
private JSONObject atr4;
}
No proper apporach to handle such scenarios. However, JSON with java has fallback serialization default mechanism which is only option left with.
Related
I have a json string, here is example
{
"Param1":"Value1",
"Param2":{...}
"ParamThatINeed":{...}
}
I want to get only "ParamThatINeed" object using gson lib in java, what is the best way to get what I need - write root class, then write class for "ParamThatINeed" and then decode json and use only "ParamThatINeed" object?
Or maybe it's better to beforehand convert my jsonString to another string, which will be only "ParamThatINeed" jsonString object using for example regexp? Or maybe there is a better way?
Your suggested solution is painless and extensible (i.e. if you decide to read an additional field in the future, you just add another field to your object). In general that's exactly how you want to use Gson - construct the necessary Java classes to represent the data you care about and Gson will silently discard the fields you don't care about. For your example that could look like:
private static final Gson GSON = ...;
public static class MyJsonData {
private final ParamThatINeed paramThatINeed;
public ParamThatINeed getParamThatINeed() { ... }
}
public static class ParamThatINeed {
...
}
public static ParamThatINeed extractParamThatINeed(String json) {
return GSON.fromJson(json, MyJsonData.class).getParamThatINeed();
}
You could parse the field yourself as #GuiSim suggests, but this won't scale as easily if your requirements change, and generally speaking the idea behind Gson is to avoid working directly with JsonElement and related classes.
I would definitely discourage a pre-processing step converting the JSON string into a different format. Structured data and string manipulations don't mix, as they lead to brittle code. JSON parsing libraries like Gson exist exactly to avoid such string manipulations.
JsonObject jobj = new Gson().fromJson(YOUR_JSON_HERE, JsonObject.class);
JsonElement value = jobj.get("ParamThatINeed");
value will contain the element associated with the ParamThatINeed key.
I am building a REST API with a payload that has a property called jsonContent, which holds any valid json.
{
"name":"foo",
"jsonContent":{ "abc":"My content"}
}
On the server side I want to map the it to a generic java object ,and eventually save the whole object to mongodb
private String name;
private ?????? jsonContent
I am using jackson for mapping json to java. How do I declare my java object so any json content can be used.
Use JsonNode:
private JsonNode jsonContent;
I answer my own question, Following worked just fine for me
private Map<String,Object> jsonContent;
For example, given JSON:
[
{"id":"3", "location":"NewYork", "date":"yesterday"},
{"id":"4", "location":"Moscow", "date":"today"}
]
resulting HashMap:
<"3", POJOLocation("NewYork", "yesterday")>
<"4", POJOLocation("Moscow", "today")>
where POJOLocation is a Java object:
class POJOLocation {
private String location;
private String date;
// etc
}
I've tried using custom deserializer, but it was really bloated with generic's tokens and hackish typeOfs. Perhaps there is a simple efficient solution?
Maybe create a POJOLocationId class:
class POJOLocationId {
private int id;
private String location;
private String date;
// etc
}
Then deserialize & loop over the resulting List populating your HashMap as you go?
Gson is designed to make serializing Java objects to their JSON equivalent painless. If you're trying to represent a Java data structure as a different type of JSON structure you're not going to have a lot of fun writing serializers and deserializers. At that point you might consider a lower-level JSON parser and simply implement the parsing you want yourself. Rather than representing your data one way in JSON and another way in Java (and thus running into the hassle of transforming between them) you might consider refactoring either your data structure or your data so they're more similar.
That said the easiest thing to do with Gson (which is really not that bad, memory and time-wise) is to use a wrapper type and then transform the input/output before using it. Something like so (borrowing from Tom Mac's type name):
private static final Type LIST_TYPE =
new TypeToken<List<POJOLocationId>>() {}.getType();
public String serialize(Map<Integer, POJOLocation> locations) {
List<POJOLocationId> locationsList = original.entrySet().stream()
.map(e -> new POJOLocationId(e.getKey(), e.getValue()).collect(toList());
return gson.toJson(locationsList);
}
public Map<Integer, POJOLocation> deserialize(String json) {
List<POJOLocationId> locationsList = gson.fromJson(json, LIST_TYPE);
return locationsList.stream()
.collect(toMap(l -> l.getId(), new POJOLocation(l)));
}
You certainly can get this same behavior with a custom deserializer, but this works, it's clean, and it's easy to read. The garbage collector should have no trouble cleaning up these temporary wrappers as soon as these methods return.
I have a Map<String, Object> which I am using as a mapping for a JSON document, however want to create and maintain Java type information at the same time as retaining the structure of the document.
I'm attempting to use Jackson to create the document and it seems to work fine but I'm seeing something strange when attempting to deserialize it. A very simple serialization example:
final ObjectMapper mapper = new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, JsonTypeInfo.As.EXTERNAL_PROPERTY);
final Map<String, Object> map = Maps.newHashMap();
map.put("test", new Date());
final String ser = mapper.writeValueAsString(map);
final Map<String, Object> deser = mapper.readValue(ser, new TypeReference<HashMap<String, Object>>(){});
System.err.println(deser.get("test").getClass());
Gives the serialized form {"test":1410721662084,"#class":"java.util.Date"} which seems fine but when deserializing returns the type of "test" to be Long.
If I change the type serialization to use WRAPPER_ARRAY rather than EXTERNAL_PROPERTY then the type of "test" is correctly returned as Date, but doing this alters the structure of the JSON document so is not something I'm allowed to do. How do I retain the structure of the document as well as allow deserialization back to the correct types?
This is against Jackson 2.4.2.
Deserialization with maps is always tricky as maps don't preserve type information, which makes Jackson resort to #class and that not something you usually want. Instead, you can create a simple class:
public class TestClass {
private Date test;
//getters and setters omitted
}
This class has concrete structure and JSON will serialize it as
{ "test" : 1410721662084}
which is much cleaner and type-safe representation of your object. Then you just need to pass TestClass.class to readValue() method and your test attribute will be magically converted to proper type (Date)
I want to move from org.json to org.codehaus.jackson. How do I convert the following Java code?
private JSONObject myJsonMessage(String message){
JSONObject obj = new JSONObject();
obj.put("message",message);
return obj;
}
I left out the try-catch block for simplicity.
Instead of JSONObject use Jackson's ObjectMapper and ObjectNode:
ObjectMapper mapper = new ObjectMapper();
ObjectNode node = mapper.createObjectNode();
node.put("message", "text");
This would be Jackson's equivalent of your current org.json code.
However, where Jackson really excels is in its capacity to do complex mappings between your Java classes (POJOs) and their JSON representation, as well as its streaming API which allows you to do really fast serialization, at least when compared with org.json's counterparts.
There is no JSONObject in Jackson api. Rather than returning a JSONObject, you can either return a Map or a Java Bean with message property that has getters and setters for it.
public class MyMessage {
private String message;
public void setMessage(final String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
So, your method will be reduced to:
private MyMessage(String message) {
MyMessage myMessage = new MyMessage();
myMessage.setMessage(message);
return myMessage;
}
Another aspect of this change would be changing the serialization code, to convert MyMessage back to json string. Jackson does Java Beans, maps by default, you don't need to create a JSONObject e.g.,
private String serializeMessage(MyMessage message){
//Note: you probably want to put it in a global converter and share the object mapper
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(message);
}
The above will return {message: "some message"}
I have skipped the exceptions for brevity.
If you want to upgrade from org.json library to Jackson piece by piece, and initially retaining same API, you might want to read "Upgrade from org.json to Jackson".
This would at least make your code about 3x faster for basic JSON reading and writing; plus you could -- if you so choose -- start converting processing, as Jackson makes it easy to convert between Trees and POJOs (ObjectMapper.treeToValue(...), valueToTree, convertValue between POJOs etc. etc).
Just keep in mind that tools that you are familiar with may bias your thinking to certain patterns, and keeping an open mind can help you find even better ones.
In case of Jackson (or GSON or other mature Java JSON tools), you really should consider where proper data-binding could help, instead of using JSON-centered tree model (that org.json offers). Tree Models keep your thinking grounded to JSON structure, which is sometimes useful; but might also prevent you from seeing more natural patterns that come from defining POJO structure to reflect expected JSON, and operating on Java Objects directly.