将字段注入 JSON 响应对象
Posted
技术标签:
【中文标题】将字段注入 JSON 响应对象【英文标题】:Inject field into JSON response object 【发布时间】:2019-11-23 02:38:20 【问题描述】:我想在序列化期间向响应对象中注入一个字段。是否可以将 "success": "true" 注入 JSON 响应对象?这需要是所有被序列化的父响应对象的通用解决方案。
以对象为例:
public class UserResponse
private int id;
private String firstName;
private String lastName;
private Organisation organisation;
// getters setters
杰克逊应该返回:
"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)
【问题讨论】:
【参考方案1】:将布尔成功添加到 UserResponse 类并在序列化之前设置它。
【讨论】:
【参考方案2】:我猜你需要的是一个
@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。
【讨论】:
但这需要我预先添加这个来添加类。我正在寻找一种方法来添加这个预序列化。所有父响应对象的一种解决方案 如果你的父母是超级班,那么把它放在超级班上。告诉我为什么一个合适的 http 响应代码不足以满足你的 rest 服务? 这是一个 javascript 框架,需要success = true
响应才能使 API 回调正常工作。
这是一种有趣的方法,是的。谢谢【参考方案3】:
您可以使用ResponseBodyAdvice
来修改控制器返回的对象,然后再将其序列化为 JSON。这是一个默认应用于所有响应的简单示例:
控制器返回的视图
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 状态代码。它是协议的一部分,将始终设置。
【讨论】:
看起来是一个非常有趣的解决方案。我现在要试一试。您对状态代码是正确的,这也是最佳实践。但我使用的 javascript 框架需要success = true
响应,API 回调才能正常工作。【参考方案4】:
我不知道这是否可以在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
。
【讨论】:
以上是关于将字段注入 JSON 响应对象的主要内容,如果未能解决你的问题,请参考以下文章
将 AngularJS 对象作为 TypeScript 类注入(缺少方法)