I have the same form that displays more or less fields depending on the user's role. So I use @JsonView to hide/ignore the fields that are not related to the current user's role. But the validation is still enabled and the @NotNull
rule is triggered.
@JsonView({View.Admin.class, View.Tech.class})
@NotNull
private String name;
I would like to find a way to enable or disable some validation annotations for example when the user's role is not administrator.
Is it possible to use these view (View.Admin.class
/ View.Tech.class
) as a group for validation please?
CodePudding user response:
We can do this!
(no spring-security, for simplicity) just:
With ("trick" is to use interfaces instead of classes!):
class View { interface Public { } interface User extends Public { } interface Admin extends User { } }
And (referring to the same interfaces as @JsonView and as "validation group"):
class MyDto { // visible by/validated for all: @NotNull(groups = View.Public.class) @JsonView(View.Public.class) private String foo; // visible by/validated for "User" @JsonView(View.User.class) @NotNull(groups = View.User.class) private String bar; // visible by/validated for "Admin" (and "User") @JsonView(View.Admin.class) @NotNull(groups = View.Admin.class) private String baz; // getter setter !! (hashcode, equals..)
We can try:
@RestController class DemoController { @PostMapping("/foo") @JsonView(View.Public.class) public MyDto foo( @Validated(View.Public.class) @RequestBody MyDto dto) { return dto; } @PostMapping("/bar") @JsonView(View.User.class) public MyDto bar( @Validated(View.User.class) @RequestBody MyDto dto) { return dto; } @PostMapping("/baz") @JsonView(View.Admin.class) public MyDto baz( @Validated(View.Admin.class) @RequestBody MyDto dto) { return dto; } }
Test
package com.example.jsonviewsmeetsvalidationgroups;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class DemoControllerTest {
@Autowired
MockMvc mvc;
@Test
void testPublicGood() throws Exception {
mvc.perform(
post("/foo")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"foo\":\"Test1\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.foo").value("Test1"));
}
@Test
void testPublicInvalid1() throws Exception {
mvc.perform(
post("/foo")
.contentType(MediaType.APPLICATION_JSON)
.content("{}")
)
.andExpect(status().isBadRequest());
}
@Test
void testUserGood() throws Exception {
mvc.perform(post("/bar")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"foo\":\"Test1\", \"bar\":\"Test2\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.foo").value("Test1"))
.andExpect(jsonPath("$.bar").value("Test2"));
}
@Test
void testUserInvalid1() throws Exception {
mvc.perform(post("/bar")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andExpect(status().isBadRequest());
}
@Test
void testUserInvalid2() throws Exception {
mvc.perform(post("/bar")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"foo\":\"Test1\"}")
).andExpect(status().isBadRequest());
}
// analogous for "/baz" / Admin ...
}
CodePudding user response:
use @JsonIgnore may help you to achieve,because it will ignore the column and validation annotation as well