Dealing with m-to-n relations in @RepositoryRestResource

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-23 10:01:45

问题


Preface

I want to create a sub-resource of another resource in one call. These resources have a @ManyToMany relationship: Users and Groups.

I do not want to create first a user, then the group and after that the relation as it is shown in Working with Relationships in Spring Data REST - simply because I think a resource that cannot exist on its own, such as a group, should only be created if at least one user is also associated with that resource. For this I require a single endpoint like this one (which is not working for me, otherwise I wouldn't be here) that creates a group and also sets the associated "seeding" user in one transaction.

Currently, the only way to make this work for me is to "synchronize" the relation manually like this:

public void setUsers(Set<AppUser> users) {
    users.forEach(u -> u.getGroups().add(this));
    this.users = users;
}

this would allow me to

POST http://localhost:8080/groups

{
  "name": "Group X",
  "users": ["http://localhost:8080/users/1"]
}

but my problem with that is that this does not feel right to me - it does seem like a workaround and not the actual Spring-way to make this requirement work. So ..


I'm currently struggling with creating relational resources using Spring's @RepositoryRestResource. I want to create a new group and associate it with the calling user like this:

POST http://localhost:8080/users/1/groups

{
  "name": "Group X"
}

but the only result is the response 204 No Content. I have no idea why. This may or may not be related to another question of mine (see here) where I try to achieve the same by setting the relating resource in the JSON payload - that doesn't work either.

Server side I am getting the following error:

tion$ResourceSupportHttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class org.springframework.hateoas.Resources<java.lang.Object>]]: java.lang.NullPointerException

Please let me know in case you need any specific code.

Tried

I added exported = false to the @RepositoryRestResource of UserGroupRepository:

@RepositoryRestResource(collectionResourceRel = "groups", path = "groups", exported = false)
public interface UserGroupRepository extends JpaRepository<UserGroup, Long> {
    List<UserGroup> findByName(@Param("name") String name);
}

and I am sending:

PATCH http://localhost:8080/users/1

{
  "groups": [
    {
      "name": "Group X"
    }
  ]
}

However, the result is still just 204 No Content and a ResourceNotFoundException on the server side.


Unit Test

Essentially, the following unit test is supposed to work but I can also live with an answer why this cannot work and which also shows how this is done correctly.

@Autowired
private TestRestTemplate template;

private static String USERS_ENDPOINT = "http://localhost:8080/users/";
private static String GROUPS_ENDPOINT = "http://localhost:8080/groups/";

// ..

@Test
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public void whenCreateUserGroup() {

    // Creates a user
    whenCreateAppUser();

    ResponseEntity<AppUser> appUserResponse = template.getForEntity(USERS_ENDPOINT + "1/", AppUser.class);
    AppUser appUser = appUserResponse.getBody();

    UserGroup userGroup = new UserGroup();
    userGroup.setName("Test Group");
    userGroup.setUsers(Collections.singleton(appUser));

    template.postForEntity(GROUPS_ENDPOINT, userGroup, UserGroup.class);

    ResponseEntity<UserGroup> userGroupResponse = template.getForEntity(GROUPS_ENDPOINT + "2/", UserGroup.class);

    Predicate<String> username = other -> appUser.getUsername().equals(other);

    assertNotNull("Response must not be null.", userGroupResponse.getBody());

    assertTrue("User was not associated with the group he created.",
            userGroupResponse.getBody().getUsers().stream()
                    .map(AppUser::getUsername).anyMatch(username));
}

However, the line

userGroup.setUsers(Collections.singleton(appUser)); 

will break this test and return a 404 Bad Request.


回答1:


According to SDR reference:

POST

Only supported for collection associations. Adds a new element to the collection. Supported media types:

text/uri-list - URIs pointing to the resource to add to the association.

So to add group to user try to do this:

POST http://localhost:8080/users/1/groups (with Content-Type:text/uri-list)
http://localhost:8080/groups/1

Additional info.



来源:https://stackoverflow.com/questions/47377464/dealing-with-m-to-n-relations-in-repositoryrestresource

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!