Parse JSON file with Java - java

I am trying to parse a JSON file in Java. But the format of the JSON file is complex (at least for me) and hence I have run into a roadblock.
You may read the file-
Reddit JSON file
Within the "reddit" file, the 'key' I am interested in is "body" which is nested deep within the JSON array within the file.
I am using Jackson for parsing and deserialization of the JSON to a Java object and my code is as follows-
class Reddit
{
private String kind;
private String data;
public String getData()
{
return this.data;
}
public void setData(String data)
{
this.data = data;
}
public String getKind()
{
return this.data;
}
public void setKind(String data)
{
this.data = data;
}
}
public class Attempting_Read_JSON
{
public static void main(String[] args)
{
// ObjectMapper can parse JSON into Java Objects, can do vice-versa and more-
ObjectMapper OM = new ObjectMapper();
try
{
out.println("\nInside try block.\n");
File json_file = new File("src/main/resources/data/reddit/redditdump.json");
Reddit[] R = OM.readValue(json_file, Reddit[].class);
out.println("\nRead from JSON file to 'Reddit class object'\n");
//out.println("\nObtained JSON- " + R.getData());
}
catch (Exception E)
{
E.printStackTrace();
}
out.println("\n\nProgram terminated successfully!\n");
}
}
But on executing the program, it keeps giving me errors.
Any suggestions on how I might get the value associated with the key- 'body'?
Thanks!

In your JSON file "data": is an object and you are trying to assign to String in Reddit class through private String data;.
That's why you are getting this error.
You either need to create a class say Data with members contest_mode, banned_by.... or use JSON Object to parse it.
Also why are you setting data here use kind
public String getKind()
{
return this.data;
}
public void setKind(String data)
{
this.data = data;
}
EDIT:
For simplicity I will give you small example:
JSON file:
[
{
"kind": "Listing",
"data": {
"contest_mode": false
}
},
{
"kind": "Listing",
"data": {
"contest_mode": false
}
}
]
Your code:
public class Attempting_Read_JSON {
public static void main(String[] args) {
ObjectMapper OM = new ObjectMapper();
try {
out.println("\nInside try block.\n");
File json_file = new File(
"src/main/resources/data/reddit/redditdump.json");
Reddit[] R = OM.readValue(json_file, Reddit[].class);
out.println("\nRead from JSON file to 'Reddit class object'\n" + R[0].toString());
// out.println("\nObtained JSON- " + R.getData());
} catch (Exception E) {
E.printStackTrace();
}
out.println("\n\nProgram terminated successfully!\n");
}
}
class Reddit {
private String kind;
#Override
public String toString() {
return "Reddit [kind=" + kind + ", data=" + data.toString() + "]";
}
private Data data;
public Data getData() {
return this.data;
}
public void setData(Data data) {
this.data = data;
}
public String getKind() {
return this.kind;
}
public void setKind(String kind) {
this.kind = kind;
}
}
class Data
{
boolean contest_mode;
public boolean isContest_mode() {
return contest_mode;
}
public void setContest_mode(boolean contest_mode) {
this.contest_mode = contest_mode;
}
#Override
public String toString() {
return "[contest_mode=" + contest_mode + "]";
}
}

Related

Spring Boot Controller return generic types (A or B)

