JsonSyntaxException - Expected BEGIN_OBJECT but was BEGIN_ARRAY - java

First of all I know that some other users have already asked a similar question before so you might think this is an duplicated question but it's not.
I want to make a model class to parse GoogleMaps-Direction API response from JSON format to java object.
The main goal is to make a custom request object using volley library so that I can consume the web service and having the response automatically converted into a Java object.
As you can see in the following screenshot the json response is formed by three root elements. The first two are arrays, at least, as far as I know the [] symbols are used to represent an array in JSON and the third one is just a string value.
So in the model class I'm trying to do the following, declaring some attributes to represent those elements in the JSON response.
Finally I created a new android studio project to test this application. You can see the code of the custom request as well.
However when I run the app I always get an exception that says:
I can understand the meaning of that message but I can't completely understand why this happens. The exception message points to the line number 16 in the response. I have tried using the JSONArray and JSONObject classes getting the same result

The thing is, GSON tries to find the geocodedWaypoints object in the JSON string and when it does, it tries to parse its value to an instance of JSONArray. But then again, JSONArray is an object itself and also expects an identifier. Hence, to use an array as a value, you ought to use the regular array type, e.g. String[].
Change the GoogleMapsResponse class to:
public class GoogleMapsResponse {
private GeocodedWaypoint[] geocodedWaypoints;
private Route[] routes;
private String status;
}
And create classes for all other objects:
public class GeocodedWaypoint {
private String geocoderStatus;
private boolean partialMatch;
private String placeId;
private String[] types;
}
etc.

Related

Convert Spring webclient error response body from string to object

In this method the msg variable is returning in string format..how can be conversion of it can be taken place into certain java pojo object.
Method image
In place of Mono I tried Mono but it didnt worked for me.
I just want to get the error response body in pojo object format rather then in string format.
Also tried in this manner, but no success.
Tried in this manner
do you know what class the response is in case of an error? ResponseEntity perhaps?
you need to use a JSON converter package to convert it into a POJO, but you first need to make a POJO class of your own with the relevant fields (and make sure to name them in case sensitive manner).
then, inside the .flatMap(...) turn the String into the POJO using the converter.

WebClient does not return a "valid" list of Strings

