I have a Model consisting in a main Manager class, which has some variables, for example name but also has a big object called data. For a special case I want to pass from json to Model with Gson but ignoring the data Object of the json (for the normal case I will decode completely all the objects of the json).
I need to do this without anotations and without transient, just adding a deserializing rule to exclude Data class in case I want to do it.
How can I specify ad decode time that I want to ignore a class?
My model:
public class Manager{
String name;
Data data;
}
public class Data{
String dummy;
String dummy2;
}
Json sample:
{"manager":{"name":"testname","data":{"dummy":"testname", "dummy2":"testname2"}}}
Code sample that decodes all:
GsonBuilder gsonBuilder = new GsonBuilder();
new GraphAdapterBuilder()
.addType(Data.class)
.addType(Manager.class)
.registerOn(gsonBuilder);
Gson gson = gsonBuilder.create();
Manager manager = gson.fromJson(json, Manager.class);
Fortunately for you, I banged my head last week to sort out a derivative of what you're trying to achieve. So as i mention in this post there is a little trick in the release version that maybe suite what are you trying to do:
Apparently the toString() method inside the parsed class is needed to
make the Gson library work.
The toString() method expose the class to the serialization.
Having said that if you use a release version and don't add any proguard rules you can use the following method to exclude data:
#Override
public String toString() {
return "Manager{" +
"name='" + name + '\'}';
}
Related
I save the payload of events as JSON string into a database.
To only have one version of the events in code while still being able to read old events I want to "upcast" the serialized data before deserialization.
I thought about something like this:
public Object deserialize(String data, Class<?> clazz) throws IOException {
data = upcaster.upcast(data, clazz);
return objectMapper.readValue(data, clazz);
}
But this means I transform the string into some JSON object twice. Once for upcasting the data and once inside the standard jackson mapper.
Is there a way to customize jackson between building the json-object and building my event object?
Something like:
#override
updateData(clazz, jsonData) {
if(clazz.equals(SpecificEvent.class)) {
if(!jsonData.containsKey("addedInfo")) {
jsonData.put("addedInfo", "foo");
}
}
}
Alternatively, I could add my own deserializer that changes the given JSON data before calling the standard deserializer I guess?
What's the normal way of doing something like this with jackson?
One option is custom deserialization with a dedicated deserializer class (per your own class). You would then have to maintain the deserializer class to make sure that it provides any missing data.
It should work for a handful of classes, if you have a lot then there might be better ways.
I have a question regarding Singleton class behavior.
Scenario
We have webservices that is used by partners with request coming as frequently as 2-3 times in 1 second. So, they are heavily used services. We would like to store the request and response in JSON format.
As of now, in each webservice interface class, we have initiated Gson object and doing the serialization of java object to json.
Question
I was just thinking if I initiate Gson object once in Singleton class as static object and then refer it for all the request / response serialization of java object to Json, can it cause any issue/problem?
I mean, as there are multiple webservices and couple of them are heavily used by partners, so will single instance of GSON accessed in all the webservice can cause any delay or any other problem? If yes, apart than memory, what are the other benefits and issues with it?
From javadoc of Gson:
This is the main class for using Gson. Gson is typically used by first constructing a Gson instance and then invoking toJson(Object) or fromJson(String, Class) methods on it. Gson instances are Thread-safe so you can reuse them freely across multiple threads.
So it's ok to have only one Gson instance in your service and reuse it for each request/response. As an example you can consider to create a util class, something like the following class:
public abstract class GsonUtils {
private static Gson gson = new Gson();
static {
// your extra init logic goes here
}
public static <T> T fromJson(String json, Class<T> classOfT) {
return gson.fromJson(json, classOfT);
}
public static String toJson(Object object) {
if (object == null) {
return "";
}
return gson.toJson(object);
}
}
Or you can do it in your way :-)
Recently I was dealing with same idea. There is older thread related to this Is it OK to use Gson instance as a static field in a model bean (reuse)?. Simply summarised the GSON instance should be thread safe.
in my gwt project i am sending objects with the gwt channel api to the client and use Autobean to encode and decode those objects. everything works fine, i receive a valid json string on the client and can decode that json string to the AutoBean back again. only the autobean.as() does not return anything different than the autobean itself.
IContactDto and ContactDto just contain getters and setters. and this is the facbory i wrote
AutoBeanFactory
public interface DtoFactory extends AutoBeanFactory{
AutoBean<IContactDto> contactDto(IContactDto contactDto);
}
Server-side code
DtoFactory dtoFactory = AutoBeanFactorySource.create(DtoFactory.class);
AutoBean<IContactDto> iContactDto = dtoFactory.contactDto(contactDto);
String sJson = AutoBeanCodex.encode(autoBean).getPayload();
// sending this json to the client
Client-side code
this is the code i use for decoding the valid json string
// sJson string looks like {"id":"6473924464345088", "lastUpdate":"1475914369346", "fullName":"testName1","givenName":"testName2"}
DtoFactory factory = GWT.create(DtoFactory.class);
AutoBean<IContactDto> autoBean = AutoBeanCodex.decode(factory, IContactDto.class, sJson); // debugger: IContactDtoAutoBean_1_g$
IContactDto iDto = autoBean.as(); // debugger still shows IContactDtoAutoBean$1_1_g$
i can actually use the getters and setters of this object, but as soon as i try continue to work this those objects i get a problem with the type signature.
any ideas how i can get the object i encoded back again?
AutoBean#as() returns a “proxy implementation of the T interface which will delegate to the underlying wrapped object, if any.” (source: javadoc), it will never return the wrapped object itself.
Moreover, when deserializing from JSON, there's no wrapped object, a new autobean is created "from scratch" and then filled with JSON (it actually directly wraps a Splittable from the parsed JSON: super-lightweight, just a thin typesafe wrapper around a JS object –or a org.json.JSONObject when not in the browser.)
I'm having some cases where Jackson is changing cases of fields in a POJO during serialization in ways I would not expect. I'm using the following block to do the serialization:
ObjectMapper mapper = new ObjectMapper()
String json = mapper.writeValueAsString(o)
I'm noticing that all of the fields which are prepended with 'v' are getting the next capital letter also lowercased. For example, for the POJO field as below:
vStatus1 = "3424522"
I see after serialization the following JSON field:
vstatus1="3424522"
This is mainly important to me because I'm using a switch to go between two different web services which should provide the same output map, but this hiccup is preventing me from doing it cleanly.
If you are using Jackson, you can set the #JsonProperty on the field's getter and change it to whatever you like...
#JsonProperty("vStatus1")
public String getvStatus1() {
return vStatus1;
}
// Produces: {"vStatus1":"3424522"}
#JsonProperty("VStatus1")
public String getvStatus1() {
return vStatus1;
}
// Produces: {"VStatus1":"3424522"}
I'm using a switch to go between two different web services which should provide the same output map
In addition to the above, perhaps consider switching on the lowercased version of your string...
switch(myString.toLowerCase()) {
case "foo": doSomething();
...
}
I have a Java object as below
public class Command {
private String cmd;
private Object data;
}
I want JSON Conversion of this Object to look as below
{"cmd":"getorder","data":{"when":"today"}}
How do I do this without changing the Class definition?
I know how to use GSON or Jackson library. I am having trouble assigning values to or initializing (Object) data above, so that it properly converts to {"when":"today"} when I use those libraries.
Thanks
You can try Gson library
it's very easy to use and it can do the reverse operation as well
Depending on your needs you might consider to add a handwritten json formatter for your class (of yourse this interferes with your demand to not change the class definition) but in fact it gives you max flexibility without 3rd party dependencies. If you strictly let all your Objects overwrite toString() to give json formatted string representation you could e.g.
String toString() {
StringBuffer result = new StringBuffer();
result.add("{ \"cmd\":" + this.cmd);
result.add(",");
result.add( \"data\":" + data.toString());
result.add("}");
return result.toString();
}
In case your need to not change the class definition appears more important than the mentioned advanteges there is a a nice json library avaialble on code.google.com named "simple json" ( https://code.google.com/p/json-simple/ ).