Retrieving JSON Data¶
JSON values are stored in database columns of type JSON
. The data retrieval mechanism for JSON values is the same as for any other data stored in Backendless database. You can use the data retrieval API to retrieve objects from the Backendless database. Data in the JSON
columns is returned to the client application as either a strongly-typed object or as an instance of java.util.Map
.. Consider the example below:
Suppose the database stores objects in the Person
data table. The table declares the profile
column of type JSON. The column contains JSON values in the following format:
{
"age": 55,
"name": "Bob",
"address": {
"city": "Los Angeles",
"state": "California",
"street": "123 Santa Monica Blvd."
},
"lastname": "Smith",
"favoriteColors": [
"Blue", "Red"
],
"favoriteNumbers": [
13, 21, 88
]
}
As you can see the sample JSON value above exhibits the following "qualities":
- literal string and numeric values -
age
,name
andlastname
keys. - an array consisting of strings -
favoriteColors
- an array consisting of numbers -
favoriteNumbers
- an enclosed JSON object in the
address
key.
The JSON values and the Person objects may appear as shown below in the database:
Suppose the client application needs to retrieve both Person
objects and the corresponding profile
values as instances of java.util.Map
.. This can be accomplished with the following code:
Backendless.Data.of( "Person" ).findById( OBJECT_ID, new AsyncCallback<Map>()
{
@Override
public void handleResponse( Map person )
{
Map profile = (Map) person.get( "profile" );
Log.d( "MYAPP", "Name " + profile.get( "name" ) );
Log.d( "MYAPP", "Last name " + profile.get( "lastname" ) );
Log.d( "MYAPP", "Age " + profile.get( "age" ) );
Log.d( "MYAPP", "Favorite numbers " + Arrays.toString( (Integer[]) profile.get( "favoriteNumbers" ) ) );
Log.d( "MYAPP", "Favorite colors " + Arrays.toString( (String[]) profile.get( "favoriteColors" ) ) );
Map address = (Map) profile.get( "address" );
Log.d( "MYAPP", "Street " + address.get( "street" ) );
Log.d( "MYAPP", "City " + address.get( "city" ) );
Log.d( "MYAPP", "State " + address.get( "state" ) );
}
@Override
public void handleFault( BackendlessFault fault )
{
}
} );
Backendless.Data.of("Person").findById(OBJECT_ID, object : AsyncCallback<Map<*, *>> {
override fun handleResponse(person: Map<*, *>) {
val profile = person["profile"] as Map<*, *>
Log.d("MYAPP", "Name ${profile["name"]}")
Log.d("MYAPP", "Last name ${profile["lastname"]}")
Log.d("MYAPP", "Age ${profile["age"]}")
Log.d("MYAPP", "Favorite numbers ${(profile["favoriteNumbers"] as Array<Int>).contentToString()}")
Log.d("MYAPP", "Favorite colors ${(profile["favoriteColors"] as Array<String>).contentToString()}")
val address = profile["address"] as Map<*, *>
Log.d("MYAPP", "Street ${address["street"]}")
Log.d("MYAPP", "City ${address["city"]}")
Log.d("MYAPP", "State ${address["state"]}")
}
override fun handleFault(fault: BackendlessFault) {
Log.e("MYAPP", fault.message)
}
})
The code produces the following log output:
Name Bob
Last name Smith
Age 55
Favorite numbers [13, 21, 88]
Favorite colors [Blue, Red]
Street 123 Santa Monica Blvd.
City Los Angeles
State California
As you can see, the entire JSON structure is converted to a Java Map
with all the key/value pairs becoming corresponding entries in the returned object.
Your application may use an alternative approach - representing objects in the Backendless database with strongly-typed classes. In the context of the example above, this means you will have the Person
class defined in your application. But then there is a question of what data type to use for the profile
property? In this case, you have a choice for how to represent the JSON values. You can use either strongly-typed objects or the java.util.Map
approach described above. See the example below:
Java:
Person class with "profile" defined as java.util.Map:
package com.company;
import java.util.Map;
public class Person
{
private Map profile;
public Map getProfile()
{
return profile;
}
public void setProfile( Map profile )
{
this.profile = profile;
}
}
Backendless.Data.of( Person.class ).findById( OBJECT_ID, new AsyncCallback<Person>()
{
@Override
public void handleResponse( Person person )
{
Map profile = person.getProfile();
Log.d( TAG, "Name " + profile.get( "name" ) );
Log.d( TAG, "Last name " + profile.get( "lastname" ) );
Log.d( TAG, "Age " + profile.get( "age" ) );
Log.d( TAG, "Favorite numbers " + Arrays.toString( (Integer[]) profile.get( "favoriteNumbers" ) ) );
Log.d( TAG, "Favorite colors " + Arrays.toString( (String[]) profile.get( "favoriteColors" ) ) );
Map address = (Map) profile.get( "address" );
Log.d( TAG, "Street " + address.get( "street" ) );
Log.d( TAG, "City " + address.get( "city" ) );
Log.d( TAG, "State " + address.get( "state" ) );
}
@Override
public void handleFault( BackendlessFault fault )
{
}
} );
Person class with "profile" defined as a custom class. The class uses public fields for brevity - alternatively use get/set methods):
public class Person {
public Profile profile;
}
public class Profile {
public String age;
public String name;
public String lastname;
public Address address;
public String[] favoriteColors;
public int[] favoriteNumbers;
}
public class Address {
public String city;
public String state;
public String street;
}
Backendless.Data.of( Person.class ).findById( OBJECT_ID, new AsyncCallback<Person>()
{
@Override
public void handleResponse( Person person )
{
Profile profile = person.profile;
Log.d( TAG, "Name " + profile.name );
Log.d( TAG, "Last name " + profile.lastname );
Log.d( TAG, "Age " + profile.age );
Log.d( TAG, "Favorite numbers " + Arrays.toString( profile.favoriteNumbers ) );
Log.d( TAG, "Favorite colors " + Arrays.toString( profile.favoriteColors ) );
Address address = profile.address;
Log.d( TAG, "Street " + address.street);
Log.d( TAG, "City " + address.city);
Log.d( TAG, "State " + address.state);
}
@Override
public void handleFault( BackendlessFault fault )
{
Log.e(TAG, fault.getMessage());
}
} );
Kotlin:
Person class with "profile" defined as java.util.Map:
class Person {
var profile: Map<*, *>? = null
}
Backendless.Data.of(Person::class.java).findById(OBJECT_ID, object : AsyncCallback<Person> {
override fun handleResponse(person: Person) {
val profile = person.profile!!
Log.d("MYAPP", "Name ${profile["name"]}")
Log.d("MYAPP", "Last name ${profile["lastname"]}")
Log.d("MYAPP", "Age ${profile["age"]}")
Log.d("MYAPP", "Favorite numbers ${(profile["favoriteNumbers"] as Array<Int>).contentToString()}")
Log.d("MYAPP", "Favorite colors ${(profile["favoriteColors"] as Array<String>).contentToString()}")
val address = profile["address"] as Map<*, *>
Log.d("MYAPP", "Street ${address["street"]}")
Log.d("MYAPP", "City ${address["city"]}")
Log.d("MYAPP", "State ${address["state"]}")
}
override fun handleFault(fault: BackendlessFault) {
Log.e("MYAPP", fault.message)
}
})
Person class with "profile" defined as a custom class.
class Person {
var profile: Profile? = null
}
class Profile {
var age: String? = null
var name: String? = null
var lastname: String? = null
var address: Address? = null
var favoriteColors: Array<String>? = null
var favoriteNumbers: Array<Int>? = null
}
class Address {
var city: String? = null
var state: String? = null
var street: String? = null
}
Backendless.Data.of(Person::class.java).findById(OBJECT_ID, object : AsyncCallback<Person> {
override fun handleResponse(person: Person) {
val profile = person.profile!!
Log.d("MYAPP", "Name ${profile.name}")
Log.d("MYAPP", "Last name ${profile.lastname}")
Log.d("MYAPP", "Age ${profile.age}")
Log.d("MYAPP", "Favorite numbers ${(profile.favoriteNumbers as Array<Int>).contentToString()}")
Log.d("MYAPP", "Favorite colors ${(profile.favoriteColors as Array<String>).contentToString()}")
val address = profile.address!!
Log.d("MYAPP", "Street ${address.street}")
Log.d("MYAPP", "City ${address.city}")
Log.d("MYAPP", "State ${address.state}")
}
override fun handleFault(fault: BackendlessFault) {
Log.e("MYAPP", fault.message)
}
})
In case when the JSON values are represented as strongly-typed classes, Backendless automatically adapts them to the instances of your classes. It is important to maintain the basic fidelity between the JSON types and the corresponding java types as shown below:
JSON Type |
Java Type |
---|---|
string |
java.lang.String |
number |
int or java.lang.Integer |
boolean |
boolean or java.lang.Boolean |
object |
custom class or java.util.Map |
array |
java.util.List java.util.List<T> int[] String[] boolean[] |