I have a spring boot app that among others, has an endpoint that when hit, returns a list of strings. I also have another spring boot app that hits the first app's endpoint to get the data. The fetch code:
return webClient.get().uri("/sensors/get-cities").headers(httpHeaders -> {
httpHeaders.set("Authorization", auth);
}).retrieve()
.bodyToFlux(String.class).collectList().block();
The above yields a list but with this format when I inspect it in the debbuger, "["city"]". The outer double quotes, I get them because it's a string but the brackets and the inside double quotes, I do not. I tried replacing these characters but I had no luck with the brackets (tried regex). It is like they are not there, but at the same time they are. I am confused at this point. But I think that the behavior of the fetch code is not normal, it should yield a valid array of strings.
What you are probably getting (im guessing here) is a response body that looks something like this:
[
"New York",
"Madrid",
"London"
]
You then tell webflux that you want to convert the body to a Flux of String by calling bodyToFlux(String.class).
So the framework takes the entire response and makes a string out of it
// A string of the entire array (im escaping the quotation marks)
"[\"New York\",\"Madrid\",\"London\"]"
And then the framework will throw the entire thing into a Flux which means it takes the first position in the Flux. You then emit all the values into a List by calling collectList The equivalent code is sort of:
List<String> oneString = Flux.just("[\"New York\",\"Madrid\",\"London\"]")
.collectList()
.block();
So you get a list, with one string in it, which is the entire body.
What you probably want to do is to get a list out if it. And this is one way to do it:
List<String> strings = webClient.get()
.uri("/sensors/get-cities")
.headers(httpHeaders -> {
httpHeaders.set("Authorization", auth);
})
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<String>>() {})
.block();
Spring explains ParameterizedTypeReference:
The purpose of this class is to enable capturing and passing a generic Type. In order to capture the generic type and retain it at runtime
So its sort of a class that makes sure we can use generic types like List<T> and helps us with type information.
So what we do is that we now take the response and tell the framework that the body is a list of strings directly. We dont need to do collectList anymore as the framework will stick it in a list for us. We then call block to wait in the response.
Your Springboot API returns result as parsed to JSON (this is default behavior). So it first builds a list of Strings (in your case just a single String "city" and than serializes it to Json. In this case since it is a list it serializes it to JSON array as opposed to JSON Object. Read about JSON here. So in your second Springboot app that hits the API from the first one should assume that you are getting JSON which you need to parse to get your list. To parse it you can use readValue() method of ObjectMapper class of Json Jackson library which is a default JSON library in Springboot. your code would be
List<String> myList;
ObjectMapper = new ObjectMapper();
//Add setters for ObjectMapper configuration here if you want a specific config
try {
myList = objectMapper.readValue(myJsonString, List.class);
} catch(IOException ioe) {
...
}
In addition I wrote my own Open-source library called MgntUtils, that includes JsonUtils class which is a thin wrapper over Json Jackson library. It provides just Json parser and serializer, but in many cases that is all you need. With my library you would only need one dependency as oppose to Jackson, and JsonUtils class just have 4 methods, so by far easier to understand. But in your case if you use my library the code would be very similar to the above code. It would be something like this:
List<String> myList;
try {
myList = JsonUtils.readObjectFromJsonString(myJsonString, List.class);
} catch(IOException ioe) {
...
}
Note that in this case you won't have to instantiate and configure ObjectMapper instance as readObjectFromJsonString is a static method. Anyway if you are interested in using my library you can find maven artifacts here and The library itself with source code and javadoc is on Github here. Javadoc for JsonUtils class is here

Why does the object fieldname change to the JSON fieldname when the name of the latter is different?

I am building a webapp with java/spring on the backend and angular 2+ on the frontend. I have just discovered something very very strange. I have an object called AffiliateLinkDTO that is send from the java application to the angular application. When received the JSON is serialized into an AffiliateLinkDTO on the frontend side. Both classes are supposed to be an exact mirror image of each other. To be thourough here are the codes of both classes.
AffiliateLinkDTO on frontend side:
export class AffiliateLinkDTO {
constructor(
public id?:number,
public affiliateLinkUrl?: string,
public localizedStoreFront?: string,
public sellerShipsAbroad?:boolean){}
}
AffiliateLinkDTO on backend side:
public class AffiliateLinkDTO {
private Long id;
private String affiliateLinkUrl;
private LocalizedStorefront localizedStorefront;
private boolean sellerShipsAbroad;
}
As you can see both are an exact image of one another except for a minor detail, the F of localizedStorefront on the backend is not capitalized like its counterpart on the frontend. Strangely this does not result in an error on the frontside but it gets even weirder.
When on the frontend i printout the field affiliateLinkDTO.localizedStoreFront of the AffiliateLinkDTO instance it prints out undefined but when i print out affiliateLinkDTO.localizedStorefront (with a small f) it prints out the value! How is this possible when the field localizedStorefront does not exist on the AffiliateLinkDTO on the frontend??? Even though the class AffiliateLinkDTO is used for instanciating the object the fieldname miraculously changes to localizedStorefront. Can anyone give me an explanation please? I'm really puzzled about this. Thank you.
PS: The JSON is not parsed to an AffiliateLinkDTO manually, i am using HttpClient to make a get request to the backend, and the JSON is parsed automatically to AffiliateLinkDTO
EDIT: What i saw was caused by a bug in visual studio, i rechecked to see if i could reproduce what i saw yesterday but i couldn't this time i've gotten a compiler error.
I assume that you're doing something like this to create your AffiliateLinkDTO instance from the JSON:
let dto = new AffiliateLinkDTO();
let obj = JSON.parse(receivedJson);
for(let attr in obj){
dto[attr] = obj[attr];
}
In that case localizedStoreFront is undefined because it's never set, because the received JSON only contains an attribute called localizedStorefront and not localizedStoreFront.
You have two options to solve this:
Change the attribute name on the backend class
or
Add a guard during the instantiation on the frontend to assign the value to localizedStoreFront and not to localizedStorefront
Maurice, when you make an httpClient.get< Interface>(...) Angular NOT check the value you received. You received you get. the idea of using < Interface> is to help you when write code. If you want you can "map" the response like
getAffiliateLinkDTO(id:number):Observable<AffiliateLinkDTO>
{
return this.httpClient<AffiliateLinkDTO>.get(".....").pipe(
map(res=>{
return {
id:res.id,
affiliateLinkUrl:res.affiliateLinkUrl,
LocalizedStoreFront:res.localizedStorefront,
sellerShipsAbroad:res.sellerShipsAbroad
}
})
)
}

Is there some way for a Jackson Delegate-based Creator to access the raw Json String?

Is there some way for a Jackson Delegate-based creator to access the raw Json String?
#JsonCreator
private static MyClass createFromJson(Map<String, Object> jsonProperties) {
return new MyClass(rawJson);
}
I am able to get the raw input as a Map of Strings to Objects in the code above, but I want to be able to access the json as a string. I tried the code below (based off of http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html) but that code as written is never invoked.
#JsonCreator
private static MyClass createFromJson(String rawJson) {
return new MyClass(rawJson);
}
Note: This is a spring boot application (1.3.1.RELEASE) that uses Jackson 2.6.4.
Looks like this type of functionality would not make sense in this context. In fact, it appears to me now that requesting the JSON string in this instance defeats the purpose of using jackson in the first place. However if anyone finds themselves here, then the comments from Sotirios Delimanolis may be useful:
"Hack: you can receive a JsonNode as the parameter type and use its toString method to get the corresponding JSON."
"It looks like you want a JsonDeserializer"

Is case important while parsing JSON using GSON

I am parsing JSON data, and storing the results in a Java object using GSON. My question is, should the fields in the JSON String match the instance variables in the class? Including the class names? For eg,
If this is my JSON string -
"telephone":
{
"landline":"1-818-502 8310"
}
Should I have a class as below?
public class Telephone
{
private String landline;
}
The reason why I am asking this is, when I use gson's fromJson(obj), the object doesn't contain any values. It shows all records as null. I am wondering if it is throwing the error due to this.
Please note - This is not the entire code. My JSON data is quite huge, so I can't paste it here. The above telephone string is just one of the many embedded strings within my json string.
This is wrong JSON:
"telephone":{"landline":"1-818-502 8310"}
The JSON objects start with a { and end with a }. SO, it should be something like
{"name": "somename", "telephone":{"landline":"1-818-502 8310"}, ...}
Yes. Attributes in class should have exact same case and character as in the JSON String in case you are using default Gson instance as correctly mentioned by Eliran. Please note that you must have attributes just having getter/setter and not attribute wouldn't work.
You mentioned you are using inner class. It may not work with default Gson instance. You may need to use registerTypeAdapter like this:
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());
refer: https://sites.google.com/site/gson/gson-user-guide#TOC-Custom-Serialization-and-Deserialization

Categories