json parsing with jackson - java

I am using the Jackson library for conversion of a JSON string to Java objects
My json is:
{
"human":{
"fname":"anjali",
"lname":"malhotra"
}
}
I want this to be converted into a Java class with following structure:
public class Human
{
String fname;
String lname;
}
I can successfully convert it into
public class HumanWrapper
{
Human human;
}
But, I wanted to know if there is a way I can directly convert it into the Human format. I read about custom deserialization but was reluctant for that approach.

You could achieve this by configuring ObjectMapper to use DeserializationFeature.UNWRAP_ROOT_VALUE :
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
and annotatating your Human class with #JsonRootName annotation :
#JsonRootName("human")
public class Human {
....
}

You need to have a HumanWrapper class as your human object is defined inside you json object
{
"human": {
}
}
If you able to change you API to send just a human object like this
{
"fname":"anjali",
"lname":"malhotra"
}
Then you woudn't be bothering to have a HumanWrapper

Related

How to deserialize JSON file starting with an array in Jackson - with Annotations only?

I have a Json response that looks like this:
[
{ "name":"A" },
{ "name":"B" }
]
I have Java classes representing a single ResponseDto and contains a List of Person:
public class GetPersonsResponseDto {
public List<Person> persons;
}
public class Person {
public String name;
}
I would like to deserialize the by JSON using ObjectMapper but without use of a custom Deserializer and without collection type (no Persons[].class or TypeReference<List<Person>>(){}). What I really want is
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(in, GetPersonsResponseDto.class);
But I get:
jackson.map.JsonMappingException:
Can not deserialize instance of com.project.my.GetPersonsResponseDto out of START_ARRAY token
I tried several Annotations but without success.
Actually it is quite simple to serialize your models to the target json, but might be tricky to deserialize.
So, the solution for deserialization in this case could be using #JsonCreator annotation from com.fasterxml.jackson.annotation package above constructor:
#Data
public class GetPersonsReponseDto {
public List<Person> persons;
#JsonCreator // use this annotation for deserialization on constructor
public GetPersonsReponseDto(List<Person> persons) {
this.persons = persons;
}
public GetPersonsReponseDto() {
}
}
However, it might not work with some versions of jackson.

How deserialize json object array as array of json strings?

Consider json input:
{
companies: [
{
"id": 1,
"name": "name1"
},
{
"id": 1,
"name": "name1"
}
],
nextPage: 2
}
How deserialize this into class:
public class MyClass {
List<String> companies;
Integer nextPage;
}
Where List<String> companies; consists of strings:
{"id": 1,"name": "name1"}
{"id": 1,"name": "name1"}
#JsonRawValue doesn't work for List<String> companies;
Is there a way to configure Jackson serialization to keep companies array with raw json string with annotations only? (E.g. without writing custom deserializator)
There is no annotation-only solution for your problem. Somehow you have to convert JSON Object to java.lang.String and you need to specify that conversion.
You can:
Write custom deserializer which is probably most obvious solution but forbidden in question.
Register custom com.fasterxml.jackson.databind.deser.DeserializationProblemHandler and handle com.fasterxml.jackson.databind.exc.MismatchedInputException situation in more sophisticated way.
Implement com.fasterxml.jackson.databind.util.Converter interface and convert JsonNode to String. It is semi-annotational way to solve a problem but we do not implement the worst part - deserialisation.
Let's go to point 2. right away.
2. DeserializationProblemHandler
Solution is pretty simple:
ObjectMapper mapper = new ObjectMapper();
mapper.addHandler(new DeserializationProblemHandler() {
#Override
public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg) throws IOException {
if (targetType.getRawClass() == String.class) {
// read as tree and convert to String
return p.readValueAsTree().toString();
}
return super.handleUnexpectedToken(ctxt, targetType, t, p, failureMsg);
}
});
Read a whole piece of JSON as TreeNode and convert it to String using toString method. Helpfully, toString generates valid JSON. Downside, this solution has a global scope for given ObjectMapper instance.
3. Custom Converter
This solution requires to implement com.fasterxml.jackson.databind.util.Converter interface which converts com.fasterxml.jackson.databind.JsonNode to String:
class JsonNode2StringConverter implements Converter<JsonNode, String> {
#Override
public String convert(JsonNode value) {
return value.toString();
}
#Override
public JavaType getInputType(TypeFactory typeFactory) {
return typeFactory.constructType(new TypeReference<JsonNode>() {
});
}
#Override
public JavaType getOutputType(TypeFactory typeFactory) {
return typeFactory.constructType(new TypeReference<String>() {
});
}
}
and now, you can use annotation like below:
#JsonDeserialize(contentConverter = JsonNode2StringConverter.class)
private List<String> companies;
Solutions 2. and 3. solve this problem almost in the same way - read node and convert it back to JSON, but uses different approaches.
If, you want to avoid deserialising and serialising process you can take a look on solution provided in this article: Deserializing JSON property as String with Jackson and take a look at:
How to serialize JSON with array field to object with String field?
How to get a part of JSON as a plain text using Jackson
How to extract part of the original text from JSON with Jackson?

How can I introduce escape characters to my JSON mapper?

