I'm trying to deserialize using ObjectMapper to a POJO and im getting the error:
No suitable constructor found for type [simple type, class LambdaResult<java.lang.Object>]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
My Pojo is quite simple
class LambdaResult<T> {
LambdaResult() {}
String Status
ArrayList<T> Results
}
And my deserialization code is the following
static <T> T Deserialize(final TypeReference<T> type,
final String json) {
return new ObjectMapper().readValue(json, type)
}
LambdaResult<Object> result = Serialization.Deserialize(new TypeReference<LambdaResult<Object>>() {},jsonResult)
Json example:
{"status": "success", "locale": "sg", "results": [{"status": "pending"}]}
I come from a C# background so there's something im probably missing here.
Thanks
I would recommend creating and configuring an ObjectMapper like this (Java, sorry don't speak Groovy):
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper in this case should probably be a field in the same class as Deserialize method that would then look like:
return mapper.readValue(json, type);
Explanation for configuration:
This MapperFeature tells Jackson to match field names in a case insensitive manner. So it will find String Status although it doesn't follow Java Beans naming conventions. This is neat in your case but comes with a small performance penalty for transforming a String to lowercase. You can alternatively annotate a field in a class with #JsonProperty and specify any JSON field name you want.
This tells Jackson to match JSON fiels to Java object fields regardless of field visibility private, public etc. You may also annotate your class with #JsonAutoDetect and specify visibility there. In both cases you don't need to define a constructor but you can keep it if you don't want it to be public.
The last one tells Jackson to not fail when encountering fields in JSON that don't exist in your class. In this case "locale".
Related
I am parsing JSON string from a byte-array and casting it as an object.
How do I determine the class of the object?
Object objDeserialized = gson.fromJson(jsonFromString, Object.class);
//It could be type Message or RoomDetail
gson.fromJson(jsonFromString, Object.class);
In general, this won't work because of Object.class. Gson prohibits overriding the Object class deserialization and uses ObjectTypeAdapter (see the primary Gson constructor as of Gson 2.8.0 and probably much earlier):
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// user's type adapters
factories.addAll(typeAdapterFactories);
If you want to use Object.class, you have to cast the result to either a primitive wrapper, null, or a List<E> or Map<K,V> -- and make some sort of analysis yourself. The rationale behind it is that you must know the result class in advance to make sure you're getting a proper deserialized object.
The best thing you can do here is making your custom parent super-type (does not really matter if it's a class or an interface), say class Message extends Base and class RoomDetail extends Base, and then registering a JsonDeserializer<Base> implementation to a GsonBuilder which can attempt to detect the real type of the Base instance. After that you can do:
gson.fromJson(jsonSource, Base.class);
See more:
Polymorphic objects deserialization:
How to parse dynamic json in android with retrofit 2 using annotations
How do I parse a nested JSON array of object with a custom Gson deserializer?
Json response parser for Array or Object
Google Gson extras, never been published as artifacts, but may be an inspiration point for you:
https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
If you do not know the type of the JSON you want to parse you could use the JsonParser from the Gson lib to parse the JSON instead of the Gson class directly. e.g.
JsonParser parser = new JsonParser(jsonFromString);
JsonObject obj = parser.parse().getAsJsonObject();
You could then look at the properties of the JsonObject you have created to see what it is. e.g.
if (obj.has("somePropertyNameIKnownIsAMemberOfRoomDetail")) {
RoomDetail roomDetail = gson.fromJson(jsonFromString, RoomDetail.class);
} else {
Message message = gson.fromJson(jsonFromString, Message.class);
}
I'm using GSON for deserializing some JSON data and I'm interested in a way to pass some contextual values into the deserialization process. To be more specific, suppose we have 2 classes:
class A {
String relativePath;
transient B contextDependentValue;
}
class B {
int y;
A z;
}
and a JSON as follows:
{
y: 2,
z: {
relativePath: "./foo/bar"
}
}
When trying to deserialize things, I'd like to populate the contextDependentValue field in the nested object with something that is dependent on where the context of deserialization (e.g. contextDependentValue could be the absolute path on which the JSON was found, so I could then build the full path as contextDependentValue + '/' + relativePath). These context values would be set for each deserialization.
Ideally, I would be able to build a custom JsonDeserializer that gets a context values holder when asked to deserialize:
public T deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context,
Map<String, Object> someSortOfContextValuesHolder) {
return buildObjectWithContext(json, someSortOfContextValuesHolder);
}
and where someSortOfContextValuesHolder would be provided when starting each deserialization:
gson.fromJson(json, B.class, someSortOfContextValuesHolder)
Any ideas on how I could implement something like this?
Have a look at Gson's TypeAdaptor
By default Gson converts application classes to JSON using its built-in type adapters. If Gson's default JSON conversion isn't appropriate for a type, extend this class to customize the conversion.
This stackoverflow article about how-to-handle-deserializing-with-polymorphism also shows sample code samples which may prove relevant and help you out a bit.
Should you be interested in marshalling at runtime you should look into RuntimeTypeAdapterFactory
Adapts values whose runtime type may differ from their declaration type.
...and these article about convert-from-json-to-multiple-unknown-java-object-types-using-gson and how-to-deserialize-a-list-of-polymorphic-objects-with-gson might also prove useful.
I am using jackson-core, databind, annotations 2.3.3 jars. I have the following simple class
public class ClassA {
private int value;
public int getValue() {
return this.value;
}
public void setValue(int value) {
this.value = value;
}
}
And here is the code to try to deserialize a JSON string to the object:
import com.fasterxml.jackson.databind.ObjectMapper;
...
final ObjectMapper objectMapper = new ObjectMapper();
ClassA request = objectMapper.readValue("{\"Value\": 1}", ClassA.class);
But I am getting the following error:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Value" (class ClassA), not marked as ignorable (one known property: "value"])
at [Source: java.io.StringReader#3bff5976; line: 1, column: 12] (through reference chain: ClassA["Value"])
If I changed the JSON string to lower case then it worked. I thought Jackson would be able to map the value to the setter by following the setter convention. I understand i could add JsonProperty annotation to ClassA to make it work but I cannot modify ClassA in my situation.
I also tried explicitly enabling the following mapping features before calling readValue, but it still got the same error:
import com.fasterxml.jackson.databind.MapperFeature;
...
objectMapper.enable(MapperFeature.AUTO_DETECT_GETTERS);
objectMapper.enable(MapperFeature.AUTO_DETECT_SETTERS);
How can I have Jackson bind to standard getters/setters (getXxx and setXxx) without specify annotation to the class being bound?
Thanks!
It looks like this is happening because of the default PropertyNamingStrategy provided by Jackson. From the documentation:
In absence of a registered custom strategy, default Java property
naming strategy is used, which leaves field names as is, and removes
set/get/is prefix from methods (as well as lower-cases initial
sequence of capitalized characters).
The mapper default uses the Java default property naming strategy. If your JSON properties are Pascal Case (not sure because you only provided 1 property) then you can give the mapper the PascalCaseStrategy.
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy.PascalCaseStrategy());
ClassA request = objectMapper.readValue("{\"Value\": 1}", ClassA.class);
Jackson follows bean naming conventions.
I understand i could add JsonProperty annotation to ClassA to make it work but I cannot modify ClassA in my situation.
That's where mixins come in handy. Create an abstract class that has the same method declarations (same getters for example) as ClassA and annotate them with the appropriate #JsonProperty annotation. You then register the mixin with the ObjectMapper and voila! The ObjectMapper will now use the mixin class as a template for serializing and deserializing ClassA.
I have question related to bean to json serialziation/deserialization using Jackson. Previously I have used GSON to do that, but now I am faced with a project that already depends on Jackson and I would prefer not to introduce new dependency if I can do with what I already have at hand.
So imagine I have a bean like:
class ExampleBean {
private String firstField;
private String secondField;
// respective getters and setters
}
And then Jackson serializes it to:
{
"firstField": "<first_field_value>",
"secondField": "<second_field_value>"
}
I am using the following code to produce the above result:
ExampleBean bean;
...
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(outStream, bean);
However I would like (am expected) to get the following serialization:
{
"first_field": "<first_field_value>",
"second_field": "<second_field_value>"
}
I have deliberately simplified my example, but I have big hierarchy of beans that I want to serialize and I want to specify that the serialized attributes should always be in snake_style (that is with underscores) and the corresponding bean fields should always be camelCased. Is there any way I can enforce such field /attribute naming policies and use them without annotating the corresponding attribute for every field?
And yes I found it (it turned out that after 2 hours of searching I had been only 30 minutes away from finding it):
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.writeValue(outStream, bean);
Hopefully this will turn out to be helpful to somebody else too.
Now CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES is the deprecated strategy use SNAKE_CASE instead
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(
PropertyNamingStrategy.SNAKE_CASE);
mapper.writeValue(outStream, bean);
I have a class in Java that is generically typed. It is supposed to return an object of type T after receiving some json. I am using the following code to create the object:
ObjectMapper mapper = new ObjectMapper();
this.object = mapper.readValue(json, type);
This method throws a JsonMappingException, and should do so if the object isn't of the proper type. The problem I'm running into (when unit testing) is that if I pass in json of an incorrect type, as long as both objects are pojos no exception is being thrown. I am simply getting back an object of the correct type where all it's fields are null.
Why is the exception not getting thrown here? If I pass in some json with a bunch of fields that don't exist on the type of object it should be mapping to, shouldn't I get an exception from that?
You possibly have:
#JsonIgnoreProperties(ignoreUnknown = true)
set somewhere, so jackson doesn't complain about the mismatch.
How do you expect Jackson to know JSON does not represent expected type? JSON data does not have type, beyond just basic Object/Array/scalars structure. So as long as structure is compatible things work, and this is by design.