Вот моя конфигурация объектного сопоставителя.Я предоставляю свой собственный объектный сопоставитель, так что включенный в весенний загрузчик объектный сопоставитель 2.0 переопределяется.Несмотря на это, я также включил JsonComponentModule (), чтобы я мог использовать аннотацию @JsonComponent
для получения пользовательских сериализаторов.
public class ObjectMapperConfigurer {
public static ObjectMapper configureObjectMapper(ObjectMapper objectMapper) {
return objectMapper.registerModules(
// First three modules can be found here. https://github.com/FasterXML/jackson-modules-java8
new Jdk8Module(), // support for other new Java 8 datatypes outside of date/time: most notably Optional, OptionalLong, OptionalDouble
new JavaTimeModule(), // support for Java 8 date/time types (specified in JSR-310 specification)
new ParameterNamesModule(), // Support for detecting constructor and factory method ("creator") parameters without having to use @JsonProperty annotation
// These two modules are provided by spring
new JsonComponentModule(), // Enables https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-json-components
new GeoModule(), // Enables marshalling of GeoResult<T>, GeoResults<T>, and GeoPage<T>
new Hibernate5Module().enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING) // Allows jackson to gracefully handle Hibernate lazy loading,
)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
// Turn on/off some features. https://github.com/FasterXML/jackson-databind/wiki/JacksonFeatures
.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
.enable(SerializationFeature.INDENT_OUTPUT)
.enable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
.disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)
.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.setFilterProvider(new SimpleFilterProvider().addFilter(FilteringAnnotationInspector.DEFAULT_FILTER, new DepthFilter()))
.setAnnotationIntrospector(new FilteringAnnotationInspector());
}
public static ObjectMapper configureObjectMapper() {
return configureObjectMapper(new ObjectMapper());
}
}
Вот мой собственный сериализатор.Ничего страшного, если реализация сериализации неверна, моя основная проблема в том, что она не вызывается.
@JsonComponent
public class PageJsonSerializer extends JsonSerializer<Page> {
@Override
public void serialize(Page page, JsonGenerator jsonGen, SerializerProvider serializerProvider) throws IOException {
System.out.println("serializing using pagejsonserializer");
ObjectMapper om = new ObjectMapper()
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
jsonGen.writeStartObject();
jsonGen.writeFieldName("size");
jsonGen.writeNumber(page.getSize());
jsonGen.writeFieldName("number");
jsonGen.writeNumber(page.getNumber());
jsonGen.writeFieldName("totalElements");
jsonGen.writeNumber(page.getTotalElements());
jsonGen.writeFieldName("last");
jsonGen.writeBoolean(page.isLast());
jsonGen.writeFieldName("totalPages");
jsonGen.writeNumber(page.getTotalPages());
jsonGen.writeObjectField("sort", page.getSort());
jsonGen.writeFieldName("first");
jsonGen.writeBoolean(page.isFirst());
jsonGen.writeFieldName("numberOfElements");
jsonGen.writeNumber(page.getNumberOfElements());
jsonGen.writeFieldName("content");
jsonGen.writeRawValue(om.writerWithView(serializerProvider.getActiveView()).writeValueAsString(page.getContent()));
jsonGen.writeEndObject();
}
}
Вот контроллер, возвращающий объект Page (d).
@GetMapping(JobController.uri.path)
@PreAuthorize("hasAuthority('" + SpringSecurityConfig.Authority.LIST_JOBS + "')")
public Page<Job> listJobs(Pageable pageable) {
return jobRepository.findAllByCandidates(currentUserHolder.getUser(), pageable);
}
Я ожидаю, что приведенное выше приведет к вызову класса PageJsonSerializer.Я вижу, что этот класс успешно регистрируется с помощью JsonComponentModule ().Я также пробовал много разных вариантов объявления класса.Как и в следующем, но ни один из них не имел никакого эффекта.
public class PageJsonSerializer extends JsonSerializer<Page<?>> {
public class PageJsonSerializer extends JsonSerializer<PageImpl> {
Я не уверен, что проверить дальше.Я также изо всех сил пытаюсь увидеть, где Джексон выстраивает объект, который он собирается сериализовать, с помощью сериализатора при отладке обратного отключения из JobController.
Наконец, и я не думаю, что это проблема, я 'используя RestControllerAdvice
расширение AbstractMappingJacksonResponseBodyAdvice
, которое выбирает jsonView, который я хочу использовать, основываясь на роли currentUser.
РЕДАКТИРОВАТЬ: Я только что закомментировал совет контроллера, и он все еще не вызывает мой пользовательский десериализатор.
@RestControllerAdvice
@Slf4j
class SecurityJsonViewControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {
@Override
protected void beforeBodyWriteInternal(
@NotNull MappingJacksonValue bodyContainer,
@NotNull MediaType contentType,
@NotNull MethodParameter returnType,
@NotNull ServerHttpRequest request,
@NotNull ServerHttpResponse response) {
if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().getAuthorities() != null) {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
Class<?> viewClass = User.Role.jsonViewFrom(authorities);
if (true || log.isDebugEnabled()) {
log.debug("Deserializing using view {}", viewClass.getSimpleName());
}
bodyContainer.setSerializationView(viewClass);
}
}
}