Why am I getting org.json.JSONException: Not a primitive array? - arrays

I have this function:
fun getFeed(token: String): Result<Array<Post?>, Exception> {
if (token != "") {
val (request, response, result) = "https://alles.cx/api/feed"
.httpGet()
.header("Authorization", token.toString())
.response()
when (result) {
is Result.Success -> {
println("Result success")
try {
val responseJSON = JSONObject(String(response.data))
if (!responseJSON.has("err")) {
println("Has no error")
var feedArray = arrayOfNulls<Post>(0)
println("HERE?")
var feed = JSONArray(responseJSON["feed"]) // <-----ERROR HERE
println("not here")
println("Made to the for")
for (i in 0 until feed.length()) {
println("For $i")
val jsonObject = feed.getJSONObject(i)
var imageURL: URL? = null
if (jsonObject.has("image")) {
imageURL = URL(jsonObject["image"].toString())
}
feedArray[i] = Post(
jsonObject.getString("id"),
User(jsonObject.getJSONObject("author").getString("id"), jsonObject.getJSONObject("author").getString("username"), jsonObject.getJSONObject("author").getString("name")),
jsonObject.getString("createdAt"),
jsonObject.getInt("replyCount"),
jsonObject.getInt("score"),
jsonObject.getString("content"),
null,
imageURL,
jsonObject.getInt("vote")
)
println("Added post $i")
}
println(feedArray)
return Result.Success(feedArray)
}
else {
println("yes error")
return Result.Failure(Exception(responseJSON["err"].toString()))
}
}
catch(e: Exception) {
return Result.Failure(e)
}
}
is Result.Failure -> {
return Result.Failure(Exception(result.component2()?.localizedMessage))
}
}
}
else {
return Result.Failure(Exception("badAuth"))
}
}
An error is occurring on this line. I know this because of the print statements that are in the code:
var feed = JSONArray(responseJSON["feed"]) // <-----ERROR HERE
This is what the error that is occurring is.
[Failure: org.json.JSONException: Not a primitive array: class org.json.JSONArray]
This is what the feed object from the get request will look like, just so you have an idea of what it is:
{
"feed": [
{
"type": "post",
"slug": "equ2ZfaX2UThtkS8DzkXdc",
"author": {
"id": "00000000-0000-0000-0000-000000000000",
"name": "Archie",
"username": "archie",
"plus": true
},
"content": "I know it's quite inactive here atm. But I'm doing tons of stuff behind the scenes - basically rewriting the entire platform from scratch. Micro will be done by the end of the summer.",
"image": null,
"createdAt": "2020-07-30T20:39:23.000Z",
"score": 5,
"vote": 0,
"replyCount": 0,
"hasParent": false
}
]
}
What could possibly be going wrong here. I am using Fuel for the request, but I don't think that is the problem

Pretty sure the correct way to get the array would be to do var feed = responseJSON.getJSONArray("feed"). You're implementation calls the JSONArray(Object o) constructor which is meant to be called only for primitive arrays (int[], double[], etc.) as they cannot be effectively typed using generics). Thus the constructor complains as you pass in an object which is not a primitive array.

Related

Parsing a Multidimensional JSON Array Into Columns in Google Sheets

I am working on a script in Google Sheets to import JSON data via API and need to be able to parse the data into columns in a spreadsheet. The API is returning a multi-dimensional array with a key that is a randomly generated ID.
{
"log":{
"5DUA3NAuET1O7TDhIvmC":{
"log":4440,
"title":"Trade money outgoing",
"timestamp":1649773788,
"category":"Trades",
"data":{
"user":282048,
"trade_id":"[view]",
"money":39562944
},
"params":{
}
}
}
}
How can I
Parse the data into a multidimensional object
Access the values like title, data.cost, etc to be able to import this data to a sheet?
Try
var result = []
function test(){
jsonString = `{
"log":{
"5DUA3NAuET1O7TDhIvmC":{
"log":4440,
"title":"Trade money outgoing",
"timestamp":1649773788,
"category":"Trades",
"data":{
"user":282048,
"trade_id":"[view]",
"money":39562944
},
"params":{
}
}
}
}`
let json= JSON.parse(jsonString.replace(/(\r\n|\n|\r|\t| )/gm,""))
getMyData(json)
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('test').getRange(1,1,result.length,result[0].length).setValues(result)
}
function getMyData(obj) {
for (let p in obj) {
if (obj[p]!=null){
if (typeof obj[p] != 'object' && typeof obj[p] != 'function'){
result.push([p, obj[p]]);
}
if (typeof obj[p] == 'object') {
result.push([p, '']);
getMyData( obj[p] );
}
}
}
}
var response = {
"log": {
"5DUA3NAuET1O7TDhIvmC": {
"log": 4440,
"title": "Trade money outgoing",
"timestamp": 1649773788,
"category": "Trades",
"data": {
"user": 282048,
"trade_id": "[view]",
"money": 39562944
},
"params": { }
}
}
}
var key = Object.keys(response.log)[0];
console.log(key);
var obj = response.log[key];
console.log(obj.title);
console.log(obj.data.user);

I need help getting all the JSON data API provides

