Search code examples
javaandroiddatabaserealm

How does Realm Database work?


I have started using Realm databse in my apps however I couldn't understand how does Realm knows the members of my model classes.

The only annotation that my realm model class has is @PrimaryKey on only one variable, other variables have no annotations.

The other way that I can think of is Realm using reflection to figure out the variables in the model class but since reflection is slow on Android, I don't think Realm relies on reflection since they market themselves as fast database.

Can someone tell me how does realm work or may be point me to some article which shows how realm works?


Solution

  • The only annotation that my realm model class has is @PrimaryKey on only one variable, other variables have no annotations.

    Wrong :) when you say extends RealmObject, you're actually inheriting from a class defined as

    @RealmClass  // <---- annotation
    public abstract class RealmObject implements RealmModel {
    }
    

    So your class has @RealmClass annotation, which the annotation processor is registered for, and then it can read all the fields, something like:

    @AutoService(Processor.class)
    public class ExampleProcessor extends AbstractProcessor {
        ProcessingEnvironment processingEnvironment;
        Elements elements;
        Messager messager;
        Filer filer;
        Types types;
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
            this.processingEnvironment = processingEnv;
            this.filer = processingEnvironment.getFiler();
            this.elements = processingEnvironment.getElementUtils();
            this.messager = processingEnvironment.getMessager();
            this.types = processingEnvironment.getTypeUtils();
        }
    
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(RealmClass.class);
            for(Element element : annotatedElements) {
                // ...
            }
            // ...
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.latest();
        }
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            Set<String> annotations = new HashSet<>();
            annotations.add(RealmClass.class.getName());
            return Collections.unmodifiableSet(annotations);
        }
    }
    

    Then it can generate a proxy class for each object annotated with @RealmClass. The code is available open-source at here.

    It gets a bit trickier when you have library projects that contain RealmObjects, hence why then you need to specify a @RealmModule (to define the schema and that it is a library module).


    As for replacing field access with proxy getter/setters, that's done by a Gradle Plugin called the Realm-Transformer (using Javassist), and it uses the so-called Transform API, and is written in Groovy.