I develop simple todo-list application with spring boot. And I wanna send common response dto from all request. The data filed in ReponseMessage is Generic because it can be various type.
public class ResponseMessage<T> {
private int statusCode = HttpStatus.OK.value();
private String message = "";
protected T data; // this is generic. it can be many response dto.
public static ResponseMessage<String> ok() {
return new ResponseMessage<>("");
}
public static <T> ResponseMessage<T> ok(T data) {
return new ResponseMessage<>(data);
}
public static ResponseMessage<Object> noContent() {
return new ResponseMessage<>(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase(), "");
}
protected ResponseMessage(T data) {
this.data = data;
}
private ResponseMessage(int statusCode, String message, T data) {
this.statusCode = statusCode;
this.message = message;
this.data = data;
}
protected ResponseMessage() {}
public int getStatusCode() {
return statusCode;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
}
Now i need to make a feature that find a recend todo.
If todo exists, send ResponseMessage.
{
"statusCode": 200,
"message": "",
"data": [
{
"id": 1,
"title": "test",
"status": "TODO"
}
]
}
If todo doesn't exist, send ResponseMessage.
{
"statusCode": 200,
"message": "",
"data": []
}
Now my controller function return like this.
public ResponseMessage<?> findRecent(#AuthenticationPrincipal LoginUser user) {
Optional<TodoResponse> todo = todoService.findRecent(user.getId());
return todo.isPresent() ? ResponseMessage.ok(todo.get()) : ResponseMessage.noContent();
}
I know that the question mark '?' is not good. so what is better way to return A or B in this case? plz help me.
If you set noContent().data to null, you can safely assign it any type:
public static <T> ResponseMessage<T> noContent() {
return new ResponseMessage<>(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase(), null);
}
Also note that calling Optional.isPresent() and then get() is something of an antipattern. In your case, you can simplify it to this:
return todoService.findRecent(user.getId())
.map(ResponseMessage::ok)
.orElseGet(ResponseMessage::noContent);

Retrofit Response Array or Object either

In the first case when it returns success true, everything works, the problem when it gets success boolean is false, then the error:
How Retrofit Response Array or Object either.
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 26 path $ .data
Can it be done with one reponse class?
Json response:
{
"success": true,
"data": {
"message": "User created",
}
}
Json response:
{
"success": false,
"data": [
{
"code": "existing_user_login",
"message": "User Exist !"
}
]
}
Code:
public class Response {
public Boolean success;
public Data data;
public Boolean isSuccess() { return success; }
public Data getData() {
return data;
}
public class Data {
public String code;
public String message;
public String getMessage() { return message; }
public String getCode() { return code; }
}
}
you could use Object data first, and judge it before use it, like following:
public class Response {
public Boolean success;
public Object data;
public Boolean isSuccess() { return success; }
public Object getData() {
if(data instanceof Data){
//do something
}else if (data instanceof List) {
//do something
}else {
//do something
}
return data;
}
public class Data {
public String code;
public String message;
public String getMessage() { return message; }
public String getCode() { return code; }
}
}
Using ObjectMapper you can do it by configuring deserialization features as below:
// import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper objMapper = new ObjectMapper();
// this is to accept single element as array
objMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
// this is to handle if any property is missing
objMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Response resp = objMapper.readValue(jsonString, Response.class);

Getting nested array from JSON using Jackson lib - Java

I've got a JSON like this:
{
"result": [
{
"reservation_id": 101,
"euro_fee": 11.00,
"hotel_id": 1
},
{
"reservation_id": 102,
"euro_fee": 12.00,
"hotel_id": 2
},
{
"reservation_id": 103,
"euro_fee": 13.00,
"hotel_id": 3
}
],
"meta": {
"ruid": "0001="
}
}
and I'm trying to use Jackson (with Spring Boot) for parse and bind it. Here is my POJO's:
Response.java
public class Response {
private Result result;
private Meta meta;
public Response() {
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
}
Meta.java
public class Meta {
private String ruid;
public Meta() {
}
public String getRuid() {
return ruid;
}
public void setRuid(String ruid) {
this.ruid = ruid;
}
}
Result.java
public class Result {
private Booking[] results;
public Result() {
}
public Booking[] getResults() {
return results;
}
public void setResult(Booking[] results) {
this.results = results;
}
}
Booking.java
public class Booking {
private long reservation_id;
private long hotel_id;
private Double euro_fee;
public Booking() {
}
public long getReservation_id() {
return reservation_id;
}
public void setReservation_id(long reservation_id) {
this.reservation_id = reservation_id;
}
public long getHotel_id() {
return hotel_id;
}
public void setHotel_id(long hotel_id) {
this.hotel_id = hotel_id;
}
public Double getEuro_fee() {
return euro_fee;
}
public void setEuro_fee(Double euro_fee) {
this.euro_fee = euro_fee;
}
}
I can get ruid from meta using:
// getting JSON from REST
String response = restTemplate.postForObject(resourceURL, httpEntity, String.class);
// use jackson
ObjectMapper mapper = new ObjectMapper();
Response theResponse = mapper.readValue(response, Response.class);
System.out.println("getRuid: " + theResponse.getMeta().getRuid());
but I can't get objects or single item from nested array. When I'm trying to get array of items I'm getting error:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of out of START_ARRAY token at [Source: (String)...
I know this one should be easy, but I'm using Jackson for the first time and the problem might be somewhere in the deep.
Change your Response class.
Try with this:
public class Response {
private List<Booking> result;
private Meta meta;
//getter setter
}

Jackson deserialize an array of object to pojo

So i have this JSON file
{
"results":[
"result":{},
"result":{}
]
}
I wish to deserialize it to a java object which contains an array of result objects.
public class Foo(){
#JsonProperty("results")
private Result[] results;
public void setResults(Result[] results){
this.results = results;
}
public Result[] getResults(){
return this.results;
}
}
public class JsonToObject(){
ObjectMapper mp = new ObjectMapper();
public void createObject(String jsonFile){
Foo bar = mp.readValue(jsonFile, Foo.Class)
}
}
My issue is I keep getting deserialization issues as I have not definied "result".
One way I can get around this is to have result as a class variable inside Result but that seems stupid to do and also may cause issues with re-serializing.
How can I convert the JSON so that my class contains an array of result?
Your question program is wrong. There are many problems with your code. Please use below sample:
public class Foo {
#JsonProperty("results")
private Result[] results;
public Foo() {
}
public Result[] getResults() {
return results;
}
public void setResults(Result[] results) {
this.results = results;
}
}
public class Result {
private String name;
public Result() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mp = new ObjectMapper();
String content = "{\"results\":[{\"name\":\"apple\"},{\"name\":\"lemon\"}]}";
Foo bar = mp.readValue(content, Foo.class);
}

Json To Java Object having Class<?> member variable

public class A {
private Class<?> dataType;
public Class<?> getDataType() {
return dataType;
}
public void setDataType(Class<?> dataType) {
this.dataType = dataType;
}
}
public class B {
public static void main(String[] args) {
try {
File file = new File( "fileName.json");
A a = new ObjectMapper().readValue(file, A.class);
} catch (IOException io) {
io.printStackTrace();
}
}
}
Contents in fileName.json file :
{
"dataType" : "java.lang.String"
}
I got error : org.codehaus.jackson.map.JsonMappingException: Can not access private java.lang.Class() (from class java.lang.Class; failed to set access: Can not make a java.lang.Class constructor accessible.
Is there wrong representation of data in json file, if yes then can any one suggest me what will be correct notation of class A in json file.
I got the solution : We have to use Jackson annotation for this. So rewrite class A.
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
public class A {
private Class<?> dataType;
public Class<?> getDataType() {
return dataType;
}
public void setDataType(Class<?> dataType) {
this.dataType = dataType;
}
#JsonCreator
public A(#JsonProperty("dataType") String dataType)
{
try {
this.dataType = Class.forName(dataType);
} catch (ClassNotFoundException c) {
c.printStackTrace();
}
}
}

Categories

Resources