3
votes

I am working on some code that is using spring-data-neo4j (SDN) and spring-data-rest-mvc to store and access graph data that would have cyclic characteristics. I'm using spring-data-rest-mvc to access the HATEOAS functionality to allow clients to navigate the graph by following the links.

As a simple example, I've taken the gs-accessing-neo4j-data-rest code from http://spring.io/guides/gs/accessing-neo4j-data-rest/ and enhanced the Person class with a kind of social aspect, namely "friends" as:

@RelatedTo(type = "FRIENDS_WITH", direction = Direction.BOTH)
Set<Person> friends = new HashSet<Person>();

i.e. a bidirectional relationship between Person instances.

I loaded a set of sample data and established random friend relationships between them. All good so far.

If I hit

http://localhost:8080/people/408 

I get the expected:

{
  "firstName" : "Remona",
  "lastName" : "Heier",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/408"
    },
    "friends" : {
      "href" : "http://localhost:8080/people/408/friends"
    }
  }
}

If I hit

http://localhost:8080/people/408/friends

however, I get

{
  "_embedded" : {
    "people" : [ {
      "firstName" : null,
      "lastName" : null,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/189"
        },
        "friends" : {
          "href" : "http://localhost:8080/people/189/friends"
        }
      }
    }, {
      "firstName" : null,
      "lastName" : null,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/34"
        },
        "friends" : {
          "href" : "http://localhost:8080/people/34/friends"
        }
      }
    }
  }
}

which contains null values for firstName and lastName.

Hitting one of those friends directly, e.g.

http://localhost:8080/people/189

I get:

{
  "firstName" : "Zita",
  "lastName" : "Speltz",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/189"
    },
    "friends" : {
      "href" : "http://localhost:8080/people/189/friends"
    }
  }
}

I understand why I'm getting the nulls - there's no @Fetch on the friends Set, so the friends aren't actually fetched - only the node id is known and that is used to build the self and friends hrefs. But the output that is produced with the null values is wrong - it's a misrepresentation of the data.

I can't include @Fetch on the friends Set as that would send the app into a spin and overflow the stack, so that's where I'm stuck. I want to see the non-relationship properties of the friends shown when the friends are listed, i.e. I want to see:

{
  "_embedded" : {
    "people" : [ {
      "firstName" : "Zita",
      "lastName" : "Speltz",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/189"
        },
        "friends" : {
          "href" : "http://localhost:8080/people/189/friends"
        }
      }
    }, {
      "firstName" : "Ciara",
      "lastName" : "Cobbley",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/34"
        },
        "friends" : {
          "href" : "http://localhost:8080/people/34/friends"
        }
      }
    }
  }
}

Does anyone know how I can achieve this?

Many thanks in advance.

1
You could try the advanced mapping with AspectJ, related objects are loaded dynamically as soon as they are accessed.remigio

1 Answers

1
votes

This appears to be a bug in spring-data or spring-data-rest. I ran into the same thing on lazily-fetched entities using spring-data-rest 2.3.0 with spring-data-jpa. The only way I've been able to get the output that you want, i.e. the entity information actually showing up, is to eagerly fetch the related entities. You said you can't do that, so the only option I see is for you to write your own controller that returns the correct data. You'd only need to overwrite the requestMappings of the referenced entities, since the spring-data-rest controllers will still handle any requestMappings that your controllers don't handle. The spring-restbucks project has an example of a custom contoller here:

https://github.com/olivergierke/spring-restbucks/blob/master/src/main/java/org/springsource/restbucks/payment/web/PaymentController.java

You'd need to add a method to handle the "/people/{id}/friends" requestMapping, and populate the Resource yourself with data and links.