I am trying to make a simple thing using com.fasterxml.jackson.databind.ObjectMapper.
I have an object I want to translate to String.
class Car{
String color;
String brand;
//... more class info
}
It is working fine and I get my String as it should but the result looks like this:
{"color: "blue", "brand": "toyota" }
Is it possible to make it look like:
{\"color\": \"blue\", \"brand\", \"toyota\" }
I'm not sure if this breaks the JSON expected format.
I've read the docs and seems like I can use this:
ObjectMapper().factory.setCharacterEscapes(...)
But I'm not sure how to pass it or from which repo. Any ideas?
Use Jackson to generate valid JSON payload and StringEscapeUtils to escape it.
Example code:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.text.StringEscapeUtils;
public class EscapeJsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Car("blue", "Toyota"));
String escapedJson = StringEscapeUtils.escapeJson(json);
System.out.println(escapedJson);
}
}
class Car {
String color;
String brand;
// getters, setters, constructor
}
Above code prints:
{\"color\":\"blue\",\"brand\":\"Toyota\"}
Maven dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.8</version>
</dependency>
I am basically trying to make a mapper for an sort of inner object to
match a SNS format https://docs.aws.amazon.com/sns/latest/dg/sns-send-custom-platform-specific-payloads-mobile-devices.html
Here's one of the examples from that page:
{
"GCM":"{\"data\":{\"message\":\"Check out these awesome deals!\",\"url\":\"www.amazon.com\"}}"
}
That's a JSON object with a single field named "GCM" whose value is a string. The content of the string is another JSON object.
Let's take your Car class as an example, and assume you want to generate this JSON as your output:
{
"car": "{\"color\": \"blue\", \"brand\": \"toyota\"}"
}
First you'll need to convert your Car object to a JSON string. Then you create another JSON object and stuff the car's JSON string into a field of this outer object:
String carJson = objectMapper.writeValueAsString(myCar);
Map<String, Object> outerObject = singletonMap("car", carJson);
String finalResult = objectMapper.writeValueAsString(outerObject);
I think that you can use something like JSONObject.quote(json):
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Car("blue", "Toyota"));
System.out.println(JSONObject.quote(json));
Output:
"{\"color\": \"blue\", \"brand\", \"toyota\" }"

creating nested Json in Java

Im trying to get the Json inside Json response of the rest api.
httpsConn.getInputStream() will be a Json like
"data":[
{"id":"1","name:"aaa","score":"90"},{"id":"2","name":"bbb","score":"85"}
]
Jave code:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
response = (MarkResponse)objectMapper.readValue(httpsConn.getInputStream(), MarkResponse.class);
Pojo class:
public class MarkResponse {
private int count;
private List<MarkData> markData;
//setter and getter.
}
public class MarkData {
private String id;
private String name;
}
The response is like below, as I'm using the List inside my main pojo.
{"headers":{},"body":"MarkResponse [count=2 markData=[MarkData [id=1,
name=aaa], MarkData
[id=2,name=bbb]]],"statusCode":"ACCEPTED","statusCodeValue":202}
What I'm expecting is,
{"headers":{},"body":"MarkResponse [count=2
markData={"id":"1","name:"aaa"},{"id":"2","name":"bbb"}],"statusCode":"ACCEPTED","statusCodeValue":202}
What is the code change i should make to get the expected output.
I think the problem is private fields. When I make fields public, jackson works and I don't need to objectMapper.disable(anything); when fields are private, or protected, or package-private, they are read, but not written to.
That is, assuming that you try to use org.codehaus.jackson.map.ObjectMapper (yes, not the latest version) rather than something else that defines a class named ObjectMapper.
This works after changing the return type.
My earlier response was,
public ResponseEntity<String> fnCall() {
//code here
return new ResponseEntity<String>(MarkResponse.toString(), HttpStatus.ACCEPTED);
}
I changed this to make it work.
public MarkResponse fnCall() {
//code here
return response;
}

How to get java objects from JSONArray url using Jackson in Android

This is my JSON from URL
https://api.myjson.com/bins/142jr
[
{
"serviceNo":"SR0000000001",
"serDate":"17",
"serMonth":"DEC",
"serYear":"2015",
"serTime":"02.30 AM",
"serApartmentName":"Galaxy Apartments"
},
{
"serviceNo":"SR0000000002",
"serDate":"19",
"serMonth":"JUN",
"serYear":"2016",
"serTime":"03.30 AM",
"serApartmentName":"The Great Apartments"
}
]
I have one ListView I want populate details from online JSON,above i given a link and sample json anybody given sample jackson code in java
Thanks for advance,
Rajesh Rajendiran
To use jackson you need to create a model class:
[
{
"serviceNo":"SR0000000001",
"serDate":"17",
"serMonth":"DEC",
"serYear":"2015",
"serTime":"02.30 AM",
"serApartmentName":"Galaxy Apartments"
},
{
"serviceNo":"SR0000000002",
"serDate":"19",
"serMonth":"JUN",
"serYear":"2016",
"serTime":"03.30 AM",
"serApartmentName":"The Great Apartments"
}
]
For the above the json the model class would be:
public class SomeClass {
private String serviceNo;
private String serDate;
private String serMonth;
private String serYear;
private String serTime;
private String serApartmentName;
#JsonProperty("serviceNo") //to bind it to serviceNo attribute of the json string
public String getServiceNo() {
return serviceNo;
}
public void setServiceNo(String sNo) { //#JsonProperty need not be specified again
serviceNo = sNo;
}
//create getter setters like above for all the properties.
//if you want to avoid a key-value from getting parsed use #JsonIgnore annotation
}
Now whenever you have the above json as string stored in a variable say jsonString use the following code to parse it:
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
ArrayList<SomeClass> results = mapper.readValue(jsonString,
new TypeReference<ArrayList<ResultValue>>() { } );
results should now contain two SomeClass objects having the above json parsed as respective objects.
PS: Its been a long time since I have used Jackson for parsing so this code might need some improvements.
If you are getting this as http response then I would suggest to use spring rest template for android.
It has support for Message Converters. That way the onus of marshaling and unmarshalling.
[Update]
Here is a blog for the same :http://www.journaldev.com/2552/spring-restful-web-service-example-with-json-jackson-and-client-program
Refer Docs for more details:
http://docs.spring.io/spring-android/docs/current/reference/html/rest-template.html

Categories

Resources