java - 如何为独立单元测试手动注册 Jackson2HalModule?

标签 java spring rest spring-hateoas hypermedia

我试过:

@BeforeClass
public static void setUpClass() {
    CurieProvider curieProvider = new DefaultCurieProvider("a", new UriTemplate("a{yey}"));
    RelProvider relProvider = new DefaultRelProvider();
    ObjectMapper halObjectMapper = JsonUtils.mapper; 
    halObjectMapper.registerModule(new Jackson2HalModule());
    halObjectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider));
}

但还是报错:

03:26:25.936 [main] ERROR org.soluvas.json.JsonUtils - Cannot serialize id.co.bippo.product.rs.commerceplug.ProductOrServiceImpl as JSON
com.fasterxml.jackson.databind.JsonMappingException: Class org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListSerializer has no default (no arg) constructor
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1042) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:445) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:599) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:92) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:800) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:676) ~[jackson-databind-2.4.3.jar:2.4.3]
    at org.soluvas.json.JsonUtils.asJson(JsonUtils.java:54) ~[classes/:na]
    at id.co.bippo.product.rs.commerceplug.ProductOrServiceImplTest.productOrService(ProductOrServiceImplTest.java:41) [test-classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_20]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_20]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_20]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_20]
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) [junit-4.11.jar:na]
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.11.jar:na]
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) [junit-4.11.jar:na]
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) [junit-4.11.jar:na]
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) [junit-4.11.jar:na]
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) [junit-4.11.jar:na]
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) [junit-4.11.jar:na]
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) [junit-4.11.jar:na]
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]
Caused by: java.lang.IllegalArgumentException: Class org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListSerializer has no default (no arg) constructor
    at com.fasterxml.jackson.databind.util.ClassUtil.createInstance(ClassUtil.java:370) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializerInstance(DefaultSerializerProvider.java:474) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerFromAnnotation(BasicSerializerFactory.java:461) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._constructWriter(BeanSerializerFactory.java:708) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:557) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.constructBeanSerializer(BeanSerializerFactory.java:344) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanSerializer(BeanSerializerFactory.java:263) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:222) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:152) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1077) ~[jackson-databind-2.4.3.jar:2.4.3]
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1037) ~[jackson-databind-2.4.3.jar:2.4.3]
    ... 31 common frames omitted

最佳答案

如果您需要转换器设置,我猜您正在做比单元测试更多的“集成”测试,因为 Controller 不返回转换后的响应。我可能会建议在您的测试类中添加这样的注释

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = Application.class)

这将允许您进行此注入(inject):

@Autowired
protected WebApplicationContext wac;

然后您可以在您的设置中将其传递给 MockMVC 构建器:

MockMvcBuilders.webAppContextSetup(wac).build()

Application.class 将是用 @ComponentScan 注释的东西,它反过来会获取您的所有配置。您也可以显式传递它们。

如果你真的想显式地生成转换器,这就是我们所拥有的:

public static HttpMessageConverter<Object> HALMessageConverter(){
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new Jackson2HalModule());

    //TODO: need to figure out this curie provider stuff...more in production mode
    DefaultCurieProvider curieProvider = new DefaultCurieProvider("a", new UriTemplate("http://localhost:8080/myapp/rels/{rel}"));
    DefaultRelProvider relProvider = new DefaultRelProvider();

    objectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider));

    MappingJackson2HttpMessageConverter halConverter = new MappingJackson2HttpMessageConverter();
    halConverter.setObjectMapper(objectMapper);
    halConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));

    return halConverter;
}

然后您必须使用 MVC 实例注册此转换器:

var mockMVC = MockMvcBuilders.standaloneSetup(controller)
            .setMessageConverters(HALMessageConverter())
            .build();

看起来您可能缺少媒体类型和注册。

最后一点,这个异常(exception)是完全不同的东西。我已经看到,当您实例化一个使用现有混合但不同的列表序列化程序的 ObjectMapper 时。这是因为资源混合将 HalListLinkSerializer 定义为序列化程序,但依赖于正确的实例化。不确定你为什么会这样……我猜你在某处进行了一些注释配置……

关于java - 如何为独立单元测试手动注册 Jackson2HalModule?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26796687/

相关文章:

java - 如何在创建期间在 apache.jena.queryExecutionFactory 调试 NullPointerException?

spring - @Required 注解如何与 JavaConfig 一起使用?

spring - hibernate JavassistLazyInitializer : problems with validation

rest - 返回也是集合的资源表示的最佳实践

java - Spring MVC - 从 JSP 中的列表访问表单中的对象

java - core 和 core_rt jSTL 标签的区别

java - 使用套接字手动发送 Keep-Alive 数据包

spring - "Request method ' POST ' not supported"放置安全注释后

angularjs - 使用 Laravel 将部分 html 模板加载到 Angular 应用程序中

java - 尝试在 Java 中进行 REST API Cypher 查询时如何解决 neo4j 错误(参数必须是 JSON 映射)