/* * Copyright 2017 Realm Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.realm.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation for defining a reverse relationship from one class to another. This annotation can * only be added to a field of the type {@code RealmResults}. *<pre> * To expose reverse relationships for use, create a declaration as follows: * {@code * * public class Person extends RealmObject { * String name; * Dog dog; // Normal relation * } * * public class Dog extends RealmObject { * // This holds all Person objects with a relation to this Dog object (= linking objects) * \@LinkingObjects("dog") * final RealmResults>Person< owners = null; * } * * // Find all Dogs with at least one owner named John * realm.where(Dog.class).equalTo("owners.name", "John").findAll(); * } * </pre> * In the above example `Person` is related to `Dog` through the field `dog`. * This in turn means that an implicit reverse relationship exists between the class `Dog` * and the class `Person`. This inverse relationship is made public and queryable by the `RealmResults` * field annotated with `@LinkingObject`. This makes it possible to query properties of the dogs owner * without having to manually maintain a "owner" field in the `Dog` class. * <p> * Linking objects have the following properties: * <ul> * <li>The link is maintained by Realm and only works for managed objects.</li> * <li>They can be queried just like normal relation.</li> * <li>They can be followed just like normal relation.</li> * <li>They are ignored when doing a `copyToRealm().`</li> * <li>They are ignored when doing a `copyFromRealm().`</li> * <li>They are ignored when using the various `createObjectFromJson*` and `createAllFromJson*` methods.</li> * <li>Listeners on an object with a `@LinkingObject` field will not be triggered if the linking objects change, * e.g: if another object drops a reference to this object.</li> * </ul> * <p> * In addition, they have the following restrictions: * <ul> * <li>{@literal @}Ignore takes precedence. A {@literal @}LinkingObjects annotation on {@literal @}Ignore field will be ignored.</li> * <li>The annotated field cannot be {@literal @}Required.</li> * <li>The annotated field must be `final`.</li> * <li>The annotation argument (the name of the backlinked field) is required.</li> * <li>The annotation argument must be a simple field name. It cannot contain periods ('.').</li> * <li>The annotated field must be of type `RealmResults>T<` where T is concrete class that extends `RealmModel`.</li> * </ul> * * Note that when the source of the reverse reference (`dog` in the case above) is a `List`, there is a reverse * reference for each forward reference, even if both forward references are to the same object. * If the `Person` class above were defined as: * {@code * * public class DogLover extends RealmObject { * String name; * List<Dog> dogs = new ArrayList<Dog>; * } * } * then the following code executes without error * {@code * * Dog fido = new Dog(); * DogLover john = new DogLover() * john.dogs.add(fido); * john.dogs.add(fido); * assert john.dogs.size() == 2; * assert fido.owners.size() == 2; * } */ @Retention(RetentionPolicy.CLASS) @Target(ElementType.FIELD) @Beta public @interface LinkingObjects { /** * The name of a field that contains a relation to an instance of the * class containing this annotation. If this argument is not provided * the annotation processor will abort with an {@code IllegalArgumentException}. */ String value() default ""; }