如何手动注册Jackson2HalModule进行独立单元测试?

时间:2014-11-07 08:01:30

标签: 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

2 个答案:

答案 0 :(得分:3)

我猜你做得更多"整合"测试比单元测试,如果你需要转换器设置,因为控制器不会返回转换后的响应。我可能会建议将这样的注释添加到您的测试类

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

这将允许您进行此注射:

@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();

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

最后请注意,该例外情况完全不同。我已经看到,当你实例化一个使用现有mixin的ObjectMapper时,却会使用不同的列表序列化器。这是因为资源mixin将HalListLinkSerializer定义为序列化程序,但依赖于正确的实例化。不知道你为什么会这样......猜测你有一些注释配置在某个地方......

答案 1 :(得分:1)

这对我有用:

import java.io.IOException;

import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.soluvas.json.JsonUtils;
import org.soluvas.json.LowerEnumSerializer;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.UriTemplate;
import org.springframework.hateoas.core.DefaultRelProvider;
import org.springframework.hateoas.hal.CurieProvider;
import org.springframework.hateoas.hal.DefaultCurieProvider;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpOutputMessage;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;

public class ProductHalJsonTest {

    private static final Logger log = LoggerFactory
            .getLogger(ProductHalJsonTest.class);
    private static MappingJackson2HttpMessageConverter halConverter;

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

        halConverter = new MappingJackson2HttpMessageConverter();
        halConverter.setObjectMapper(halObjectMapper);
        halConverter.setSupportedMediaTypes(ImmutableList.of(MediaTypes.HAL_JSON));
    }

    @Test
    public void product() throws HttpMessageNotWritableException, IOException {
        Brand brand = new Brand().withName("Tuneeca");
        Product product = new Product()
            .withName("T-2081239")
            .withBrand(brand)
            .addOffer(new Offer().withAvailability(ItemAvailability.IN_STOCK));
//      String json = JsonUtils.asJson(product);
        final MockHttpOutputMessage msg = new MockHttpOutputMessage();
        halConverter.write(product, MediaTypes.HAL_JSON, msg);
        String json = msg.getBodyAsString();
        log.info("{}", json);
    }

}

但是,当我只想获得HAL + JSON输出时,我无法理解为什么必须创建HttpMessageConverter ...

相关问题