Is there any way to support custom types with Realm? For instance, instead of using Date in Java, I use the fairly common Joda Time library, so I'd like to be able to store a custom type, DateTime, which can easily be stored as a long or a String. Do I have any way to map this in realm?
Hi @spierce7
Currently there is no easy way outside static mapper methods. Once we introduce support for custom getters and setters ( #909 ), doing this will be easier as you can do the mapping inside the getter and setter.
We will most likely not introduce native support for 3rd party types as one of the core features of Realm is that the data should be readable on all platforms.
Other similar SQL platforms allow for mapping to supported database types, such as boolean, short, 矛nt, long, float, double, String and byte[], all of which you guys support. It'd still would be usable on all platforms, just with the native supported types.
Hi @spierce7
Yes, but that is also why custom getters and setters would solve this, eg.
public Foo extends RealmObject {
private long timestamp;
public Date getDate() {
return new Date(timestamp);
}
pulibc void setDate(Date date) {
timestamp = date.getTime();
}
}
That would work for any time that could be converted to one of the types supported by Realm.
I suppose you are right. That would solve my concern.
@cmelchior has any progress been made here? I feel that support for custom types could be added in realm-java by using converters without having to touch the core. The currently support types are enough to support a wide range of custom classes. Is there perhaps already an open issue for this since this? I couldn't find one.
We could register these converters in the Realm configuration builder perhaps like so:
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
.addConverter(LocalTime.class, new LocalTimeConverter())
.build()
We could also define them on a per-field basis:
public class Foo extends RealmObject {
@Converter(LocalTimeConverter.class)
public LocalTime bar;
}
Or something similar and perhaps better?
Well, you can already do
public class Foo extends RealmObject {
private Date bar;
public LocalTime getBar() {
return new LocalTime(bar);
}
public void setBar(LocalTime localTime) {
this.bar = new Date(localTime.getTime());
}
}
since 0.88.0+
@Zhuinden yes. But in order to get that working requires a whole lot of work people need to do in their own code. This blog post shows the amount of extra boilerplate that example requires. Imagine having to do that for every single class you have. You would also need to get the value everywhere in your code every single time. It would add even more boilerplate.
Another solution is to have your own backing field and change those in the getters and setters so Realm can store them. This at least doesn't add an extra layer that you need to know about when you're not working on the data classes. But it's a lot of copy and paste to get your own "converters".
public class Foo extends RealmObject {
public String _time;
@Ignore
private LocalTime time;
public LocalTime getTime() {
if(time == null && _time != null)
time = LocalTime.parse(_time, SomeFormatter());
return time;
}
public void setTime(LocalTime time) {
this.time = time;
this._time = time == null ? null : SomeFormatter().format(time);
}
}
You would still be able to use Foo.getTime() instead of Foo.getTime().getValue() and then adding abstraction layers in all of your libraries that use that object. It adds a lot of failure points imo that could be negated.
Now imagine being able to Foo.getTime() without having this ugly boilerplate code and without the abstraction layers in all of your libraries. This would in my opinion remove a lot of pain points that come with using Realm.
@AndreasBackx a flawed comparison, you are comparing the support of arbitrary types to storing RealmList<primitive>. They are not the same problem.
Honestly, hacking Realm by adding RealmList<RealmObject> instead of merging (joining) the Strings into a single field was the worst possible error the Internet could have come up with.
As for the automatic conversion, I've only ever needed this for enums, but the @Ignore setup solved that issue. I'm far too sleepy at the moment (3 AM does that to you) to think about how Realm wouldn't bloat their API with a @Converter annotation.
@Zhuinden I never compared the support of arbitrary types to storing RealmList<primitive>. This issue was created in order request adding support for arbitrary types. RealmLists never seem to have been mentioned in this issue.
I don't see how this would "bloat" the Realm API. I feel that this is essential and currently leaving it up to the users to hack in a workaround is contradicting to the promise Realm gives its users. Realm promises "Build better apps, faster." and "Realtime collaboration in as little as 10 lines of code".
I don't know the complete internals of realm-java. But I would say that adding an annotation would already be an immense feat. I feel that this goes together with #909. Realm currently forces us to change the way we work by rethinking polymorphism and inheritance #761. Making Realm more seamless is in my eyes the first thing that needs to be focused on in order to get a higher adoption rate. The basics are here and more, but there are still a lot of things holding people back in my opinion and these are the major ones. It takes time, effort and boilerplating to get "normal" data models to work with Realm.
The last thing I would like to say is that you could compare Realm and other ORMs with parsers like Jackson and Gson. They all need to handle data, whether you save it or not. Jackson and Gson can adjust with relative ease to how your JSON is written and I think Realm needs to follow this route.
I'm willing to make a PR for this myself and get it out of the door. I don't have any experience with annotation processors, but would of course like to learn. But before I perhaps start, I would like to know the opinions of you all.
_PS: I wrote this at 4AM. I might edit this the next day and apologise in advance if I come over a bit "sharp"._
@AndreasBackx It is being tracked here https://github.com/realm/realm-java/issues/1694 , but with a relatively low priority since the work arounds are pretty clear.
The problem with type adapters is that for converters to be truely elegant you need to hook into our RealmTransformer, which means defining these converters will be non-trivial. Also you eventually need to map your own class to _something_ that can be stored in Realm. That code cannot be automated as Realm is restricted by which types we can save, so the user must decide how non-standard types get converted, so the converter must be hand-written. At which point making factory converters is just as easy. Lets just take the Java class Point as an example:
// From Java framework
public class Point {
public int x;
public int y;
// bunch of methods
}
// This would require a Realm class
public class RealmPoint extends RealmObject {
public int x;
public int y;
// Add factory methods for mapping
public static RealmPoint fromPoint(Point p) {
return new RealmPoint(p.x, p.y);
}
public static Point toPoint(RealmPoint p) {
return new Point(p.x, p.y);
}
}
// Conversion in classes
public class MyClass extends RealmObject {
public RealmPoint myPoint;
public void setPoint(Point p) {
myPoint = RealmPoint.fromPoint(p);
}
public Point getPoint() {
return RealmPoint.toPoint(myPoint);
}
}
Most helpful comment
@cmelchior has any progress been made here? I feel that support for custom types could be added in
realm-javaby using converters without having to touch the core. The currently support types are enough to support a wide range of custom classes. Is there perhaps already an open issue for this since this? I couldn't find one.We could register these converters in the Realm configuration builder perhaps like so:
We could also define them on a per-field basis:
Or something similar and perhaps better?