Unable to find generated Parcelable class - android

I am trying to use Parceler in my android project.
This is my Song model.
#Parcel(implementations = {SongRealmProxy.class},
value = Parcel.Serialization.BEAN,
analyze = {Song.class})
public class Song extends RealmObject {
#PrimaryKey
public String id;
public String isrc;
public String songName;
public String artistName;
public String album_id;
public String albumArtUrl;
public String genre_id;
public String genreName;
public String releaseYear;
public String price;
public String lyrics;
public String demo;
public int explicit;
}
When I try to warp these song model using bundle like this.
b.putParcelable(DATA_PARAM, Parcels.wrap(song));
I keep having this error.
org.parceler.ParcelerRuntimeException: Unable to find generated Parcelable class for com.devhousemyanmar.juketrill.models.Song, verify that your class is configured properly and that the Parcelable class com.devhousemyanmar.juketrill.models.Song$$Parcelable is generated by Parceler.
Please help me to solve this problem.

Parcelable class should be like this :
package com.yourpackagename;
public class BrushData implements Parcelable {
public static final Creator<BrushData> CREATOR = new Creator<BrushData>() {
#Override
public BrushData createFromParcel(Parcel in) {
return new BrushData(in);
}
#Override
public BrushData[] newArray(int size) {
return new BrushData[size];
}
};
private static final int VERSION = 1;
#SerializedName("icon")
private String icon;
#SerializedName("effects")
private ArrayList<String> effects;
private BrushData(Parcel parcel) {
if (parcel != null) {
readFromParcel(parcel);
}
}
#Override
public int describeContents() {
return 0;
}
private void readFromParcel(Parcel in) {
if (in.readInt() == VERSION) {
icon = in.readString();
}
}
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(VERSION);
parcel.writeString(icon);
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public ArrayList<String> getEffects() {
return effects;
}
public void setEffects(ArrayList<String> effects) {
this.effects = effects;
}
}

Related

Accessing and Storing multiple POJO classes in Room