Hello can you help me get array of all the data including global_rank, brawlhalla_id, etc.? I am only able to get array of legend like legend_id, legend_key_name. This is the json
{
"name": "bmg | dan",
"brawlhalla_id": 2,
"rating": 1745,
"peak_rating": 1792,
"tier": "Platinum 2",
"wins": 207,
"games": 391,
"region": "US-E",
"global_rank": 5698,
"region_rank": 1644,
"legends": [
{
"legend_id": 4,
"legend_name_key": "cassidy",
"rating": 1736,
"peak_rating": 1792,
"tier": "Platinum 1",
"wins": 161,
"games": 300
},
{
"legend_id": 21,
"legend_name_key": "barraza",
"rating": 1640,
"peak_rating": 1640,
"tier": "Gold 5",
"wins": 41,
"games": 77
}
],
...
My code looks like this:
import SwiftUI
class BrawlhallaSevice {
let url = URL(string: "http://sion.red/brawlhalla/ranked.json")!
func getBrawlhalla(completion: #escaping (Result<[Brawlhalla], Error>) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil else {
completion(.failure(error!))
return
}
completion(.success(self.getBrawlhallaResponse(fromData: data!)))
}.resume()
}
private func getBrawlhallaResponse(fromData data: Data) -> [Brawlhalla] {
let brawlhallaData = try? JSONDecoder().decode(BrawlhallaResponse.self, from: data)
if let brawlhallaD = brawlhallaData {
print(brawlhallaD)
//return brawlhallaD.legends works and returns array of data about a legend
return brawlhallaD
}
return [Brawlhalla(legend_name_key: "Error", rating: 0, peak_rating: 0, tier: "Error")]
}
}
But it throws an error: "Cannot convert return expression of type 'BrawlhallaResponse' to return type '[Brawlhalla]'".
This is how my models look
import Foundation
struct BrawlhallaResponse: Codable {
let legends: [Brawlhalla]
let name: String
let rating: Int
let peak_rating: Int
let tier: String
}
import Foundation
struct Brawlhalla: Codable {
let name: String
let rating: Int
let peak_rating: Int
let tier: String
}
I have tried many changes to the code but nothing seem to work.
I think you got the right code, but it seems like you're trying to return brawhallaD in that if let statement. You're getting the error because your return type is [Brawlhalla], but you're returning a decodedResponse of type BrawlhallaResponse.
So what you can do is this:
class BrawlhallaSevice {
let url = URL(string: "http://sion.red/brawlhalla/ranked.json")!
func getBrawlhalla(completion: #escaping (Result<BrawlhallaResponse?, Error>) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil else {
completion(.failure(error!))
return
}
guard let safeData = data else { return }
completion(.success(self.getBrawlhallaResponse(fromData: safeData)))
}.resume()
}
private func getBrawlhallaResponse(fromData data: Data) -> BrawlhallaResponse?{
let brawlhallaData = try? JSONDecoder().decode(BrawlhallaResponse.self, from: data)
if let brawlhallaD = brawlhallaData {
return brawlhallaD // Will return BrawlhallaResponse.peak_rating and also legends
}
return nil
}
}

How can i set protocol model to multiple known types String / Object?

API JSON Response
1st scene resp:
{
"success": false,
"code": 200,
"response": {
"error_message": "Incorrect email or password."
}
}
2nd scene resp:
{
"success": false,
"code": 200,
"response": {
"error_message": {
"email": [
"Email is empty."
],
"password": [
"Password is empty."
]
}
}
}
My Protocol Model for response
protocol UserLoginResponse {
var id : Int { get }
var success: Bool { get }
var code: Int { get }
var response: UserLoginEntity? { get }
}
My problem is in the protocol below, don't know how to setup multiple types for error_message :
protocol UserLoginEntity {
var error_message: String? { get }
}
Hello you can use "Tuple" as error_message type will solve your problem:
typealias errorMsgType = (String,String)
var error_message: errorMsgType?
error_message = ("Email is empty.","Password is empty.")
print(error_message!)
print(error_message!.0)
print(error_message!.1)
another solution is little trick :
create a one string like:
let error1 = "Email is empty."
let error2 = "Password is empty."
let finalError = [error1,error2].joined(separator: "######")
print(finalError)
let getErrors = finalError.components(separatedBy: "######");
print(getErrors)

Processing error message 'The function getJSONArray(JSONArray) does not exist'

