Skip to content

How to use projections in Java

Joe Betz edited this page Oct 18, 2013 · 26 revisions

What are projections?

Projections are a way for a client to request only specific fields from an object instead of the entire object. Using projections when you only need a few fields from an object is a good way to self-document your code and reduce payload of responses. You can read more about projections here: Projections

Getting the PathSpec of a field

Using projections in java code relies heavily on PathSpec objects, which represent specific fields of an object. To get a PathSpec of a field bar of a RecordTemplate object Foo, you would write the following:

PathSpec pathSpec = Foo.fields().bar();

It is not possible to set projections for non-RecordTemplate objects.

How do I make a rest request with projections using the Java Client?

Projections are set by the request builder. To set a request projection, create your builder as you normally would, and then add your projection to it:

builder.fields(pathSpec);

the fields() method can take as arguments any number of PathSpecs, or an array of them.

builder.fields(pathSpec1, pathSpec2, pathSpec3);

builder.fields(pathSpecArray);

This will create a positive projection for your given fields. The request will only return fields that you have specified with .fields(...).

Is it possible to create a negative projection if I want all but a few fields?

No. If you want a large number of fields you will need to include them all in the .fields(...) method call.

If a field’s type is itself a RecordTemplate, can I create a projection on it?

At present, you cannot make nested projections using the Java client.

Can I examine a request’s projections on the server side?

In general, examining a request’s projections on the server side will not be necessary. When the server returns an object to the client, the rest framework will take care of stripping all unrequested fields. It is not necessary for the server to examine the projection and strip fields itself.

However, it is possible for the server to examine a request’s projection.

MaskTree projections = getContext().getProjectionMask();

Or, if you are using free-form resources, you can get the same MaskTree by having it injected in, for example:

@RestMethod.Get
public Greeting get(Long key, @Projection MaskTree projection) {
 // ...
}

this will get you the projections of a request. If there were no projections, this will be null.

If there were projections, you can check the status of each field.

MaskOperation mask = projections.getOperations.get(pathSpec);

if (mask == MaskOperation.POSITIVE_MASK_OP)
{
  // field is requested.
}

if (mask == MaskOperation.NEGATIVE_MASK_OP)
{
  // field is not requested.
}

You can then use this information in whatever way you wish to.

Turning off the rest.li framework’s automatic projection

If you choose to examine and apply projections in it’s application, you may also, as a performance optimization, turn off the frameworks automatic projection processing.

This can be done by setting the “projection mode” to manual on the ResourceContext:

getContext().setProjectionMode(ProjectionMode.MANUAL);

For example:

public Greeting get(Long key)
{
  MaskTree mask = context.getProjectionMask();
  if(mask != null)
  { 
    // client has requested a projection of the entity
    getContext().setProjectionMode(ProjectionMode.MANUAL); // since we're manually applying the projection
    // manually examine the projection and apply it entity before returning
    // here we can take advantage of the information the projection provides to only load the data the
    // client requested
  }
  else
  { 
    // client is requesting the full entity
    // construct and return the full entity
  }
}

Clone this wiki locally