首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Spring引导页反序列化- PageImpl无构造函数

Spring引导页反序列化- PageImpl无构造函数
EN

Stack Overflow用户
提问于 2018-09-25 04:01:37
回答 9查看 30.4K关注 0票数 22

尝试从spring引导接收页面的单元测试。如果与javascript一起使用,页面可以很容易地反序列化,但如果使用java,则会失败。已经为spring添加了一个默认构造函数(在另一个堆栈溢出帖子中是一个可接受的答案),但是它在这里不起作用。

单元测试

代码语言:javascript
运行
复制
@Test
public void test_read_pagination_happy(@Autowired ObservationSet set) {

    repository.save(set);

    final HttpEntity<String> authHeaders = authentication.convert("", authSuccess);
    final ParameterizedTypeReference<RestResponsePage<ObservationSet>> responseType = new ParameterizedTypeReference<RestResponsePage<ObservationSet>>() {
    };
    // final ResponseEntity<String> result = restTemplate.exchange(base + "/api/v1/observationset", HttpMethod.GET, authHeaders, String.class);
    final ResponseEntity<RestResponsePage<ObservationSet>> result = restTemplate.exchange(base + "/api/v1/observationset", HttpMethod.GET, authHeaders,
                    responseType);
    System.out.println(result.getBody());
    assertSame(HttpStatus.OK, result.getStatusCode(), "incorrect status code");
}

RestRespongePage类

代码语言:javascript
运行
复制
class RestResponsePage<T> extends PageImpl<T> {

    private static final long serialVersionUID = 3248189030448292002L;

