无法将 JSON 值反序列化为类型

Failed to de-serialize JSON value into type

我试图在我的网络服务中反序列化一个 post 请求,但我最终得到一个 HTTP 500 说 javax.json.bind.JsonbException: Error deserialize JSON value into type: class [C。我正在使用 Jackson 来处理 JSON 的东西。

这是我从 Postman 发送的 JSON 字符串:

{"firstName":"FirstName","middleName":"middleName","lastName":"LastName","name":"SomeName","password":"[=11=]meR@nd0m","creationTimeStamp":1533950475466}  

这是我的 POJO:

@XmlRootElement
public class UserFormInterceptor   {
    @Pattern(regexp = "^[\S][\p{L} .'-]+$") @Size(min = 2, max = 64) @NotEmpty @NotNull
    private String firstName;
    @Pattern(regexp = "^[\S][\p{L} .'-]+$") @Size(min = 2, max = 64)
    private String middleName;
    @Pattern(regexp = "^[\S][\p{L} .'-]+$") @Size(min = 2, max = 64) @NotEmpty @NotNull
    private String lastName;
    @Pattern(regexp = "^[a-zA-z][\w]*$") @Size(min = 8, max = 64) @NotEmpty @NotNull
    private String name;
    @Pattern(regexp = "(?=.*?[A-Z]+)(?=.*?[0-9]+)(?=.*?[\p{Punct}]+).*") @Size(min = 8, max = 64) @NotEmpty @NotNull
    private char[] password;
    @Positive @NotEmpty @NotNull
    private long creationTimeStamp;

    public UserFormInterceptor() {}

    public UserFormInterceptor(@NotNull String name, @NotNull String password, @Positive long creationTimeStamp, @NotNull String firstName, String middleName, @NotNull String lastName) {
        this.name = name;
        this.password = password.toCharArray();
        this.creationTimeStamp = creationTimeStamp;
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
    }


    @NotNull
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(@NotNull String firstName) {
        this.firstName = firstName;
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    @NotNull
    public String getLastName() {
        return lastName;
    }

    public void setLastName(@NotNull String lastName) {
        this.lastName = lastName;
    }

    @NotNull
    public String getName() {
        return name;
    }

    public void setName(@NotNull String name) {
        this.name = name;
    }

    @NotNull
    public char[] getPassword() {
        return password;
    }

    public void setPassword(@NotNull String password) {
        this.password = password.toCharArray();
    }

    public long getCreationTimeStamp() {
        return creationTimeStamp;
    }

    public void setCreationTimeStamp(long creationTimeStamp) {
        this.creationTimeStamp = creationTimeStamp;
    }

    public Map<String, Object> buildMap() {
        Map<String,Object> returnMap = new HashMap<>();
        returnMap.put("name",this.getName());
        returnMap.put("firstName",this.firstName);
        returnMap.put("middleName",this.middleName==null ? "" : this.middleName);
        returnMap.put("lastName",this.lastName);
        returnMap.put("creationTimeStamp",Long.toString(this.getCreationTimeStamp()));
        return returnMap;
    }
}  

这是我的请求处理程序class:

@Path("/users")
public class UserController {
    private static final UserDAO userDao = new UserDAO();

    @POST
    @Path(value = "/signup")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(value = MediaType.APPLICATION_JSON)
    public Response signUpUser(@Valid @NotNull UserFormInterceptor userSignUpForm) {
        UserCreatorModel userCreatorModel = (UserCreatorModel) new UserCreatorModel(userSignUpForm)
                .setUniqueId();
        String response = userDao.addCustomer(userCreatorModel);
        return Response.ok(response).build();
    }
}  

这些是我对 Jackson 的 Maven 依赖项:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider -->
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.9.6</version>
        </dependency>  

这是堆栈跟踪:

StandardWrapperValve[Controller Servlet]: Servlet.service() for servlet Controller Servlet threw exception
javax.json.bind.JsonbException: Error deserialize JSON value into type: class [C.
    at org.eclipse.yasson.internal.serializer.DeserializerBuilder.build(DeserializerBuilder.java:113)
    at org.eclipse.yasson.internal.serializer.ObjectDeserializer.deserializeNext(ObjectDeserializer.java:161)
    at org.eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserializeInternal(AbstractContainerDeserializer.java:84)
    at org.eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserialize(AbstractContainerDeserializer.java:60)
    at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:57)
    at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:50)
    at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:45)
    at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:85)
    at org.glassfish.jersey.jsonb.internal.JsonBindingProvider.readFrom(JsonBindingProvider.java:99)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:257)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:236)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:73)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1091)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
    at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:271)
    at org.glassfish.jersey.server.internal.inject.EntityParamValueParamProvider$EntityValueSupplier.apply(EntityParamValueParamProvider.java:97)
    at org.glassfish.jersey.server.internal.inject.EntityParamValueParamProvider$EntityValueSupplier.apply(EntityParamValueParamProvider.java:80)
    at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.apply(ParamValueFactoryWithSource.java:74)
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:92)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:133)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:200)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
    at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:277)
    at org.glassfish.jersey.internal.Errors.call(Errors.java:272)
    at org.glassfish.jersey.internal.Errors.call(Errors.java:268)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:268)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1580)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:258)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:652)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:591)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:463)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:168)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:242)
    at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access0(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
    at java.lang.Thread.run(Thread.java:748)
]]  

我也已将 Jackson 依赖项的 jar 添加到应用服务器的 lib 目录中。 我正在使用 GlassFish 5.0 和 Jersey 2.26。 我做错了什么?如何解决?

线索在错误信息中:

Error deserialize JSON value into type: class [C

class[C就是char[]对应的class。

查看您的代码,您已将 password 声明为:

    private char[] password;

改为

    private String password;

这里发生的事情是 Jackson 不知道如何将 JSON 字符串反序列化为 char[]


有一种观点认为你不应该使用 Java 字符串来保存密码......因为它可能允许黑客从(比如说)非JVM 核心转储中的 GC 字符串。但现实情况是,如果黑客可以通过这种方式提取密码,他们很可能会做其他事情来获取密码。此外,完全相同的密码很可能位于 Glassfish 框架 classes and/or JSON 反序列化器内部创建的 String 对象中。在这种情况下使用 char[] 很可能是徒劳的。即使您解决了这些问题,只有尽快覆盖 char[] 的内容,使用 char[] 来表示密码才会更加安全。如果你让 char[] 在它仍然持有密码的情况下变得无法访问,你又回到了 String 问题。