I get an error when I try to save an array that comes from a JSON string. I've tried to use RLMArray with no success.
The error I receive is:
'RLMException', reason: 'Property 'page' is of type 'RLMArray<(null)>' which is not a supported RLMArray object type.
My model class:
public class Project: Object, Mappable {
dynamic var id = 0
dynamic var user: User!
dynamic var page: RLMArray!
dynamic var error_message: String! = ""
dynamic var status: String! = ""
override public static func primaryKey() -> String? {
return "id"
}
required convenience public init?(_ map: Map) {
self.init()
mapping(map)
}
public func mapping(map: Map) {
user <- map["user"]
page <- map["page"]
error_message <- map["error_message"]
status <- map["status"]
}
}
JSON File:
let parameters = [
"user": [
"username": "Marcus",
"password": "123asd"
],
"page": [
"home": [
[
"kind": "navigation",
"title": "suite",
"image": "ic_suite",
"backgroundImage": "ic_background1"
],
[
"kind": "navigation",
"title": "jardim",
"image": "ic_jardim",
"backgroundImage": "ic_background2"
]
],
"suite": [
[
"kind": "button",
"title": "My Master Suite",
"textColor": "0x000000",
"textSize": "16"
]
]
],
"status": "success",
"error_message": ""
]
self.project = Mapper<Project>().map(parameters)
Your class inherits from Object, Realm Swift's base class, but is attempting to use RLMArray, a Realm Objective-C type, in its interface. You cannot mix Realm Swift and Realm Objective-C in this manner. You should use List<T> for array properties when using Realm Swift.
Related
I'm starting to work on a weather app using "openweathermap.org" API, and they provide you with a list of available cities in Json format.
Before i continue with the project, i would like to able to work with the data from this Json file.
The problem is that i get Null whenever i try to read and parse that file.
Here is the code:
Main Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val jsonFileString = getJsonDataFromAsset(applicationContext, "citylist.json")
Log.i("gabs Data", jsonFileString ?: "Empty Data")
val gson = Gson()
val listOfCities = object : TypeToken<List<CityList>>() {}.type
var cities: List<CityList> = gson.fromJson(jsonFileString, listOfCities)
cities.forEachIndexed { idx, city -> Log.i("data", "> Item $idx:\n$city") }
}
}
Utils.kt:
fun getJsonDataFromAsset(context: Context, fileName: String): String? {
val jsonString: String
try {
jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
} catch (ioException: IOException) {
ioException.printStackTrace()
return null
}
return jsonString
}
And the data class (Array of cities data):
class CityList : ArrayList<CityList.CityListItem>(){
data class CityListItem(
#SerializedName("coord")
val coord: Coord,
#SerializedName("country")
val country: String,
#SerializedName("id")
val id: Double,
#SerializedName("name")
val name: String,
#SerializedName("state")
val state: String
) {
data class Coord(
#SerializedName("lat")
val lat: Double,
#SerializedName("lon")
val lon: Double
)
}
}
And the error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.weatherdisplay/com.example.weatherdisplay.ui.activities.MainActivity}: java.lang.NullPointerException: gson.fromJson(jsonFileString, listOfCities) must not be null.
Caused by: java.lang.NullPointerException: gson.fromJson(jsonFileString, listOfCities) must not be null
at com.example.weatherdisplay.ui.activities.MainActivity.onCreate(MainActivity.kt:21)
There were some problems in your code:
You were not closing the BufferedReader
You should not load the file on the Main thread since it will block the UI
I created some sample data corresponding to your data structure:
[
{
"id": 1,
"country": "Germany",
"state": "Saxony",
"name": "Dresden",
"coord": {
"lat": 0.0,
"lon": 0.0
}
},
{
"id": 2,
"country": "Germany",
"state": "Berlin",
"name": "Berlin",
"coord": {
"lat": 0.0,
"lon": 0.0
}
},
{
"id": 3,
"country": "Germany",
"state": "Baden-Wuerttemberg",
"name": "Stuttgart",
"coord": {
"lat": 0.0,
"lon": 0.0
}
},
{
"id": 4,
"country": "Germany",
"state": "Hessen",
"name": "Frankfurth",
"coord": {
"lat": 0.0,
"lon": 0.0
}
},
{
"id": 5,
"country": "Germany",
"state": "Nordrhine-Westphalia",
"name": "Cologne",
"coord": {
"lat": 0.0,
"lon": 0.0
}
}
]
Your activity:
class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "MyApplication"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launchWhenStarted {
launch(Dispatchers.IO) {
var reader: BufferedReader? = null
try {
// Create a reader and read the file contents
reader = assets.open("data.json").bufferedReader()
val rawData = reader.use { it.readText() }
// Create a Type token that Gson knows how to parse the raw data
val cityListType = object : TypeToken<List<City>>() {}.type
// Parse the raw data using Gson
val data: List<City> = Gson().fromJson(rawData, cityListType)
// TODO: Do something with the data
} catch (e: IOException) {
// Handle IOException: Gets thrown when the file wasn't found or something similar
Log.e(TAG, "An error occurred while reading in the data:", e)
} catch (e: JsonParseException) {
// Handle JsonParseException: Gets thrown when there is a problem with the contents of the file
Log.e(TAG, "An error occurred while reading in the data:", e)
}
finally {
// Close the reader to release system resources
reader?.close()
}
}
}
}
}
Your data structure:
data class City(
#SerializedName("id")
val id: Int,
#SerializedName("country")
val country: String,
#SerializedName("state")
val state: String,
#SerializedName("name")
val name: String,
#SerializedName("coord")
val coordinate: Coordinate
) {
override fun toString(): String {
return "#$id[$name $state $country]#[${coordinate.lat}|${coordinate.lon}]"
}
}
data class Coordinate(
#SerializedName("lat")
val lat: Double,
#SerializedName("lon")
val lon: Double
)
In the best case you would put the code in which you get the file contents and parse the data in a ViewModel, but this would to go beyond the scope for this answer.
Additional information about ViewModels: https://developer.android.com/topic/libraries/architecture/viewmodel
I have json like:
{
"member": [
{
"name": "string",
"lastname": "string",
"email": "string",
"address": {
"city": "string",
"country": "string"
}
}
]
}
I parse with the fromGson(google)
Gson().fromJson(jsonString,Member::class.java)
I already have a class to map this json on each field
data class Member(
var name: String,
var lastname: String,
var email: String,
var address: HashMap<String, String>
)
but I have problem to map address, I don't know why
it's only work when json like
"address":
{
"city": "string"
}
it look like I need parse map on json object whos in json object too
array of hashmap didn't work also
Probably you need a wrapper class on the top of member class, try this:
private val jsonString =
"{\"member\": [{ \"name\": \"string\",\"lastname\": \"string\",\"email\": \"string\",\"address\": { \"city\": \"string\",\"country\": \"string\" } }]}"
data class Member(
var name: String,
var lastname: String,
var email: String,
var address: HashMap<String, String>
)
class Response(val member: List<Member>)
fun parse() {
val response = Gson().fromJson(jsonString, Response::class.java)
for (member in response.member){
// do something
}
}
I have Deserialized dynamic Json using Newtonsoft. The JSON is complex and dynamic.
{
"last_updated": " ",
"regions": {
"antarctica": {
"name": "Antarctica",
"totals": [],
"list": [
"aq",
"bv",
"gs",
"tf",
"hm"
]
},
"world": {
"name" : "",
"totals": {
"confirmed": 250566,
"daily_confirmed": 0,
"recovered": 202098,
"deaths": 35205,
"daily_deaths": 0,
"critical": 676,
"tests": 7249844
},
"list": [
{
"country": "Italy",
"country_code": "it",
"state": "Lombardy",
"confirmed": 85775,
"deaths": 15662,
"critical": 231,
"recovered": 231,
"tests": 43442,
"daily_confirmed": -1,
"daily_deaths": -1
}, and so on ..
To overcome the data type issue I have used the dynamic objects
[JsonTypedExtensionData]
public Dictionary<string, dynamic> items { get; set; }
Up to This works well. Now I am trying to fetch the data out of this dynamic Dictionary
var report = await GetCountryReport();
Dictionary<string, dynamic> Dict = report.regions.results["world"].items;
I'm getting data as Dict Count (2)
[0] = {[list, {[ {"country": "Italy","confirmed": 4149,"deaths": 55,"recovered": 2916,"Incidence_Rate": "54.408517127144925","Case-Fatality_Ratio": "1.274822260357931","last_updated": "2020-08-10T22:30:32Z","...
[1] = {[totals, {{"confirmed": 20218306,"recovered": 12814226,"deaths": 737481,"critical": 64743,"tests": 370260493}}]}
How do I fetch the values of each element from the Dictionary like "values.list.country" etc..?
Visual Studio debug - output
You can do it like below:
var list = Dict.Where(x => x.Key == "list").Select(x => x.Value).SingleOrDefault();
var data = ((JArray)list).Select(x => new
{
country = (string)x["country"],
state = (string)x["state"],
confirmed = (int)x["confirmed"]
//...other properties in list
}).ToList();
The data structure is like below:
Then, you can use a foreach loop to get the specify value:
foreach(var x in data)
{
var country = x.country;
var state = x.state;
var confirmed = x.confirmed;
}
im trying to extract my data from json into a case class without success.
the Json file:
[
{
"name": "bb",
"loc": "sss",
"elements": [
{
"name": "name1",
"loc": "firstHere",
"elements": []
}
]
},
{
"name": "ca",
"loc": "sss",
"elements": []
}
]
my code :
case class ElementContainer(name : String, location : String,elements : Seq[ElementContainer])
object elementsFormatter {
implicit val elementFormatter = Json.format[ElementContainer]
}
object Applicationss extends App {
val el = new ElementContainer("name1", "firstHere", Seq.empty)
val el1Cont = new ElementContainer("bb","sss", Seq(el))
val source:String=Source.fromFile("src/bin/elementsTree.json").getLines.mkString
val jsonFormat = Json.parse(source)
val r1= Json.fromJson[ElementContainer](jsonFormat)
}
after running this im getting inside r1:
JsError(List((/elements,List(ValidationError(List(error.path.missing),WrappedArray()))), (/name,List(ValidationError(List(error.path.missing),WrappedArray()))), (/location,List(ValidationError(List(error.path.missing),WrappedArray())))))
been trying to extract this data forever, please advise
You have location instead loc and, you'll need to parse file into a Seq[ElementContainer], since it's an array, not a single ElementContainer:
Json.fromJson[Seq[ElementContainer]](jsonFormat)
Also, you have the validate method that will return you either errors or parsed json object..
I'm using mantle to parse JSON data with Swift. The content of the JSON file consists of:
{
"Name1": [
{
"Type": "New",
"Available": true,
"Kind": "4178228729",
"Loot": "4367",
"Advanced": [
{
"Type": "Old",
"Name": "RoundRobin",
"Available": true,
"Specs": [
{
"Type": "Fire",
"Available": true,
"Actions": [
--continues with similar pattern--
],
"Name2": [
--repeats the same pattern at before--
]
}
I created the model classes, inheriting from MTLJSONSerializing. The "first level class" is to contain the two top level arrays of objects.
import Foundation
class lv1Class: MTLJSONSerializing {
let name1: Array<lv2Class> = []
let name2: Array<lv2Class> = []
class func name2JSONTransformer() -> NSValueTransformer {
return NSValueTransformer.mtl_JSONArrayTransformerWithModelClass(lv2Class.self)
}
class func name1JSONTransformer() -> NSValueTransformer {
return NSValueTransformer.mtl_JSONArrayTransformerWithModelClass(lv2Class.self)
}
override class func JSONKeyPathsByPropertyKey() -> [NSObject : AnyObject]!
{
return ["name1": "Name1",
"name2": "Name2"]
}
}
And it goes on like this deeper and deeper.
import Foundation
class lv2Class: MTLJSONSerializing {
let type: String = ""
let available: Bool = true
let kind: String = ""
let loot: String = ""
let advanced: Array<lv3Class> = []
class func advancedJSONTransformer() -> NSValueTransformer {
return NSValueTransformer.mtl_JSONArrayTransformerWithModelClass(lv3Class.self)
}
override class func JSONKeyPathsByPropertyKey() -> [NSObject : AnyObject]!
{
return ["type": "Type",
"available": "Available",
"kind": "Kind",
"loot": "Loot",
"advanced": "Advanced"]
}
}
The other classes are similar in structure. (I can post them all on gists if necessary.)
The call to get the JSON data is as follows:
if let lv1ClassObject = MTLJSONAdapter.modelOfClass(lv1Class.self, fromJSONDictionary: testDic, error: errorjson) as? lv1Class
testDic is the file posted above.
The call that i make to get the json data succeeds, I'm pretty confident that the problem is in my data model. The value of the dictionary is an array so I feel pretty confident parsing it as an array.
The error I get is:
Assertion failure in -[MTLJSONAdapter initWithJSONDictionary:modelClass:error:], /Users/xx/Documents/Xcode/My_project/Pods/Mantle/Mantle/MTLJSONAdapter.m:149
2015-03-14 14:34:20.331 My_project[25794:711328] *** Caught exception available is not a property of My_project.lv2Class
But available is a property of such class...
let available: Bool = true
Hope it's clear enough, if you have any question feel free to ask.
I'm really not familiar with parsing JSON, thanks everyone for the help.
Answer is here.
You both need to put them as dynamic and to make sure that all your property can be bridged to the equivalent Obj-C property.