    public RestResponsePage(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public RestResponsePage(List<T> content) {
        super(content);
    }

    public RestResponsePage() {
        super(new ArrayList<T>());
    }

}
代码语言:javascript
运行
复制
Code is available on github --> [https://github.com/OpenPCM/openpcm-server/blob/integration-test/src/test/java/org/openpcm/controller/ObservationSetControllerIntTest.java](https://github.com/OpenPCM/openpcm-server/blob/integration-test/src/test/java/org/openpcm/controller/ObservationSetControllerIntTest.java)

The deserialization throws this error:

```javascript

org.springframework.http.converter.HttpMessageConversionException:类型定义错误:简单类型,类org.springframework.data.domain.Pageable;嵌套的异常是com.fasterxml.jackson.databind.exc.InvalidDefinitionException:不能构造org.springframework.data.domain.Pageable的实例(没有创建者,像默认构造一样,存在):抽象类型要么需要映射到具体类型,要么需要自定义反序列化器,或者包含额外的类型信息。

Source: (PushbackInputStream); line: 1, column: 294

代码语言:javascript
运行
复制
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:240)
代码语言:javascript
运行
复制
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225)
代码语言:javascript
运行
复制
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:100)
代码语言:javascript
运行
复制
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:959)
代码语言:javascript
运行
复制
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:942)
代码语言:javascript
运行
复制
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:689)
代码语言:javascript
运行
复制
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:644)
代码语言:javascript
运行
复制
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:593)
代码语言:javascript
运行
复制
at org.springframework.boot.test.web.client.TestRestTemplate.exchange(TestRestTemplate.java:843)
代码语言:javascript
运行
复制
at org.openpcm.controller.ObservationSetControllerIntTest.test_read_pagination_happy(ObservationSetControllerIntTest.java:85)
代码语言:javascript
运行
复制
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
代码语言:javascript
运行
复制
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
代码语言:javascript
运行
复制
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
代码语言:javascript
运行
复制
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
代码语言:javascript
运行
复制
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436)
代码语言:javascript
运行
复制
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
代码语言:javascript
运行
复制
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
代码语言:javascript
运行
复制
at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
代码语言:javascript
运行
复制
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
代码语言:javascript
运行
复制
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
代码语言:javascript
运行
复制
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
代码语言:javascript
运行
复制
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
代码语言:javascript
运行
复制
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
代码语言:javascript
运行
复制
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
代码语言:javascript
运行
复制
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
代码语言:javascript
运行
复制
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:430)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
代码语言:javascript
运行
复制
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
代码语言:javascript
运行
复制
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
代码语言:javascript
运行
复制
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
代码语言:javascript
运行
复制
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
代码语言:javascript
运行
复制
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
代码语言:javascript
运行
复制
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:430)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
代码语言:javascript
运行
复制
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
代码语言:javascript
运行
复制
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
代码语言:javascript
运行
复制
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
代码语言:javascript
运行
复制
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
代码语言:javascript
运行
复制
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
代码语言:javascript
运行
复制
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
代码语言:javascript
运行
复制
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
代码语言:javascript
运行
复制
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
代码语言:javascript
运行
复制
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
代码语言:javascript
运行
复制
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

由: com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造org.springframework.data.domain.Pageable实例(没有创建者,与默认构造一样,存在):抽象类型需要映射到具体类型、具有自定义反序列化程序或包含其他类型信息。

Source: (PushbackInputStream); line: 1, column: 294

代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:265)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
代码语言:javascript
运行
复制
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)
代码语言:javascript
运行
复制
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
代码语言:javascript
运行
复制
... 65 more
代码语言:javascript
运行
复制
EN

回答 9

Stack Overflow用户

发布于 2019-02-17 05:22:03

有一种更简单的方法--为Page接口创建和注册自定义反序列化器。因此,使用将是简单明了的:

代码语言:javascript
运行
复制
//Catalog is the paged entity
Page<Catalog> page = objectMapper.readValue(content, new TypeReference<Page<Catalog>>() {});

ObjectMapper配置:

代码语言:javascript
运行
复制
ObjectMapper objectMapper= new ObjectMapper();
objectMapper.registerModule(new PageModule());

PageModule:

代码语言:javascript
运行
复制
public class PageModule extends SimpleModule {
    private static final long serialVersionUID = 1L;

    public PageModule() {
        addDeserializer(Page.class, new PageDeserializer());
    }
}

PageDeserializer:

代码语言:javascript
运行
复制
public class PageDeserializer extends JsonDeserializer<Page<?>> implements ContextualDeserializer {
    private static final String CONTENT = "content";
    private static final String NUMBER = "number";
    private static final String SIZE = "size";
    private static final String TOTAL_ELEMENTS = "totalElements";
    private JavaType valueType;

    @Override
    public Page<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        final CollectionType valuesListType = ctxt.getTypeFactory().constructCollectionType(List.class, valueType);

        List<?> list = new ArrayList<>();
        int pageNumber = 0;
        int pageSize = 0;
        long total = 0;
        if (p.isExpectedStartObjectToken()) {
            p.nextToken();
            if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
                String propName = p.getCurrentName();
                do {
                    p.nextToken();
                    switch (propName) {
                        case CONTENT:
                            list = ctxt.readValue(p, valuesListType);
                            break;
                        case NUMBER:
                            pageNumber = ctxt.readValue(p, Integer.class);
                            break;
                        case SIZE:
                            pageSize = ctxt.readValue(p, Integer.class);
                            break;
                        case TOTAL_ELEMENTS:
                            total = ctxt.readValue(p, Long.class);
                            break;
                        default:
                            p.skipChildren();
                            break;
                    }
                } while (((propName = p.nextFieldName())) != null);
            } else {
                ctxt.handleUnexpectedToken(handledType(), p);
            }
        } else {
            ctxt.handleUnexpectedToken(handledType(), p);
        }

        //Note that Sort field of Page is ignored here.
        //Feel free to add more switch cases above to deserialize it as well.  
        return new PageImpl<>(list, PageRequest.of(pageNumber, pageSize), total);
    }

    /**
     * This is the main point here.
     * The PageDeserializer is created for each specific deserialization with concrete generic parameter type of Page.
     */
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        //This is the Page actually
        final JavaType wrapperType = ctxt.getContextualType();
        final PageDeserializer deserializer = new PageDeserializer();
        //This is the parameter of Page
        deserializer.valueType = wrapperType.containedType(0);
        return deserializer;
    }
}
票数 11
EN

Stack Overflow用户

发布于 2020-10-06 23:11:55

这起作用了,(org.springframework.cloud:spring-cloud-openfeign-core:2.2.5.RELEASE):

代码语言:javascript
运行
复制
@Configuration
public class FeignConfigurationFactory {

    @Bean
    public Module pageJacksonModule() {
        return new PageJacksonModule();
    }

    @Bean
    public Module sortJacksonModule() {
        return new SortJacksonModule();
    }
}
票数 11
EN

Stack Overflow用户

发布于 2019-01-29 14:47:22

不得不做一个小小的改变来忽略未知属性的空:

代码语言:javascript
运行
复制
package ...helper;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.util.ArrayList;
import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class RestResponsePage<T> extends PageImpl<T> {
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public RestResponsePage(@JsonProperty("content") List<T> content,
                            @JsonProperty("number") int number,
                            @JsonProperty("size") int size,
                            @JsonProperty("totalElements") Long totalElements,
                            @JsonProperty("pageable") JsonNode pageable,
                            @JsonProperty("last") boolean last,
                            @JsonProperty("totalPages") int totalPages,
                            @JsonProperty("sort") JsonNode sort,
                            @JsonProperty("first") boolean first,
                            @JsonProperty("numberOfElements") int numberOfElements) {

        super(content, PageRequest.of(number, size), totalElements);
    }

    public RestResponsePage(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public RestResponsePage(List<T> content) {
        super(content);
    }

    public RestResponsePage() {
        super(new ArrayList<>());
    }
}
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52490399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档