I'm having a problem serializing an object using Gson.
#XmlRootElement
class Foo implements Serializable {
private int number;
private String str;
public Foo() {
number = 10;
str = "hello";
}
}
Gson will serialize this into a JSON
{"number":10,"str":"hello"}.
However, I want it to be
{"Foo":{"number":10,"str":"hello"}},
so basically including the top level element. I tried to google a way to do this in Gson, but no luck. Anyone knows if there is a way to achieve this?
Thanks!
You need to add the element at the top of the the object tree. Something like this:
Gson gson = new Gson();
JsonElement je = gson.toJsonTree(new Foo());
JsonObject jo = new JsonObject();
jo.add("Foo", je);
System.out.println(jo.toString());
// Prints {"Foo":{"number":10,"str":"hello"}}
Instead of hardcoding the type you can do:
...
jo.add(Foo.getClass().getSimpleName(), je);
A better way to do this is to create a wrapper class and then create an object of Foo inside it.
Sample code:
public class ResponseWrapper {
#SerializedName("Foo")
private Foo foo;
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo= foo;
}
}
Then you can easily parse to JSON using:
new GsonBuilder().create().toJson(responseWrapperObj);
which will give you the desired structure:
{"Foo":{"number":10,"str":"hello"}}
If you are using Jackson api use the below lines
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
Related
I have a POJO that contains the following attributes
public class Example {
#JsonProperty("inputFoo")
private String foo
#JsonProperty("inputBar")
private String bar
#JsonProperty("inputBaz")
#JsonDeserialize(using = MyDeserializer.class)
private Set<String> baz
}
The JSON that I am working with to represent this data currently represents the baz attribute as a single string:
{"inputFoo":"a", "inputBar":"b", "inputBaz":"c"}
I am using the Jackson ObjectMapper to attempt to convert the JSON to my POJO. I know that the input baz String from the JSON wont map cleanly to the Set that I am trying to represent it as, so I defined a custom Deserializer:
public class MyDeserializer extends StdDeserializer<Set<String>> {
public MyDeserializer(){}
public MyDeserializer(Class<?> vc) {
super(vc);
}
public Set<String> deserialize(JsonParser p, DeserializationContext cxt) throws IOException, JsonProcessingException {
String input = p.readValueAs(String.class);
Set<String> output = new HashSet<>();
if(input != null) {
output.add(input);
}
return output;
}
}
I am getting an IllegalArgumentException referencing the "inputBaz" attribute, which I can provide details on. Does anyone see any obvious issue with my deserializer implementation? Thanks
You do not need to implement custom deserialiser, use ACCEPT_SINGLE_VALUE_AS_ARRAY feature. It works for sets as well:
Feature that determines whether it is acceptable to coerce non-array
(in JSON) values to work with Java collection (arrays,
java.util.Collection) types. If enabled, collection deserializers will
try to handle non-array values as if they had "implicit" surrounding
JSON array. This feature is meant to be used for
compatibility/interoperability reasons, to work with packages (such as
XML-to-JSON converters) that leave out JSON array in cases where there
is just a single element in array. Feature is disabled by default.
See also:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.ArrayList out of START_OBJECT token
Replace the 2 constructors with this no-arg constructor:
public MyDeserializer() {
super(TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class));
}
ACCEPT_SINGLE_VALUE_AS_ARRAY as suggested is a good option.
Maybe your actual problem is more complicated but if not you could also try #JsonCreator instead of custom deserializer. Like:
public class Example {
#JsonCreator
public Example(#JsonProperty("inputFoo") String foo,
#JsonProperty("inputBar") String bar,
#JsonProperty("inputBaz") String strBaz) {
this.foo = foo;
this.bar = bar;
this.baz = new HashSet<>();
baz.add(strBaz);
}
private String foo;
private String bar;
private Set<String> baz;
}
Just to show that in more general case you might avoid implementing custom deserializer with #JsonCreator also but still make some simple conversions.
I'm new to java (Hum... No... I learned Java at school 10 years ago but never really used it since today).
I have an object class which corresponds to my json and was generated with the website http://www.jsonschema2pojo.org/ (simplified here) :
public class ServerDatasObject {
private Integer error;
private Boolean isOffline;
public Integer getError() {
return error;
}
public Boolean getIsOffline() {
return isOffline;
}
}
And another class used to access all object data (simplified too) :
public class ServerDatasHandler extends ServerDatasObject {
public ServerDatasHandler(String json) {
Gson gson = new Gson();
// how to populate current object using : gson.fromJson(json, ServerDatasObject.class);
}
}
The question is in the code: how to populate current object?
I searched and found something about InstanceCreator :
final Foo existing;
InstanceCreator<Foo> creator = new InstanceCreator<Foo>() {
public Foo createInstance(Type type) { return existing; }
}
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, creator).create();
Foo value = gson.fromJson(jsonString, Foo.class);
// value should be same as existing
but I don't understand how to use it and if it is what I need.
The final goal is to
{
ServerDatasHandler serverDatasHandler = new ServerDatasHandler (json);
do something with serverDatasHandler.getError()
}
Thanks for your help
You can create a separate static method which creates your handler from json:
public static ServerDatasHandler fromJsonConfig(String json) {
Gson gson = new Gson();
ServerDatasHandler handler = gson.fromJson(json, ServerDatasHandler.class);
return handler;
}
Of course you can also move this method to a factory.
I never used InstanceCreator inside constructor because parsing JSON is almost never a task for a constructor. Preferably it should be hidden inside framework or your own factories. Though, your example with InstanceCreator should also work if you will return ServerDatasHandler.this from the createInstance method.
I need to convert a java object (called org) to json format.
The object (DTO ) is a bit complex, because it contains a list of objects of the same class and which in turn can also contain more objects of the same class ( built recursively). When I passing the object to gson.toJsonTree method it seems to fail (there isnt any error), but it seems that the method does not like complex objects). If I set to null the list of objects of the first object everything works fine. I can not modify the class, only the method that makes json.
JsonElement jsonUO = null;
jsonUO = gson.toJsonTree(org,OrgDTO.class);
jsonObject.add("ORG", jsonUO)
public class OrgDTO implements Serializable{
private String id;
......
private List sucesores;
public OrgDTO(){
this.sucesores = new ArrayList();
}
.....
}
It might be a little bit late for the questioner, however I share my answer in case someone else face similar issue:
You'll need to create a helper class that does the json serialization. It should implement the JsonDeserializer:
public class OrgDTOJsonSerializer implements JsonDeserializer<OrgDTO> {
#Override
public JsonElement serialize(OrgDTO src, Type type, JsonSerializationContext jsc) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", src.getId());
/// Build the array of sucesores (whatever it means!)
JsonArray sucesoresArray = new JsonArray();
for (final OrgDTO obj: src.getSucesores()) {
JsonObject succJsonObj = serialize(obj, type, jsc);
sucesoresArray.add(succJsonObj);
}
jsonObject.add("sucesores", sucesoresArray);
return jsonObject;
}
}
Then you'll need to register it in gson before attempting to serialize any object of that type:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(OrgDTO.class, new OrgDTOJsonSerializer());
This is an example of the kind JSON I'm trying to consume using GSON:
{
"person": {
"name": "Philip"
"father.name": "Yancy"
}
}
I was wondering if it were possible to deserialize this JSON into the following structure:
public class Person
{
private String name;
private Father father;
}
public class Father
{
private String name;
}
So that:
p.name == "Philip"
p.father.name == "Yancy"
Currently I am using #SerializedName to obtain property names containing a period, e.g.:
public class Person
{
private String name;
#SerializedName("father.name")
private String fathersName;
}
However, that's not ideal.
From looking at the documentation it doesn't appear to be immediately possible but there may be something I have missed - I'm new to using GSON.
Unfortunately I cannot change the JSON I'm consuming and I'm reluctant to switch to another JSON parsing library.
As far as I understand you can't do it in a direct way, because Gson will understand father.name as a single field.
You need to write your own Custom Deserializer. See Gson user's guide instructions here.
I've never tried it, but it doesn't seem to be too difficult. This post could be also helpful.
Taking a look at Gson's user guide and the code in that post, you'll need something like this:
private class PersonDeserializer implements JsonDeserializer<Person> {
#Override
public Person deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonObject jobject = (JsonObject) json;
Father father = new Father(jobject.get("father.name").getAsString());
return new Person(jobject.get("name").getAsString(), father);
}
}
Assuming that you have suitable constructors...
And then:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Person.class, new PersonDeserializer());
Gson gson = gsonBuilder.create();
Person person = gson.fromJson(jsonString, Person.class);
And Gson will call your deserializer in order to deserialize the JSON into a Person object.
Note: I didn't try this code, but it should be like this or something very similar.
I couldn't do this with just Gson. I need a new library 'JsonPath'. I used Jackson's ObjectMapper to convert the object to string but you can easily use Gson for this.
public static String getProperty(Object obj, String prop) {
try {
return JsonPath.read(new ObjectMapper().writeValueAsString(obj), prop).toString();
} catch (JsonProcessingException|PathNotFoundException ex) {
return "";
}
}
// 2 dependencies needed:
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
// https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path
// usage:
String motherName = getProperty(new Person(), "family.mother.name");
// The Jackson can be easily replaced with Gson:
new Gson().toJson(obj)
Let's imagine I have a Java class of the type:
public class MyClass
{
public String par1;
public Object par2;
}
Then I have this:
String json = "{"par1":"val1","par2":{"subpar1":"subval1"}}";
Gson gson = new GsonBuilder.create();
MyClass mClass = gson.fromJson(json, MyClass.class);
The par2 JSON is given to me from some other application and I don't ever know what are it's parameter names, since they are dynamic.
My question is, what Class type should par2 variable on MyClass be set to, so that the JSON String variable is correctly deserialized to my class object?
Thanks
Check out Serializing and Deserializing Generic Types from GSON User Guide:
public class MyClass<T>
{
public String par1;
public T par2;
}
To deserialize it:
Type fooType = new TypeToken<Myclass<Foo>>() {}.getType();
gson.fromJson(json, fooType);
Hope this help.
See the answer from Kevin Dolan on this SO question: How can I convert JSON to a HashMap using Gson?
Note, it isn't the accepted answer and you'll probably have to modify it a bit. But it's pretty awesome.
Alternatively, ditch the type safety of your top-level object and just use hashmaps and arrays all the way down. Less modification to Dolan's code that way.
if you object has dynamic name inside lets say this one:
{
"Includes": {
"Products": {
"blablabla": {
"CategoryId": "this is category id",
"Description": "this is description",
...
}
you can serialize it with:
MyFunnyObject data = new Gson().fromJson(jsonString, MyFunnyObject.class);
#Getter
#Setter
class MyFunnyObject {
Includes Includes;
class Includes {
Map<String, Products> Products;
class Products {
String CategoryId;
String Description;
}
}
}
later you can access it:
data.getIncludes().get("blablabla").getCategoryId()
this code:
Gson gson = new GsonBuilder.create();
should be:
Gson gson=new Gson()
i think(if you are parsing a json doc).