Deserialize json as quoted string in Jackson without annotations - java

I have a class like this.
class MyClass {
String config;
// ... other fields, getters, setters ...
}
The config string will be coming as JSON from the REST endpoint in the request body as follows..
"config": {
"field1": "value1",
"field2": 2,
"field3": true
}
// other fields of MyClass
I need to deserialize MyClass in such a way that the above JSON string is put in quotes as follows.
"config": "{
\"field1\": \"value1\",
\"field2\": 2,
\"field3\": true
}"
I cannot modify this class as it is being used by other projects. So, I cannot use #JsonDeserialize or any annotations on the class.
I tried setting the following properties to ObjectMapper
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false)
.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
Is there any other way, perhaps using ObjectMapper to deserialize it that way. I am using Spring Boot also, so would welcome a Spring boot Jackson way of doing this.

You can use JsonNode, the Jackson JsonNode class, com.fasterxml.jackson.databind.JsonNode is Jackson's tree model (object graph model) for JSON, use like that:
String content = jsonNode.get("data").textValue();

Related

Convert entity property camel case to snake case in json in jhipster project

I am working with a project that is generated with jhipster. It is a micro service architecture project.
In my entity class properties are named with camel case. So when I create a rest service it gives me json, where the json property names are as same as the entity properties.
Entity class
#Entity
#Table(name = "ebook")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "ebook")
public class Ebook implements Serializable {
private Long id;
private String nameBangla;
private String nameEnglish;
Json response
{
"id": 0,
"nameBangla": "string",
"nameEnglish": "string"
}
I want that my entity property will camel case, But in json response it will snake case. That is I don't want to change my entity class but I want to change my json response like bellow
{
"id": 0,
"name_bangla": "string",
"name_english": "string"
}
You have two possibilities:
Explicit naming your properties:
#JsonProperty("name_bangla")
private String nameBangla;
#JsonProperty("name_english")
private String nameEnglish;
or changing how jackson (which is used for de/serialization) works:
Jackson has a setting called PropertyNamingStrategy.SNAKE_CASE
which you can set for the jackson objectmapper.
So, you need to configure Jackson for that, e.g. by adding your own object mapper:
#Configuration
public class JacksonConfiguration {
#Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder().propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
}
}
As far as I know, in older version of JHipster, there was already a JacksonConfiguration to configure the JSR310 time module, but was removed later...
Adding this to your application.yml should also work:
spring.jackson.property-naming-strategy=SNAKE_CASE
Also you can use annotation to define naming strategy per class.
Little example in Kotlin:
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class Specialization(val altUrl: String, val altId: Int, val altName: String)

How to make POJO dynamic so that it ignores an json tag but reads the value under that tag using jackson in java?

