jsonapi-converter icon indicating copy to clipboard operation
jsonapi-converter copied to clipboard

Eager vs Lazy resolution of relationships

Open emetsger opened this issue 8 years ago • 2 comments

The current behavior of the JSON-API Converter when resolving relationships is to resolve them eagerly, and recursively.

If you have a model that represents a hierarchy of objects that is arbitrarily deep, resolving a single object in that hierarchy will result in recursivly resolving all of the nodes below it.

For example, retrieving an instance of Node, below, may result in traversing a hierarchy that is arbitrarily deep:

Example Java

@Types("node")
class Node {

  @Id
  String id;

  @Relationship(value = "children", resolve = true, relType = RelType.RELATED)
  List<Node> children;

  // ...
}

Example JSON

{
  "data": [
    {
      "type": "node",
      "id": "1",
      "relationships": {
        "children": {
          "links": {
            "related": "http://example.com/node/1/children"
          }
        }
      }
    }
  ]
}

This behavior may not be desirable for many reasons, least of which have to do with the performance of retrieving deeply nested structures.

There may be multiple ways to address this. For example:

  • Add a depth attribute to the @Relationship annotation, which controls how many levels deep the resolution will go
    • Let n be value of the depth attribute; the problem is you have to gracefully handle the situation when the developer wants to resolve the object that is n+1 levels deep.
  • Update the behavior of the resolution mechanism to lazily resolve relationships
    • This doesn't seem to be within the scope of the JSON API Converter. Once a JSON document is converted into POJOs, the converter has no interaction with the POJO model, and wouldn't be able to lazily resolve relationships.
  • Instead of resolving the URL and deserializing the response document to a Java object, simply save the URL as a string in the Java model. This is essentially lazy loading, which puts the burden of resolving and deserializing a reference explicitly on the developer of the model.

emetsger avatar May 06 '16 16:05 emetsger

Hey,

I've considered lazy loading already. Having in mind that lib is used for android dev also and networking restrictions that come with it, executing lazy resolution becomes really tricky.

jasminb avatar May 06 '16 16:05 jasminb

Hey @jasminb, so I put together a proposed approach:

@Type("foo")
class Foo {
    @Id
    String id;

    @Relationship(value = "...", resolve = true, strategy = ResolutionStrategy.REF)
    String relRef;
}

If the @Relationship uses a strategy of ResolutionStrategy.REF, the url of the relationship is stored instead of resolving and deserializing the response document.

If the @Relationship uses a strategy of ResolutionStrategy.OBJECT the url of the relationship is resolved and deserialized like normal.

Essentially, this is implementing the third bullet point from above:

Instead of resolving the URL and deserializing the response document to a Java object, simply save the URL as a string in the Java model. This is essentially lazy loading, which puts the burden of resolving and deserializing a reference explicitly on the developer of the model.

emetsger avatar May 06 '16 16:05 emetsger