我有一個用JacksonAnnotationIntrospector設置的自定義註釋,根據API版本吐出正確的屬性名稱。還有一個助手類,它再次根據API版本吐出正確的ObjectMapper。發送回覆時未使用MessageBodyWriter
public class ObjectMapperFactory {
private static final ObjectMapper objectMapper_V1 = new ObjectMapper().setAnnotationIntrospector(new VersioningPropertiesIntrospector(Entity.ApiVersion.V1));
private static final ObjectMapper objectMapper_V2016 = new ObjectMapper().setAnnotationIntrospector(new VersioningPropertiesIntrospector(Entity.ApiVersion.V2016));
public static ObjectMapper getObjectMapper(Entity.ApiVersion version) {
switch (version) {
case V1:
return objectMapper_V1;
case V2016:
return objectMapper_V2016;
case INVALID:
return null;
}
return null;
}
}
還有用於測試序列
public static String serializeEntity(Entity.ApiVersion version, Object object) {
try {
return getObjectMapper(version).writeValueAsString(object);
} catch (JsonProcessingException e) {
log.error(e.toString());
}
return "Invalid API version.";
}
在單元測試這樣的輔助函數:
@Test
public void testSerializeUserWithStateField() {
User user = new User();
user.setVersion(Entity.ApiVersion.V2016);
user.setState(EntityState.CREATED.name());
String userJson = serializeEntity(user.getVersion(), user);
assertThat(userJson, equalTo("{\"lifecycleState\":\"CREATED\"}"));
}
現在,說我有這樣的事情:
@GET
@Path("users/{userId}")
public Response getUser(@PrincipalContext Principal principal,
@AuthorizationRequestContext AuthorizationRequest authorizationRequest,
@PathParam("userId") String userId) {
final String decodedId = Optional
.ofNullable(RequestValidationHelper.decodeUrlEncodedOCID(userId))
.filter(StringUtils::isNotEmpty)
.orElseThrow(BadArgumentException::new);
User user = userStore.getUser(decodedId)
.orElseThrow(OperationNotAllowedException::new);
log.debug("Successfully retrieved user '{}'", decodedId);
return Response.status(Response.Status.OK)
.header(HttpHeaders.ETAG, user.getEtag())
.entity(user)
.build();
}
其中用戶擴展實體:
public abstract class Entity {
private String id;
private String userId;
@JsonIgnore
private String etag;
@VersioningProperties({
@VersioningProperties.Property(version = ApiVersion.V1, value = "state"),
@VersioningProperties.Property(version = ApiVersion.V2016, value = "lifecycleState")
})
private String state;
@JsonIgnore
private ApiVersion version = ApiVersion.INVALID;
public enum ApiVersion {
INVALID,
V1,
V2016
}
}
我知道映射器單獨返回正確的JSON。在構造Responses時,我可以在.entity()中插入對serializeEntity的調用,但是這導致我們的測試出現問題,這些問題檢查Response中的實體是否是相同類型(例如User)。如果他們發現單個對象的序列化版本或任何對象的序列化列表的字符串,例如,它們會中斷。
如果我正確理解它,應該挑選一個帶有@Provider註解的MessageBodyWriter,並在序列化指定對象(我們使用Dropwizard和Jersey)時使用它。
@Provider
public class EntityMessageBodyWriter implements MessageBodyWriter<Entity> {
@Override
public long getSize(Entity entity, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return 0;
}
@Override
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return Entity.class.isAssignableFrom(aClass);
}
@Override
public void writeTo(Entity entity, Class<?> aClass, Type type, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap, OutputStream outputStream)
throws IOException, WebApplicationException {
outputStream.write(serializeEntity(entity.getVersion(), entity).getBytes());
}
}
但是,情況並非如此。我沒有爲每個對象創建一個單獨的MessageBodyWriter,因爲文檔說你可以使用超類,並且所有的子類都會匹配(假設你在isWriteable()函數中返回true)。我還嘗試過使用JSON媒體類型指定@Produces並指定一個子類(如User)而不是Entity,但似乎沒有任何效果。
我也試圖與註冊MessageBodyWriter:
JerseyEnvironment jersey = env.jersey();
jersey.register(new IdentityEntityMessageBodyWriter());
但所有做的是打破幾乎每一個測試,我們有(500S,409S,等等)。
我試圖根據API版本state
更改的變量在響應V2016 API調用時從未設置爲lifecycleState
。我怎樣才能使這個工作正常?
嗨,你可以添加拋出你的問題的異常? – pandaadb
實際上並沒有例外。它編譯並運行,但它只是吐出屬性名稱的錯誤版本。 – Gemini14
你的消息是否被調用?在serializeEntity中設置斷點時,發生了什麼?這是一個生產問題(例如,您在運行服務器時看到這種情況是否失敗)還是集成測試問題? – pandaadb