Я пытаюсь написать модульный тест для пользовательского десериализатора, который создается с использованием конструктора с параметром @Autowired, а моя сущность помечена @JsonDeserialize. Он отлично работает в моих интеграционных тестах, где Mock Mvc поднимает пружинный сервер.
Однако в тестах, где вызывается objectMapper.readValue (...), создается новый экземпляр десериализатора с использованием конструктора по умолчанию без параметров. Хотя
@Bean
public MyDeserializer deserializer(ExternalObject externalObject)
создает экземпляр проводной версии десериализатора, реальный вызов все еще передается пустому конструктору, а контекст не заполняется.
Я попытался вручную создать экземпляр десериализатора и зарегистрировать его. в ObjectMapper, но он работает только в том случае, если я удаляю @JsonDeserialize из моего класса сущности (и это нарушает мои интеграционные тесты, даже если я делаю то же самое в своем классе @Configuration.) - выглядит так: https://github.com/FasterXML/jackson-databind/issues/1300
Я все еще могу проверить поведение десериализатора, вызывая deserializer.deserialize (...) напрямую, но этот подход не работает для меня в тестах, которые не являются модульными тестами Десериализатора ...
UPD: рабочий код ниже
import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.github.tomakehurst.wiremock.common.Json;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import java.io.IOException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@JsonTest
@RunWith(SpringRunner.class)
public class JacksonInjectExample {
private static final String JSON = "{\"field1\":\"value1\", \"field2\":123}";
public static class ExternalObject {
@Override
public String toString() {
return "MyExternalObject";
}
}
@JsonDeserialize(using = MyDeserializer.class)
public static class MyEntity {
public String field1;
public String field2;
public String name;
public MyEntity(ExternalObject eo) {
name = eo.toString();
}
@Override
public String toString() {
return name;
}
}
@Component
public static class MyDeserializer extends JsonDeserializer<MyEntity> {
@Autowired
private ExternalObject external;
public MyDeserializer() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public MyDeserializer(@JacksonInject final ExternalObject external) {
this.external = external;
}
@Override
public MyEntity deserialize(JsonParser p, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
return new MyEntity(external);
}
}
@Configuration
public static class TestConfiguration {
@Bean
public ExternalObject externalObject() {
return new ExternalObject();
}
@Bean
public MyDeserializer deserializer(ExternalObject externalObject) {
return new MyDeserializer(externalObject);
}
}
@Test
public void main() throws IOException {
HandlerInstantiator hi = mock(HandlerInstantiator.class);
MyDeserializer deserializer = new MyDeserializer();
deserializer.external = new ExternalObject();
doReturn(deserializer).when(hi).deserializerInstance(any(), any(), eq(MyDeserializer.class));
final ObjectMapper mapper = Json.getObjectMapper();
mapper.setHandlerInstantiator(hi);
final MyEntity entity = mapper.readValue(JSON, MyEntity.class);
Assert.assertEquals("MyExternalObject", entity.name);
}
}