Spring Data Neo4j 5 - HttpMessageNotWritableException when hitting resource endpoints

167 Views Asked by At

In an attempt to recreate the Spring Data Neo4j official Movies example in Scala I have ran into an issue jsonifying on the Spring Data Neo4j layer.

The details are noted in the README in this example project.

Booting the Spring app and hitting /movies/<id> gives the following stacktrace:

018-03-27 15:33:23 WARN DefaultHandlerExceptionResolver:442 - Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Invalid Object Id definition for movies.Movie: cannot find property with name 'id'; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid Object Id definition for movies.Movie: cannot find property with name 'id' (through reference chain: org.springframework.hateoas.PagedResources["_embedded"]->java.util.Collections$UnmodifiableMap["movies"]->java.util.ArrayList[0])

I have opened an official Spring Data Neo4j JIRA issue here.

Edit: After the latest comment, I have removed unrelated theories about the root cause from this post. And I have updated the example project to expose the IDs on the Spring Data Rest layer using a PostConstruct method (thanks @meistermeier). I also tried the RepositoryRestConfigurerAdapter method. However, the original HttpMessageNotWritableException persists. Any ideas?

Update: Modeling Movie.scala after SDN-University example, I tried using com.voodoodyne.jackson.jsog.JSOGGenerator as an Object ID Generator. I can successfully hit /movies/ but the only key is "id", and it's simply an index, and not the actual id. However, 38 movies do return, the amount in the Movies data set. I would think this narrows down the issue to the jsonfying part.

Update 2: By using a bandaid to manually form the json in the controller (using an object-to-map function, and a map-to-json function) I am finally able to send data out through the endpoints. I have updated the example project to demonstrate this. I can successfully retrieve objects from the movieRepository, and manipulate them as I please. I think this has clearly narrowed down the problem to the jsonification. Does anyone have a clear example (Java or Scala) on how to properly annotate NodeEntity with JsonIdentifyInfo?

2

There are 2 best solutions below

0
On BEST ANSWER

Finally, after more than a month I have solved the problem.

You must add scala.beans.BeanProperty to any vars that need generated getters and setters.

Added this to my NodeEntity properties as well as on the sessionFactory bean and the transactionManager bean, and all my problems magically vanished.

It would make sense to document this required annotation to use these libraries in Scala.

1
On

First a note on the id as String part: The internal Neo4j id has to be of type Long (paragraph between the info sections here: https://neo4j.com/docs/ogm-manual/current/reference/#reference:annotating-entities:entity-identifier). With another type than Long Neo4j OGM is unable to find the, so called, native id field on your class.

Now back to the initial problem you are facing. Spring Data Rest suppresses the exposure of id-like fields and Spring Data Neo4j will mark/register fields with an @Id annotation as such. To use this id fields you could for example do something like this:

public class SpringBootApplication {
  private final RepositoryRestConfiguration configuration;

  public SpringBootApplication(RepositoryRestConfiguration configuration) {
    this.configuration=configuration;
  }

  @PostConstruct
  public void configuration() {
    configuration.exposeIdsFor(Person.class);
  }

I know that this is Java, so this but more Scala-ish.

Side notes:

  • We are currently upgrading the movie sample
  • This problem is totally unrelated to the class loading bug