spring boot jpa projections

I was using Spring JPA REST features in a project recently when I ran into a problem with nested resources in my REST JSON:

Below is my JPA repository:

    @RepositoryRestResource(collectionResourceRel = "user", path = "user", excerptProjection = UserInlineFavorites.class)
	public interface UserRepository extends CrudRepository<User, String> {

		User findByEmailAndPassword(@Param("email") String email, @Param("password") String password);

	}

This resulted in the following JSON:

{
  "name" : "test",
  "email" : "test@gmail.com",
  "password" : "test",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/user/test"
    },
    "user" : {
      "href" : "http://localhost:8080/user/test@gmail.com",
      "templated" : true
    },
    "favorites" : {
      "href" : "http://localhost:8080/user/test@gmail.com/favorites"
    }
  }
}

The problem with this is the nested favorites entities have to obtained using another REST call which seemed like a waste to me. After digging around for a while, I came across the concept of Projections to obtain fully resolved entities:

Create a projection interface to define the structure of the resolved entity:

package com.kkrishna.gymtime.dao;

import java.util.List;

import org.springframework.data.rest.core.config.Projection;

@Projection(name = "inlineFavorites", types = { User.class })
public interface UserInlineFavorites {

	public String getName() ;

	public String getEmail();

	public String getPassword() ;

	public List<Gym> getFavorites() ;
}

Add the below to the Spring configuration to force it to always use the projection:

config.getProjectionConfiguration().addProjection(UserInlineFavorites.class, User.class);

Finally change the repository to add the projection:

@RepositoryRestResource(collectionResourceRel = "user", path = "user", excerptProjection = UserInlineFavorites.class)
public interface UserRepository extends CrudRepository<User, String> {

	User findByEmailAndPassword(@Param("email") String email, @Param("password") String password);

}

Now the resulting json is:

{
  "name" : "test",
  "favorites" : [ {
    "latLong" : "33.64_-117.86",
    "name" : "Pilates Plus Newport Beach",
    "address" : "1220 Bison Ave, Newport Beach, CA 92660"

  }, {
    "latLong" : "33.65_-117.84",
    "name" : "Yoga Shakti Wellness Center",
    "address" : "4249 Campus Dr B140, Irvine, CA 92612"
  }, {
    "latLong" : "33.66_-117.86",
    "name" : "Equinox Newport Beach",
    "address" : "19540 Jamboree Rd, Irvine, CA 92612"
  }, {
    "latLong" : "33.63_-117.83",
    "name" : "Merage Jewish Community Center of Orange County",
    "address" : "1 Federation Way #200, Irvine, CA 92603"
  } ],
  "email" : "test@gmail.com",
  "password" : "mirage2000",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/user/test@gmail.com"
    },
    "user" : {
      "href" : "http://localhost:8080/user/test@gmail.com{?projection}",
      "templated" : true
    },
    "favorites" : {
      "href" : "http://localhost:8080/user/test@gmail.com/favorites"
    }
  }
}

The caveat to this is that to retrieve single resources you have to add the projection to the URL:

http://localhost:8080/user/test@gmail.com?projection=inlineFavorites

more discussion on StackOverflow