Skip to main content

Visibility

Previous documents have discussed in detail the dynamic and immutable properties of Jimmer entities. This introduces a new feature: visibility.

Entangled Properties

For Jimmer entities, although properties are mostly independent, in some cases multiple properties share private data and thus affect each other. We call this entanglement between properties.

These cases include:

  • Java/Kotlin-based calculated properties (review details)

    Author.java
    package com.example.model;

    import org.babyfish.jimmer.sql.*;

    @Entity
    public interface Author {

    String firstName();

    String lastName();

    @Formula(dependencies = {"firstName", "lastName"})
    default String fullName() {
    return firstName() + ' ' + lastName();
    }

    ...Omit other properties...
    }

    Author.fullName has no private data, it depends on Author.firstName and Author.lastName.

    Although Author.fullName is defined as a calculated property, it can also be considered a view property from another perspective.

    If treating Author.firstName and Author.lastName as original properties, then Author.fullName can be considered a view property based on them.

  • @IdView view properties (review details)

    Book.java
    package com.example.model;

    import org.babyfish.jimmer.sql.*;
    import org.jetbrains.annotations.Nullable;

    @Entity
    public interface Book {

    ...Omit other properties...

    @ManyToOne
    @Nullable
    BookStore store();

    @ManyToMany
    @JoinTable(
    name = "BOOK_AUTHOR_MAPPING",
    joinColumnName = "BOOK_ID",
    inverseJoinColumnName = "AUTHOR_id"
    )
    List<Author> authors();

    @IdView // View of associated object store's id
    Long storeId();

    // View of ids of all objects in associated collection authors
    @IdView("authors")
    List<Long> authorIds();
    }
    • Book.store is the original property, Book.storeId is the view property based on it

    • Book.authors is the original property, Book.authorIds is the view property based on it

  • @ManyToManyView view properties (review details)

    Student.java
    @Entity
    public interface Student {

    // In step 1, already declared one-to-many association `learningLinks`
    @OneToMany(mappedBy = "student")
    List<LearningLink> learningLinks();

    @ManyToManyView(
    prop = "learningLinks",
    deeperProp = "course"
    )

    List<Course> courses();

    ...Omit other code...
    }

    Student.learningLinks is the original property, Student.courses is the view property based on it.

The commonality in the examples above is that there are original properties and view properties.

The original properties have their own private data, while the view properties have none. The view properties just observe the values of the original properties from a different perspective.

From an internal implementation perspective, a view property actually shares private data with the original property. This means knowing one value necessarily reveals partial information about the other's value. Hence they can be metaphorically described as entangled properties.

Object Fetchers and Entangled Properties

We introduced entangled properties, with original properties and view properties. The real data is held by the original properties, while the view properties only observe.

When using an object fetcher to fetch a view property, the internal logic will translate it into fetching the original property, for example:

  • Fetching Author.fullName is translated internally into fetching Author.firstName and Author.lastName

  • Fetching Book.storeId is translated internally into fetching Book.store

  • Fetching Book.authorIds is translated internally into fetching Book.authors

  • Fetching Student.courses is translated internally into fetching Student.learningLinks

Let's take Book.authorIds and Book.authors to demonstrate how object fetchers handle original properties and view properties differently:

  • Fetch the original property

    Book book = sqlClient.findById(
    Fetchers.BOOK_FETCHER
    .allScalarFields()
    .authors(), // Associated objects with only id
    1L
    );
    System.out.println(book);

    The authors() in the fetcher has no arguments, indicating it fetches a collection of author objects with only id properties. The result is (manually formatted for readability):

    {
    "id":1,
    "name":"Learning GraphQL",
    "edition":1,
    "price":50,
    "authors":[
    { "id":2 },
    { "id":1 }
    ]
    }
  • Fetch the view property

    Book book = sqlClient.findById(
    Fetchers.BOOK_FETCHER
    .allScalarFields()
    .authorIds(), // Associated ids, not objects
    1L
    );
    System.out.println(book);

    This time the result is (manually formatted for readability):

    {
    "id":1,
    "name":"Learning GraphQL",
    "edition":1,
    "price":50,
    "authorIds":[
    2, 1
    ]
    }

Although the returned data is equivalent, the formats are completely different.

We said earlier that when an object fetcher fetches a view property, it translates internally into fetching the original property.

Since this is the case, the underlying logic should be exactly the same. Where does this difference come from?

Property Visibility

The question above is, with identical underlying logic, why do two queries with the same logic return data in different formats?

Jimmer can control the visibility of each property, making it shown or hidden.

Unlike dynamic where a property can be loaded or unloaded, visibility is an orthogonal feature, completely unrelated to dynamism.

Visibility only affects Jackson serialization of objects (including their own toString behavior), deciding whether a property is serialized. Other than that, it does not impact any other behavior of the object.

So the previous examples can be easily explained:

  • First query: Book.authors is shown, Book.authorIds is hidden

  • Second query: Book.authors is hidden, Book.authorIds is shown

tip

Only when both conditions below are met will a property participate in Jackson serialization

  • Dynamism: the property is set
  • Visibility: the property is shown

See tool methods for how to control visibility of Jimmer object properties yourself