Reputation: 1369
I am trying to de-serialize a post request in my web service but I end up getting an HTTP 500 saying javax.json.bind.JsonbException: Error deserialize JSON value into type: class [C
. I am using Jackson to handle the JSON stuff.
This is the JSON String I'm sending from Postman:
{"firstName":"FirstName","middleName":"middleName","lastName":"LastName","name":"SomeName","password":"$0meR@nd0m","creationTimeStamp":1533950475466}
This is my 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;
}
}
This is my request handler 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();
}
}
These are my Maven dependencies for Jackson:
<!-- 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>
And this is the stack trace:
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$1.run(ServerRuntime.java:277)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272)
at org.glassfish.jersey.internal.Errors$1.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$9.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.access$100(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)
]]
I have added the jars for the Jackson dependencies to the lib directory of the app server as well. I am using GlassFish 5.0 and Jersey 2.26. What is it that I am doing wrong? How to resolve this?
Upvotes: 1
Views: 11450
Reputation: 719006
The clue is in the error message:
Error deserialize JSON value into type: class [C
The class [C
is the class that corresponds to char[]
.
Looking at your code, you have declared password
as:
private char[] password;
Change it to
private String password;
What is going on here is that Jackson doesn't know how to deserialize a JSON string as a char[]
.
There is a school of thought that says that you should not use Java strings to hold passwords ... because it supposedly allows a hacker to extract them from (say) non-GC'ed strings in a JVM core dump. But the reality is that if a hacker can extract passwords that way, they can most likely do other things to get the password. Besides, the very same passwords will most likely be in String
objects created internally by Glassfish framework classes and/or the JSON deserializer. Using a char[]
in this case is most likely futile. Even if you address those concerns, using char[]
to represent passwords will only be more secure if you overwrite the content of the char[]
as soon as possible. If you let the char[]
become unreachable while it still holds a password, you are back to the String
problem.
Upvotes: 5