将字段注入 JSON 响应对象
Inject field into JSON response object
我想在序列化期间向响应对象中注入一个字段。是否可以将 "success": "true" 注入到 JSON 响应对象中?这需要成为所有序列化的父响应对象的通用解决方案。
例如对象:
public class UserResponse {
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
// getters setters
}
杰克逊应该return:
{
"success": "true",
"id": 1,
"firstName": "tom",
"lastName": "jeffrey",
"organisation": {
// etc.
}
}
我已经尝试过
public class CustomJsonSerializer extends StdSerializer<Object> {
public CustomJsonSerializer() {
this(null);
}
public CustomJsonSerializer(Class<Object> t) {
super(t);
}
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("success", "true");
jsonGenerator.writeObject(o);
jsonGenerator.writeEndObject();
}
}
但是没有成功:
Could not write JSON: Can not start an object, expecting field name (context: Object); nested exception is com.fasterxml.jackson.core.JsonGenerationException: Can not start an object, expecting field name (context: Object)
将布尔成功添加到 UserResponse class 并在序列化之前设置它。
我想你需要的是
@JsonAppend(attrs = {@JsonAppend.Attr(value = "success")})
public class UserResponse implements Serializable {
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
// getters setters
}
你调查过吗?
这是我认为应该如何完成的示例。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
import org.junit.Assert;
import org.junit.Test;
import java.io.Serializable;
public class InjectFieldTest {
@Test
public void testResponse() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
final UserResponse response =
new UserResponse(1, "Stack", "Overfloww", new Organisation("Developers"));
final ObjectWriter writer =
mapper.writerFor(UserResponse.class).withAttribute("success", "true");
final String out = writer.writeValueAsString(response);
System.out.println("jsData = " + out);
Assert.assertTrue(out.contains("success"));
}
@JsonAppend(attrs = {@JsonAppend.Attr(value = "success")})
private class UserResponse implements Serializable {
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
public UserResponse(int id, String firstName, String lastName, Organisation organisation) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.organisation = organisation;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Organisation getOrganisation() {
return organisation;
}
}
private class Organisation {
private String name;
public Organisation(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
根据您的成功标准,您可以将此值设置为 true 或 false。
在序列化为 JSON 之前,您可以使用 ResponseBodyAdvice
修改控制器返回的对象。这是一个默认应用于所有响应的简单示例:
查看你的控制器returns
public class Greeting {
private static final String message = "Hello World!";
public String getMessage() {
return message;
}
}
设置状态的响应包装器
public class ResponseWrapper {
private Object data;
private boolean success;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
控制器
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public Greeting hello() {
return new Greeting();
}
}
验证行为的测试
@RunWith(SpringJUnit4ClassRunner.class)
@WebMvcTest
public class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
private static final String GREETING_ENDPOINT = "/api/hello";
@Test
public void returnsGreetingWithStatus() throws Exception {
mockMvc.perform(get(GREETING_ENDPOINT))
.andExpect(jsonPath("$.data.message").value("Hello World!"))
.andExpect(jsonPath("$.success").value(true));
}
}
ResponseBodyAdvice
@ControllerAdvice
public class ResponseStatusAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return converterType.equals(MappingJackson2HttpMessageConverter.class);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
ResponseWrapper wrapper = new ResponseWrapper();
wrapper.setData(body);
wrapper.setSuccess(true);
return wrapper;
}
}
这应该会给您一个良好的开端。
附带说明一下,您始终可以利用 HTTP 状态代码。它是协议的一部分,将始终设置。
我不知道这是否可以在 serialization
期间完成。但是如果你愿意,你可以稍微修改你的 Response
以通用方式实现你想要的:
public class ServiceResponse <T>{
private boolean success;
//your data which you want to access/use in client side. You can pass `UserResponse` or whatever class you want to pass as general.
private T data;
}
现在,将您的值设置为此 class
对象,然后 serialize
。如果需要,您可以为自定义消息添加 message
字符串字段。
现在,ServiceResponse
也将接受其他 classes
。
我想在序列化期间向响应对象中注入一个字段。是否可以将 "success": "true" 注入到 JSON 响应对象中?这需要成为所有序列化的父响应对象的通用解决方案。
例如对象:
public class UserResponse {
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
// getters setters
}
杰克逊应该return:
{
"success": "true",
"id": 1,
"firstName": "tom",
"lastName": "jeffrey",
"organisation": {
// etc.
}
}
我已经尝试过
public class CustomJsonSerializer extends StdSerializer<Object> {
public CustomJsonSerializer() {
this(null);
}
public CustomJsonSerializer(Class<Object> t) {
super(t);
}
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("success", "true");
jsonGenerator.writeObject(o);
jsonGenerator.writeEndObject();
}
}
但是没有成功:
Could not write JSON: Can not start an object, expecting field name (context: Object); nested exception is com.fasterxml.jackson.core.JsonGenerationException: Can not start an object, expecting field name (context: Object)
将布尔成功添加到 UserResponse class 并在序列化之前设置它。
我想你需要的是
@JsonAppend(attrs = {@JsonAppend.Attr(value = "success")})
public class UserResponse implements Serializable {
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
// getters setters
}
你调查过吗?
这是我认为应该如何完成的示例。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
import org.junit.Assert;
import org.junit.Test;
import java.io.Serializable;
public class InjectFieldTest {
@Test
public void testResponse() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
final UserResponse response =
new UserResponse(1, "Stack", "Overfloww", new Organisation("Developers"));
final ObjectWriter writer =
mapper.writerFor(UserResponse.class).withAttribute("success", "true");
final String out = writer.writeValueAsString(response);
System.out.println("jsData = " + out);
Assert.assertTrue(out.contains("success"));
}
@JsonAppend(attrs = {@JsonAppend.Attr(value = "success")})
private class UserResponse implements Serializable {
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
public UserResponse(int id, String firstName, String lastName, Organisation organisation) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.organisation = organisation;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Organisation getOrganisation() {
return organisation;
}
}
private class Organisation {
private String name;
public Organisation(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
根据您的成功标准,您可以将此值设置为 true 或 false。
在序列化为 JSON 之前,您可以使用 ResponseBodyAdvice
修改控制器返回的对象。这是一个默认应用于所有响应的简单示例:
查看你的控制器returns
public class Greeting {
private static final String message = "Hello World!";
public String getMessage() {
return message;
}
}
设置状态的响应包装器
public class ResponseWrapper {
private Object data;
private boolean success;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
控制器
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public Greeting hello() {
return new Greeting();
}
}
验证行为的测试
@RunWith(SpringJUnit4ClassRunner.class)
@WebMvcTest
public class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
private static final String GREETING_ENDPOINT = "/api/hello";
@Test
public void returnsGreetingWithStatus() throws Exception {
mockMvc.perform(get(GREETING_ENDPOINT))
.andExpect(jsonPath("$.data.message").value("Hello World!"))
.andExpect(jsonPath("$.success").value(true));
}
}
ResponseBodyAdvice
@ControllerAdvice
public class ResponseStatusAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return converterType.equals(MappingJackson2HttpMessageConverter.class);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
ResponseWrapper wrapper = new ResponseWrapper();
wrapper.setData(body);
wrapper.setSuccess(true);
return wrapper;
}
}
这应该会给您一个良好的开端。 附带说明一下,您始终可以利用 HTTP 状态代码。它是协议的一部分,将始终设置。
我不知道这是否可以在 serialization
期间完成。但是如果你愿意,你可以稍微修改你的 Response
以通用方式实现你想要的:
public class ServiceResponse <T>{
private boolean success;
//your data which you want to access/use in client side. You can pass `UserResponse` or whatever class you want to pass as general.
private T data;
}
现在,将您的值设置为此 class
对象,然后 serialize
。如果需要,您可以为自定义消息添加 message
字符串字段。
现在,ServiceResponse
也将接受其他 classes
。