I have Multiple POJO classes as type's for the main POJO class which I am using to parse the json data using Retrofit. So I provided type converters for the first level Pojo but I'm having trouble in reading the stored data because that is not in correct format.
Here is my POJO class
#Entity(tableName = "entry")
public class Entry implements Parcelable {
#NonNull
#PrimaryKey
#SerializedName("id")
private FeedID feedId;
#SerializedName("title")
private Title EntryTitle;
#SerializedName("im:image")
private List<Image> image;
#SerializedName("summary")
private Summary summary;
public Entry(){}
public FeedID getFeedId() {
return feedId;
}
public void setFeedId(FeedID feedId) {
this.feedId = feedId;
}
public Title getEntryTitle() {
return EntryTitle;
}
public void setEntryTitle(Title entryTitle) {
this.EntryTitle = entryTitle;
}
public List<Image> getImage() {
return image;
}
public void setImage(List<Image> image) {
this.image = image;
}
public Summary getSummary() {
return summary;
}
public void setSummary(Summary summary) {
this.summary = summary;
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator<Entry>() {
#Override
public Entry createFromParcel(Parcel in) {
return new Entry(in);
}
#Override
public Entry[] newArray(int size) {
return new Entry[size];
}
};
protected Entry(Parcel in) {
feedId = (FeedID) in.readValue(FeedID.class.getClassLoader());
EntryTitle = (Title) in.readValue(Title.class.getClassLoader());
if (in.readByte() == 0x01) {
image = new ArrayList<Image>();
in.readList(image, Image.class.getClassLoader());
} else {
image = null;
}
summary = (Summary) in.readValue(Summary.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(feedId);
dest.writeValue(EntryTitle);
if (image == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(image);
}
dest.writeValue(summary);
}
public class Title implements Parcelable {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Title> CREATOR = new Parcelable.Creator<Title>() {
#Override
public Title createFromParcel(Parcel in) {
return new Title(in);
}
#Override
public Title[] newArray(int size) {
return new Title[size];
}
};
protected Title(Parcel in) {
label = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(label);
}
}
public class Image implements Parcelable {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Image> CREATOR = new Parcelable.Creator<Image>() {
#Override
public Image createFromParcel(Parcel in) {
return new Image(in);
}
#Override
public Image[] newArray(int size) {
return new Image[size];
}
};
protected Image(Parcel in) {
label = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(label);
}
}
public class Summary implements Parcelable {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Summary> CREATOR = new Parcelable.Creator<Summary>() {
#Override
public Summary createFromParcel(Parcel in) {
return new Summary(in);
}
#Override
public Summary[] newArray(int size) {
return new Summary[size];
}
};
protected Summary(Parcel in) {
label = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(label);
}
}
public class FeedID implements Parcelable {
private Attributes attributes;
public Attributes getAttributes() {
return attributes;
}
public void setAttributes(Attributes attributes) {
this.attributes = attributes;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<FeedID> CREATOR = new Parcelable.Creator<FeedID>() {
#Override
public FeedID createFromParcel(Parcel in) {
return new FeedID(in);
}
#Override
public FeedID[] newArray(int size) {
return new FeedID[size];
}
};
protected FeedID(Parcel in) {
attributes = (Attributes) in.readValue(Attributes.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(attributes);
}
}
public class Attributes implements Parcelable {
#SerializedName("im:id")
private String id;
public String getIm() {
return id;
}
public void setIm(String im) {
this.id = im;
}
#SuppressWarnings("unused")
public final Parcelable.Creator<Attributes> CREATOR = new Parcelable.Creator<Attributes>() {
#Override
public Attributes createFromParcel(Parcel in) {
return new Attributes(in);
}
#Override
public Attributes[] newArray(int size) {
return new Attributes[size];
}
};
protected Attributes(Parcel in) {
id = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
}
}
}
and this is my TypeConverter class
public class RoomTypeConverters {
#TypeConverter
public static String toString(Entry.Title value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static Entry.Title toTitle(String value) {
Type listType = new TypeToken<Entry.Title>() {
}.getType();
return new Gson().fromJson(value, listType);
}
#TypeConverter
public static String toString(Entry.FeedID value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static Entry.FeedID toFeedID(String value) {
Type listType = new TypeToken<Entry.FeedID>() {
}.getType();
return new Gson().fromJson(value, listType);
}
#TypeConverter
public static String toString(Entry.Summary value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static Entry.Summary toSummary(String value) {
Type listType = new TypeToken<Entry.Summary>() {
}.getType();
return new Gson().fromJson(value, listType);
}
#TypeConverter
public static String toString(List<Entry.Image> value) {
Gson gson = new Gson();
String json = gson.toJson(value);
return json;
}
#TypeConverter
public static List<Entry.Image> toImage(String value) {
Type listType = new TypeToken<Entry.Summary>() {
}.getType();
return new Gson().fromJson(value, listType);
}
}
Do I have to create multiple POJO's like that only for one field? Do we have any other alternative?
Yes, to save a POJO you have to define a class for it (either inner or normal class).
But what I understand from your data schema is that you have a possibly complex data store server side and you want to use a subset of that data in your app. Your POJO can be simplified so you can create a Class called EntryRecord for example and define a simple setter and getter for it like this:
#Entity(tableName = "entry")
public class EntryRecord {
#NonNull
#PrimaryKey
#SerializedName("id")
private String feedId;
#SerializedName("title")
private StringEntryTitle;
#SerializedName("im:image")
private String[] image;
#SerializedName("summary")
private String summary;
public EntryRecord(Entry entry){
//Resolve primitive values from Entry class attributes..
}
public Entry getEntry(){
Entry entry = new Entry();
//Resolve entry values from primitive ones...
return entry ;
}
}
, now all you have to do is to use this class to save and restore your data, you can event make your DAO abstract to convert your POJO before save and vice versa.
P.S: if you don't have any use for such complex Schema with so many single variable classes I really advise you to define custom GSON serializer/deserializer to convert the complex POJO to simplified one from the beginning; removing such a complex schema entirely from your code base.
So after a little research I have found a annotation for which if you have multiple inner classes room will take care of it and you don't have to create any TypeConverters for it.
#Embedded Can be used as an annotation on a field of an Entity or Pojo to signal that nested fields (i.e. fields of the annotated field's class) can be referenced directly in the SQL queries.
For example, if you have 2 classes:
public class Coordinates {
double latitude;
double longitude;
}
public class Address {
String street;
#Embedded
Coordinates coordinates;
}
Room will consider latitude and longitude as if they are fields of the Address class when mapping an SQLite row to Address.
Source : Documentation

Pass ArrayList of Parcelable objects throws error

I have an object with a couple of Strings, one int and another object which has 4 inner objects. All of them implementing Parcelable. In order to generate the boilerplate code, I used Parcelable plugin from Android studio.
Even though all the objects are parcelable, I'm getting the following error: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: AlbumTrackResponse
Here's how the POJOs look like:
Main object:
public class AlbumTrackResponse implements Parcelable {
private String id;
private String albumId;
private String position;
private String title;
private int rate;
private AllServices services;
public AllServices getServices() {
return services;
}
public void setServices(AllServices services) {
this.services = services;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAlbumId() {
return albumId;
}
public void setAlbumId(String albumId) {
this.albumId = albumId;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getRate() {
return rate;
}
public void setRate(int rate) {
this.rate = rate;
}
protected AlbumTrackResponse(Parcel in) {
id = in.readString();
albumId = in.readString();
position = in.readString();
title = in.readString();
rate = in.readInt();
services = (AllServices) in.readValue(AllServices.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(albumId);
dest.writeString(position);
dest.writeString(title);
dest.writeInt(rate);
dest.writeValue(services);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<AlbumTrackResponse> CREATOR = new Parcelable.Creator<AlbumTrackResponse>() {
#Override
public AlbumTrackResponse createFromParcel(Parcel in) {
return new AlbumTrackResponse(in);
}
#Override
public AlbumTrackResponse[] newArray(int size) {
return new AlbumTrackResponse[size];
}
};
}
Inner object with 4 objects
public class AllServices implements Parcelable {
private GigRevService gigrev;
private AppleService apple;
private GoogleService google;
private SpotifyService spotify;
protected AllServices(Parcel in) {
gigrev = (GigRevService) in.readValue(GigRevService.class.getClassLoader());
apple = (AppleService) in.readValue(AppleService.class.getClassLoader());
google = (GoogleService) in.readValue(GoogleService.class.getClassLoader());
spotify = (SpotifyService) in.readValue(SpotifyService.class.getClassLoader());
}
#Override
public int describeContents() {
return 0;
}
public GigRevService getGigrev() {
return gigrev;
}
public void setGigrev(GigRevService gigrev) {
this.gigrev = gigrev;
}
public AppleService getApple() {
return apple;
}
public void setApple(AppleService apple) {
this.apple = apple;
}
public GoogleService getGoogle() {
return google;
}
public void setGoogle(GoogleService google) {
this.google = google;
}
public SpotifyService getSpotify() {
return spotify;
}
public void setSpotify(SpotifyService spotify) {
this.spotify = spotify;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(gigrev);
dest.writeValue(apple);
dest.writeValue(google);
dest.writeValue(spotify);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<AllServices> CREATOR = new Parcelable.Creator<AllServices>() {
#Override
public AllServices createFromParcel(Parcel in) {
return new AllServices(in);
}
#Override
public AllServices[] newArray(int size) {
return new AllServices[size];
}
};
}
The inner objects from here contain just string items.
Here's how I pass the ArrayList to the bundle:
bundle.putParcelableArrayList(MediaPlayerService.TRACK_LIST, trackList);
I'm passing the items from an Activity to a Service. Any ideas why I'm getting this error?
EDIT: Implementation of service classes
public class GoogleService implements Parcelable {
private String name;
private String uri;
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected GoogleService(Parcel in) {
name = in.readString();
uri = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(uri);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<GoogleService> CREATOR = new Parcelable.Creator<GoogleService>() {
#Override
public GoogleService createFromParcel(Parcel in) {
return new GoogleService(in);
}
#Override
public GoogleService[] newArray(int size) {
return new GoogleService[size];
}
};
}
This looks extremly strange
this.services = in.readParcelable(getClass().getClassLoader());
You are pointing out to the wrong class loader. You have to use it like this
this.services = (AllServices)in.readParcelable(AllServices.class.getClassLoader());
Besides that, I am always using this site http://www.parcelabler.com/ to quickly generate my Parceables. Or you could use it like this
services = (AllServices) in.readValue(AllServices.class.getClassLoader());
Here:
protected AllServices(Parcel in) { this.gigrev = in.readParcelable(getClass().getClassLoader());
this.apple = in.readParcelable(getClass().getClassLoader());
this.google = in.readParcelable(getClass().getClassLoader());
this.spotify = in.readParcelable(getClass().getClassLoader()); }
Replace it with
protected AllServices(Parcel in) { this.gigrev = in.readParcelable(GigRevService.class.getClassLoader());
this.apple = in.readParcelable(AppleService.class.getClassLoader());
this.google = in.readParcelable(GoogleService.class.getClassLoader());
this.spotify = in.readParcelable(SpotifyService.class.getClassLoader()); }
And replace:
this.services = in.readParcelable(getClass().getClassLoader());
With:
this.services = in.readParcelable(AllServices.class.getClassLoader());
Also can you show the GoogleService etc classes? Each inner object's class must have a Parcelable creator also and implement the Parcelable interface as well.

source.readList of Parcelable doesn't work over List<String>

This line is red flagged by IDE :
mBook.Color=source.readList(Color,Book.class.getClassLoader());
I also changed to
mBook.Color=source.readList(Color,String.class.getClassLoader());
but still wrong, I thought it's because my code was missing getter & setter for color field, but after creating them, it's still wrong. I'm sure this is not the way to make the field parceabled but don't know either the correct way to make correct
Book.java :
public class Book implements Parcelable {
private String bookName;
private int publishTime;
private static List<String> Color = Arrays.asList(new String[]{"red","blue"});
public String getBookName() {
return bookName;
}
public static List<String> getColor() {
return Color;
}
public static void setColor(List<String> Color) {
Book.Color = Color;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public int getPublishTime() {
return publishTime;
}
public void setPublishTime(int publishTime) {
this.publishTime = publishTime;
}
public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() {
public Book createFromParcel(Parcel source) {
Book mBook = new Book();
mBook.bookName = source.readString();
mBook.publishTime = source.readInt();
mBook.Color =source.readList(Color,Book.class.getClassLoader());
return mBook;
}
public Book[] newArray(int size) {
return new Book[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(bookName);
parcel.writeInt(publishTime);
parcel.writeList(Color);
}
}
The problem is that readList returns a void so that might be what your IDE is complaining about. The solution is the following :
mBook.Color = null;
source.readList(Color,Book.class.getClassLoader());
Hope it helps.

Android use Intent to send a list of Parcelable objects which contain a list of another Parcelable objects

In my Android app, I want to use Intent to pass a list of SingleGroup to another Activity where each SingleGroup object contains a list of SingleImage, here are class for SingleImage and SingleGroup:
public class SingleImage implements Parcelable{
public String name;
public int drawableId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDrawableId() {
return drawableId;
}
public void setDrawableId(int drawableId) {
this.drawableId = drawableId;
}
public SingleImage(String name, int drawableId)
{
this.name = name;
this.drawableId = drawableId;
}
public static final Parcelable.Creator<SingleImage> CREATOR
= new Parcelable.Creator<SingleImage>()
{
public SingleImage createFromParcel(Parcel in)
{
return new SingleImage(in);
}
public SingleImage[] newArray(int size)
{
return new SingleImage[size];
}
};
private SingleImage(Parcel in)
{
name = in.readString();
drawableId = in.readInt();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(drawableId);
}
}
Here is SingleGroup class:
public class SingleGroup implements Parcelable{
private static final String TAG = "SINGLEGROUP";
private ArrayList<SingleImage> images = new ArrayList<SingleImage>(0);
private String myTitle;
private String groupDesc;
public SingleGroup(String mTitle, String desc, ArrayList<SingleImage> imagesList) {
this.myTitle = mTitle;
this.groupDesc = desc;
this.images = imagesList;
}
public String getGroupDesc() {
return groupDesc;
}
public String getMyTitle() {
return myTitle;
}
public void setMyTitle(String myTitle) {
this.myTitle = myTitle;
}
public ArrayList<SingleImage> getImages() {
return images;
}
public void setImages(ArrayList<SingleImage> images) {
this.images = images;
}
public static final Parcelable.Creator<SingleGroup> CREATOR
= new Parcelable.Creator<SingleGroup>()
{
public SingleGroup createFromParcel(Parcel in)
{
return new SingleGroup(in);
}
public SingleGroup[] newArray(int size)
{
return new SingleGroup[size];
}
};
private SingleGroup(Parcel in)
{
myTitle = in.readString();
groupDesc = in.readString();
//problem maybe here
in.readTypedList(images,SingleImage.CREATOR);
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(myTitle);
dest.writeString(groupDesc);
//problem maybe here
dest.writeTypedList(images);
}
#Override
public String toString() {
String result = "myTitle "+myTitle+" desc "+ groupDesc + " imagesize "+images.size();
return result;
}
}
It works ok when calling to pass ArrayList<SingleImage> through Intent,
while when I called to pass ArrayLlist<SingleGroup> through Intent I got error:
Parcel android.os.Parcel#3c4c6743: Unmarshalling unknown type code
3211379 at offset 224
Any idea? Thanks in advance
---------------- Update ----------------
I have changed in.readTypedList(images, null); to in.readTypedList(images, SingleImage.CREATOR); but it still not working. same unmarshalling error
---------------- Problem Solved --------------
Thanks to Keita. The real problem is not actually listed in my code. When I passing the parcelable object, I should also include some other attributes which I missed.
Strongly recommend AS plugin Android Parcelable code generator
You must be pass SingleImage.CREATOR into method readTypedList instead of "null" value
private SingleGroup(Parcel in)
{
myTitle = in.readString();
groupDesc = in.readString();
//problem maybe here
in.readTypedList(images, SingleImage.CREATOR);
}
Try this one. That is what i always do and it work:
private SingleGroup(Parcel in)
{
myTitle = in.readString();
groupDesc = in.readString();
//problem maybe here
in.createTypedArrayList(SingleImage.CREATOR);
}
ArrayList is serialize. So try to this
public class SingleImage implements Serializable{
....
}
Refer this: ArrayList Android Documentation

Parcelable inheritance in android caused ClassCastExeption

i have a Parent class implementing parcelable and a child extending parent also implementing parcelable. My code is attached below. I get a runtime ClassCastException. What am I missing?
Thanks,
Parent Class:
public class Follower implements Parcelable{
private long id;
private String fullName;
public Follower() {
}
public Follower(String fullName) {
this.fullName = fullName;
}
public long getId(){
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getFullName());
}
protected Follower(Parcel in){
setFullName(in.readString());
}
public static final Parcelable.Creator<Follower> CREATOR =
new Parcelable.Creator<Follower>() {
public Follower createFromParcel(Parcel in) {
return new Follower(in);
}
public Teen[] newArray(int size) {
return new Teen[size];
}
};
}
The Child Class
public class Teen extends Follower
implements Parcelable{
public Teen(){
super();
}
public Teen( String fullName, String birthDate) {
super(fullName);
this.birthDate = birthDate;
}
private String birthDate;
public String getBirthDate() {
return birthDate;
}
public void setBirthDate(String birthDate){
this.birthDate = birthDate;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString (birthDate);
}
private Teen(Parcel in){
super(in);
birthDate = in.readString();
}
public static final Parcelable.Creator<Teen> CREATOR =
new Parcelable.Creator<Teen>() {
public Teen createFromParcel(Parcel in) {
return new Teen(in);
}
public Teen[] newArray(int size) {
return new Teen[size];
}
};
}
On the server, I create a Teen/Follower like below. The teen and follower clasess are copied to the server without the parcelable implementation.
public Follower getData()
{
if (logic to see if the user is a teen){
Teen t = new Teen( "Full Name", "1:1:1960");
return t;
}
else
{
Follower f = new Follower("Full Name");
return f;
}
}
On the client
I do get the Follower in the client code. I have checked by accessing the Follower class methods. It works. However when I do something like this I get a ClassCastException at runtime.
if(logic to see if it is a teen)
{
Teen t = (Teen) follower;
}
I am sure it is something small that I am missing but am at loss. Any help will be appreciated. Thanks,
Change this:
public class Teen extends Follower
implements Parcelable{
to this:
public class Teen extends Follower{
You don't have to reimplement the parcelable in child, because it inherit from the parent. I'm not sure, but when you create a Teen it implements it's own parcelable data-type, and it isn't in hierarchical structure with it's parent parcelable data-type.

Categories

Resources