I've a parent DAO:
#XmlRootElement//(name="metadata")
public class FolderAttributes {
private Map nameValueForListValue;
Child DAO:
#XmlAccessorType(XmlAccessType.FIELD)
public class ListWrapper {
#XmlElementWrapper(name = "attrValue")
private List<Object> list;
JSON request that works (if I use "metadata" name as root element):
"metadata": {
"nameValueForListValue": {
"signed": {
"attrValue": [
"ahsdfhgakjf"
]
},
"id": {
"attrValue": [
"12345678",
"87654321"
]
},
.......... continues
I don't want the tag "nameValueForListValue" in request, instead it should be smart enough to read rest of the values without that tag. Looks like it always needs to have the param name "nameValueForListValue" on the request. Is there any annotations that will do my job easier? I'm using Java 6 & jackson 1.9.
What about using #JsonAnySetter Jackson annotation
It would be something like:
#XmlRootElement//(name="metadata")
public class FolderAttributes {
private Map nameValueForListValue;
#JsonAnySetter
public void genericSetter(String key, Object value){
nameValueForListValue.put(key, value);
}
}
That whay any unknown field could be handle by this setter.
More info:#JsonAnySetter example
#JsonInclude(JsonInclude.Include.NON_NULL)

How to skip Optional.empty fields during Jackson serialization?

I have a Java class with an Optional field. I am serializing the class to JSON using Jackson 2.8.3 (called from Spring web 4.3.3).
I am hoping to get the serializer to skip the field if the Optional is empty, and serialize the contained string if it is present. An example of the result I'm looking for with a list of two objects:
[
{
"id": 1,
"foo": "bar"
},
{
"id": 2,
}
]
Here the foo Optional is empty for the object with id 2.
Instead, what I get is:
[
{
"id": 1,
"foo": {
"present": true
}
},
{
"id": 2,
"foo": {
"present": false
}
}
]
This is the result even if I annotate the "bar" field in the class like
#JsonInclude(JsonInclude.Include.NON_ABSENT)
public Optional<String> getFoo() { ...
Is there any way I can achieve a result like the first list using the Jackson annotations or a custom serializer?
No need to write custom serializer. Annotate your class with #JsonInclude(JsonInclude.Include.NON_ABSENT).
You also need to:
include com.fasterxml.jackson.datatype:jackson-datatype-jdk8 as your dependency
and to register the corresponding module with your object mapper: objectMapper.registerModule(new Jdk8Module());
You can use objectMapper.registerModule(new Jdk8Module()); but it serializes with null values.
But still you want to remove null values also from JSON, please use the following code:
objectMapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(true));
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Use a JsonSerializer to your needs.
Something like this (semi-pseudo):
public class MySer extends JsonSerializer<Opional<?>> {
#Override
public void serialize(Optional<?> optString, JsonGenerator generator, SerializerProvider provider)
throws IOException, JsonProcessingException {
//Check Optional here...
generator.writeString(/* DO SOMETHING HERE WHATEVER */);
}
//Then in your model:
public class ClassWhatever {
#JsonSerialize(using = MySer .class)
public Optional<String> getFoo() { ...
}
To avoid annotating every field with #JsonSerialize you may register your custom serializer to object mapper using
ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addSerializer(new MyCustomSerializer()); // assuming serializer declares correct class to bind to
mapper.registerModule(testModule);
Also, given solution works only for serialization. Deserialization will fail unless you write your own deserializer. Then you need to annotate every field with #JsonDeserialize or register your custom deserializer.

Jackson serialization error when class has generics in it

So I have a class that I want jackson to serialize.
public class MyClass<T extends MyInterface> {
private T myGeneric;
private String desc;
....
}
public interface MyInterface {
String getSomeString();
}
public class MySubClass implements MyInterface {
private String info;
....
#Override
public getSomeString() {
return "";
}
}
MyClass can have many types of other classes under it's myGeneric field.
The problem is that when I pass my JSON to the server, then Jackson throws an error: problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information.
I investigated around and mostly only found examples of how to solve jackson problems with abstract classes but none for this kind of problem. I also tried using the #JsonTypeInfo and #JsonSubTypes annotations to list what kind of classes can go under MyClass but I am not sure if what I did was just wrong or not because it is hard to find any similar examples with them and the documentation in here: was not really helpful also.
Is this kind of problem solvable with Jackson annotations or I need to write a custom serializer for my class?
I am testing the serialization like this:
String json = "myJson";
ObjectMapper mapper = new ObjectMapper();
MyClass myClass = mapper.readValue(json, MyClass.class);
Jackson can't deserialize abstract types without additional info: when you have JSON with field
"myGeneric" : { "field1" : 1, "field2" : 2}
you have no idea what is the class of the myGeneric object.
So you have two options: use #JsonTypeInfo annotation or to create custom deserializer. Example:
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
private T myGeneric ;
After that, serialized myGeneric field will look something like that:
"myGeneric" : { "field1" : 1, "field2" : 2, "#class" : "com.project.MySubClass"}
Deserializer will use this info to instantiate an object of correct type

can't deserialize an Object to its original Type using jackson #JsonTypeInfo annotation

im Trying to serialize an object ( from an Enum ) in the client-side of my application and deserialize it in the other side ( server-side ) to the same Object using jackson . i have this enum in my client-side :
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#type")
public enum Request{
Signup,
Login
}
which using the #jsonTypeInfo annotaion of jackson .
and on the server-side im doing this to deserialize the object :
ObjectMapper mapper = new ObjectMapper();
final JsonNode jsonNode;
jsonNode = mapper.readTree(json); //json is the return String from the convertObjectToJson(Request.Signup);
//i get the error on this line
String type = jsonNode.get("#type").asText();
as i've commented in the code above im getting the NullException on the jsonNode.get("#type").asText() while the json is : [ "Request", "Signup" ]
and this is the function that serialize the objects :
public static String convertObjectToJson(Object object) throws IOException {
ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = objectWriter.writeValueAsString(object);
return json;
}
where is the problem ?
Jackson by default will represent java enums as simple strings and for that reason you are unable to deserialize the object
Take a look here, it could help: http://www.baeldung.com/jackson-serialize-enums

Categories