The api returns both an object and an array - arrays

I'm new to json, there was a problem and I couldn't find a solution
I was given an api and when executing a get request, I get some object, but if there is no data in the object, an array is returned.
At the moment I was able to get Any?, instead of JSONArray or JSONObject, but there was a problem with converting Any? to the class
How to convert data to kotlin data class correctly?
returned object
returned array
The class I'm converting the json request to:
data class ProductInfo (var product:Product?,var specifications: JsonObject?,var supplements: Any?,var files:List<File>?,var feedback: Feedback?)

This seems something that the backend has to solve for you. They can give you a nullable array or just an empty array, whatever is more convenient, but implementing polymorphism is not something trivial.
Jackson makes polymorphism easier than Gson, however, it is always required some kind of anchor to know how to route the parsing, in this case, you don't have any.
Jackson uses an annotation and there you have indicate in which thing is going to pivot:
#JsonSubTypes.Type(value = Nothing.class, name = "????")
With Gson you have to implement your own JsonDeserializer but again, how do you know what type is it? If it can be cast to array then is nothing? Just writing that seems like an antipattern.

Related

Can't access nested JSON Api data: no implicit conversion of String into Integer

Wondering if you could help. I am trying to access all the nested first_names from this API inside of elements:
https://fantasy.premierleague.com/api/bootstrap-static/
Here's my controller code:
def index
require 'net/http'
require 'json'
url = 'https://fantasy.premierleague.com/api/bootstrap-static/'
uri = URI(url)
response = Net::HTTP.get(uri)
object = JSON.parse(response)
#testy = object["elements"]["first_name"]
end
I am able to access all the data inside of elements just fine, but when I add ["first_name"], I get the error: no implicit conversion of String into Integer
Seems a bit weird? Surely it should just pull in whatever is inside of "first_name", whether it's an integer, string etc?
Thanks
It's not the least bit strange.
object["elements"] is an array and when you call the [] method on a array the argument is coerced into an integer as its used to access array elements by index:
irb(main):052:0> []["foo"]
(irb):52:in `[]': no implicit conversion of String into Integer (TypeError)
Surely it should just pull in whatever is inside of "first_name", whether it's an integer, string etc?
In other languages like JavaScript you would just get null instead because what you expect to be a single object is actually an array.
Do yourself a big favor and move the HTTP call and JSON processing out of the controller and into a separate component that you can test in isolation. It will make it a lot easier to spot simple issues like this.

How to loop through and edit a JsonArray of objects in Scala

I have a variable descriptions that is an Option[JsonArray] (JsonArray results from calling getJsonArray on a JsonObject). descriptions is a list of objects that I'm getting back as a response from a server. Each object has a structure like so:
{age: String,
number: Long,
link: String}
I'd like to loop through this JsonArray and edit the link field to a certain value that is returned from a function. I don't even need to edit it in place and can take a new array of objects. In JS, it might be as simple as descriptions.map(d => ({...d, link: someValue})) but I'm not sure how I need to transform the JsonArray to get this working in Scala. Any help is appreciated!
#mysl didn't provide necessary details as mentioned in the comments. So I'm going to speculate that the approach you've proposed didn't work and you want to understand why.
Most probably you've assumed that JsonArray would be mutated when you .map a lambda over it (which is the case for Javascript I guess). That's not true in Scala case. I.e. when you map a list over you've got another list. I.e. .map, as the name assumes, is just a way to map one collection to another.
So what you need to do is:
val originalJsonArray = ...
val updatedJsonArray = originalJsonArray.map { description =>
description.copy(link = description.link.replace("foo","bar"))
}
println(s"originalJsonArray=$originalJsonArray, updatedJsonArray=$updatedJsonArray")
I hope that helps, though I'm not sure I guessed your problem correctly.

Kotlin JSONArray to MutableList<JSONObject>

I am fairly new to Kotlin and I am currently dealing with JSON a lot.
I receive a JSON string from the server which I parse into JSONArray as below
var dataArray = JSONArray(String(resultVar!!))
But as far as I've seen JSONArray doesn't really give me enough capabilities to change it's data, it forces me to create a new JSONArray, if I'm not mistaken. So I thought I should use MutableList<JSONObject>, which seems good enough, but I can't find a way to parse JSONArray or the String into it.
How do I do this the easy way? Do I have to iterate through the JSONArray adding every single JSONObject one by one?
As a side question, should I just stick to JSONArray? Is there a way to manipulate the data inside it?
As far as it seems, there is no builtin method to convert JSONArray to List.
However, You can use Kotlin tricks to make the java code much shorter:
fun JSONArray.toMutableList(): MutableList<JSONObject> = MutableList(length(), this::getJSONObject)
Note that JSONArray may have values that are not JSONObject (but JSONArray for example). If you are not sure the array contains just object, use the following method:
fun JSONArray.toMutableList(): MutableList<Any> = MutableList(length(), this::get)
If you are using the JSON-java library and not the android one, then you can use JSONArray.toList() which returns a list you can modify.

What is the difference between a model object queried by filter and an object queried by get() in Django?

I keep coming across this issue where I am trying to update a record using the update() method.
It always works when I query an object using filter.
my_dictionary = {"key":"Val","another":"Val"}
thing = Thing.objects.filter(pk=1)
thing[0].update(**my_dictionary) wrote it wrong in the original question.
thing.update(**my_dictionary)
When I query the object using get() it keeps telling me that the object has no method update()
my_dictionary = {"key":"Val","another":"Val"}
thing = Thing.objects.get(pk=1)
thing.update(**my_dictionary)
Isn't a model object the same in both cases? Why would one have an update method and the other one not? Any insight would be greatly appreciated.
The documentation is very explicit about this:
filter() will always give you a QuerySet, even if only a single object matches the query - in this case, it will be a QuerySet containing a single element.
If you know there is only one object that matches your query, you can use the get() method on a Manager which returns the object directly.
Your first snippet returns a QuerySet, which has an update method. The second snippet returns a model instance, which doesn't.
Note that you have not shown the exact code you are using: thing[0].update would give exactly the same error as the second snippet.
You're using QuerySet.update() and ModelInstance.save().
If you’re just updating a record and don’t need to do anything with the model object, the most efficient approach is to call update(), rather than loading the model object into memory. For example, instead of doing this:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
...do this:
Entry.objects.filter(id=10).update(comments_on=False)

Map as return type of #MatrixParameter

The Rest-api we are building we need some sort of filtering system to prevent too much (useless) data to be transfered to our client. The use of #MatrixParameter seems like a nice solution since this allows a readable way to filter on multiple 'levels' of the URI
However in our api we have fields our clients would like to filter on which are not defined on compile time (and can be different per client). This makes is infeasable to speficy these fields on the #matrixParam annotation.
So i was hoping there would be some way to use a Map as receiving 'bean' object
ie: when i do a GET on
https://api.example.com/rest/filtered_get;param1=value1;param2=value2/optional/continuation/of/uri/
would end up with in map containing param1,param2 as keys and value1 and value2 as values
#Get()
#Path("filtered_get")
public Response getter(#matrixParam("") HashMap<String, String/Object>parameters) {
//doStuffWiththeParameters;
}
The Service is being implemented with cxf
I think i have this figured out.
The trick is to use the PathSegment variable
usinge the code like so:
#Path("/filter{reference_to_pathParam}")
public RestEntityService<T> search(#PathParam("reference_to_pathParam") PathSegment p) {
MultiValuedMap<String,String> matrix = p.getMatrixParameters();
// doStuff with the matrix parameters
}
allows you to use unspecified matrix parameters in your URI like:
https://api.example.com/rest/../filter;field=value;field2=value2/rest/of/the/URI/
and get those fields in the matrix (map)
Note that i'm using a explicit pathsegment for this filter. This is because if i would use something like #path("/{filter}") as annotation it would interfere with other selectors using pathparameters.
Not marking this as answer yet because i dont know if there might be better/cleaner ways to do this.

Resources