i am not sure why i am getting the error message 'The function getJSONArray(JSONArray) does not exist' when i run this sketch that uses a json query to Weather Underground. That comment seems illogical since Processing is recognising the id ref for the JSONArray.
The .json can be read here: http://api.wunderground.com/api/97a2805510de59e9/hourly/q/pws:IENGLAND274.json
Any thoughts? Thanks.
import com.francisli.processing.http.*;
HttpClient client;
String data;
com.francisli.processing.http.JSONObject weatherInfo;
JSONArray hourly_forecast;
int last = 0;
PImage img;
Float humidity = 50.2;
void setup() {
size(700, 700);
client = new HttpClient(this, "api.wunderground.com");
client.GET("/api/97a2805510de59e9/hourly/q/pws:IENGLAND274.json");
background(255);
}
void responseReceived(HttpRequest request, HttpResponse response) {
println(response.getContentAsString());
weatherInfo = response.getContentAsJSONObject();
JSONArray hourly_forecast = weatherInfo.getJSONArray(hourly_forecast);
}
There is no method called getJSONArray() that takes in a JSONArray as an argument.
The function should be used as JSONArray.getJSONArray(0) which gets the first array of elements in your JSON data. You can put this in a loop to get all of them.
Example (taken from: http://art.buffalo.edu/coursenotes/art380/reference/JSONArray_getJSONArray_.html):
// The following short JSON file called "data.json" is parsed
// in the code below. It must be in the project's "data" folder.
//
// [
// [
// { "name": "apple", "isFruit": true },
// { "name": "grape", "isFruit": true },
// { "name": "carrot", "isFruit": false }
// ],
// [
// { "name": "lettuce", "isFruit": false },
// { "name": "plum", "isFruit": true },
// { "name": "cinnamon", "isFruit": false }
// ]
// ]
JSONArray json;
void setup() {
json = loadJSONArray("data.json");
// Get the first array of elements
JSONArray values = json.getJSONArray(0);
for (int i = 0; i < values.size(); i++) {
JSONObject item = values.getJSONObject(i);
String name = item.getString("name");
boolean isFruit = item.getBoolean("isFruit");
println(name + ", " + isFruit);
}
}
// Sketch prints:
// apple, true
// grape, true
// carrot, false
Second problem with your code is that you're declaring hourly_forecast twice: once globally and once within the responseReceived() function. You probably want to remove JSONArray from hourly_forecast within the responseReceived() function.

Swift - NSDictionary multidimensional

currently i am working on a class which initializes an multidimensional array:
class Manager {
var data: Dictionary<String,NSDictionary>
init(data: Dictionary<String,NSDictionary>) {
func getApiData() {
getApiDataResource() { responseObject, error in
let resourceA = responseObject!
self.data["resources"] = resourceA
}
}
}
}
The responseObject which is returned asyncronously has this structure:
{
"data": [
{
id: 1
name: "Name1"
},
{
id: 2
name: "Name2"
}
],
"count": 2,
"success": true
}
The structure i want to get in my "data"-variable:
{
"resources": [
{
"resourceA":
{
"data": [
{
id: 1
name: "Name1"
},
{
id: 2
name: "Name2"
}
],
"count": 2,
"success": true
}
},
{
"resourceB": // and so on ...
}
]
}
But when saving my responseObject into my "data"-variable:
self.data["resources"] = resourceAData // this line fails
It prints:
Cannot assign to the result of this expression
Anybody could help me with this problem??
Thanks and Greetings!
I assume there is a function defined as follow:
func getApiDataResource(callback: (responseObject:NSDictionary?, error:NSError?) -> ()) {
// data retrieved from server at warp 8 here and other futuristic things
}
Step 1 (required)
I moved the function getApiData outside the init.
class Manager {
var data: Dictionary<String,NSDictionary>
init(data: Dictionary<String,NSDictionary>) {
getApiData()
}
func getApiData() {
getApiDataResource() { responseObject, error in
let resourceA = responseObject!
self.data["resources"] = resourceA
}
}
}
Now the compiler is complaining about this:
Use of self in method call getApiData before all store properties are initialized
and this
Return from initializer without initializing all stored properties
(As stated by you in a comment)
Fine. Let's fix it.
Step 2 (required)
class Manager {
var data: Dictionary<String,NSDictionary>
init(data: Dictionary<String,NSDictionary>) {
self.data = data
getApiData()
}
func getApiData() {
getApiDataResource() { responseObject, error in
let resourceA = responseObject!
self.data["resources"] = resourceA
}
}
}
Now it does compiles properly.
However I would adjust a couple of other things.
Step 3 (suggested)
Inside the trailing closure you are using the !. You should avoid this when possible. And you are not checking the error parameter that could be not nil.
You should use conditional unwrapping that is a safe alternative to the force unwrap (you did with !).
class Manager {
var data: Dictionary<String,NSDictionary>
init(data: Dictionary<String,NSDictionary>) {
self.data = data
getApiData()
}
func getApiData() {
getApiDataResource() { responseObject, error in
if let resourceA = responseObject where error == nil {
self.data["resources"] = resourceA
}
}
}
}
Now the code does not crash if responseObject from the closure is nil.
Step 4 (just a preference)
This is just a style preference.
Swift allows you to define your dictionary this way (as you did).
Dictionary<String,NSDictionary>
or this way:
[String:NSDictionary]
The 2 statement are equivalent. I just find more essential the second one. So...
class Manager {
var data: [String:NSDictionary]
init(data: [String:NSDictionary]) {
self.data = data
getApiData()
}
private func getApiData() {
getApiDataResource() { responseObject, error in
if let resourceA = responseObject where error == nil {
self.data["resources"] = resourceA
}
}
}
}
Let me know is this is what you need!
You have let data: Dictionary<String, Array<String>>, should be var data: Dictionary<String, Array<String>>

Resources