4

I cannot figure out how to add an object to a OneToMany relationship using Spring-Data REST when the mapped classes REST Repository is not exported.

I have two classes, Question and Answer. Question has a member variable defined like this:

@OneToMany(mappedBy = "answer", cascade=CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE) 
private List<Answer> answers = new LinkedList<Answer>();

And Answer maps back to Question like this:

@NotNull
@ManyToOne(targetEntity = Question.class)
@JoinColumn(name = "question_id", referencedColumnName = "id") 
private Question question;

Because Answer objects are only relevant to the Question they belong to, I've disabled exporting the REST repository:

@RestResource(exported = false)
public interface AnswerRepository extends JpaRepository<Answer, Long> {}

When I fetch a question here: http://localhost:9090/data/questions/7, I get something like this:

{
    "creationDate": "2014-09-26T06:36:44.000+0000",
    "modificationDate": "2014-09-26T06:36:44.000+0000",
    "answers": [],
    "_links": {
        "self": {
            "href": "http://localhost:9090/data/questions/7"
        }
    }
}

So far so good. Now I want to add an answer like this:

curl -v -X PUT -H "Content-Type: application/json" \
    -d "{"answers": [{"value": "Red"}]}" http://localhost:9090/data/questions/7

Unfortunately, at this point I get the following error:

A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: com.example.Question.answers

A brief search of StackOverflow indicates the above error is caused by replacing your collection with another one, orphaning the previous collection. Since all of this code managed by Spring, I don't see how to manipulate my objects to avoid this problem.

This question is similar, however the difference is that in this case the repository is not exported, while in that question it is.

Community
  • 1
  • 1
JBCP
  • 13,109
  • 9
  • 73
  • 111
  • I solved this problem by writing a custom controller to handle a POST to http://localhost:9090/data/questions/7/answers, but I don't consider that an answer to this SO question. – JBCP Oct 10 '14 at 14:15
  • It shouldn't be necessary to implement your own controller. Your command doesn't add an answer, btw. – a better oliver Oct 13 '14 at 14:51
  • I agree it shouldn't be necessary, but I don't have another solution. Do you mean my comment doesn't add an answer? That's because I don't consider it an answer to the question. – JBCP Oct 13 '14 at 20:16
  • Your command (= `curl ...`), not comment, doesn't add an `Answer` to a `Question`. If anything it replaces all answers. Posting to `localhost:9090/data/questions/7/answers` should work out of the box - have you tried it? – a better oliver Oct 14 '14 at 07:10
  • @zeroflagL - You are correct, the `curl` command I showed above is intended to set all answers, which I would expect to be a valid operation, but it doesn't work. Yes I tried POSTing to `...questions/7/answers`, that is what prompted this question. When you have `@RestResource(exported = false)` on your repository, it disables access to that URL and you get an HTTP 405 error. – JBCP Oct 14 '14 at 18:03
  • I haven't tried 'rel', but I doubt it will help, according to the documentation it just modifies `answers` to whatever string you want. What I really want is to have the answer objects provided in the Question GET, and then be able to update them somehow. The REST way (`questions/7/answers`) would be fine, but I'll take anything. – JBCP Oct 15 '14 at 00:45

1 Answers1

0

If you're using PUT you should be sending text/uri-list media type. But I don't see how would you do that since you did not export Answer repository thus you can not call POST on it first.

Did you try PATCH? It's not documented that way though...

rikica
  • 351
  • 2
  • 11