Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

com.fasterxml.jackson.databind.JsonMappingException: Class CustomSerializer has no default (no arg) constructor #12345

Closed
banifou opened this issue Sep 25, 2020 · 12 comments · Fixed by #12387
Assignees
Labels
kind/bug Something isn't working
Milestone

Comments

@banifou
Copy link

banifou commented Sep 25, 2020

Describe the bug
I'm using a custom serialiser extending com.fasterxml.jackson.databind.ser.std.StdSerializer to serve a REST Api. It works fine in OpenJDK 11. When I run it in native mode, I get a no default (no arg) constructor error.

Expected behavior
Get my java object serialized serving/producing an application/json endpoint.

Actual behavior
When i try to get the serialized entity object retrieved from Postgresql with the native image (in GET) it does throw error

com.fasterxml.jackson.databind.JsonMappingException: Class com.example.utils.BookSerializer has no default (no arg) constructor (through reference chain: java.util.ArrayList[1]->com.example.model.entities.OfferBasket["bookBaskets"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.model.entities.BookBasket["bookList"]->org.hibernate.collection.internal.PersistentSet[0])
	at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:381)
	at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:216)
	at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:610)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:520)
	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:259)
	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:160)
	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
	at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:163)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:245)
	at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:131)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:37)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:94)
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at java.lang.Thread.run(Thread.java:834)
	at org.jboss.threads.JBossThread.run(JBossThread.java:479)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:517)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Class com.example.utils.BookSerializer has no default (no arg) constructor (through reference chain: java.util.ArrayList[1]->com.example.model.entities.OfferBasket["bookBaskets"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.model.entities.BookBasket["bookList"]->org.hibernate.collection.internal.PersistentSet[0])
	at com.fasterxml.jackson.databind.SerializerProvider.reportMappingProblem(SerializerProvider.java:1309)
	at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1427)
	at com.fasterxml.jackson.databind.SerializerProvider.findContentValueSerializer(SerializerProvider.java:754)
	at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddSecondarySerializer(PropertySerializerMap.java:90)
	at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase._findAndAddDynamic(AsArraySerializerBase.java:304)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:140)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:667)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:171)
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1516)
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1006)
	at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.writeTo(ResteasyJackson2Provider.java:329)
	at org.jboss.resteasy.core.messagebody.AsyncBufferedMessageBodyWriter.asyncWriteTo(AsyncBufferedMessageBodyWriter.java:24)
	at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:87)
	at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.asyncProceed(AbstractWriterInterceptorContext.java:203)
	at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.getStarted(AbstractWriterInterceptorContext.java:166)
	at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$getStarted$0(ServerWriterInterceptorContext.java:73)
	at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.aroundWriteTo(ServerWriterInterceptorContext.java:93)
	at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.getStarted(ServerWriterInterceptorContext.java:73)
	at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$3(ServerResponseWriter.java:163)
	at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:404)
	at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:252)
	at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:101)
	at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:74)
	at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:590)
	... 20 more

Note that the class actually does have a no-arg constructor:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.example.model.entities.Book;
import java.io.IOException;

public class BookSerializer extends StdSerializer<Book> {

    public BookSerializer(Class<Book> t) {
        super(t);
    }
    
    public BookSerializer() {
       super(Book.class);
   }

    @Override
    public void serialize(Book book, JsonGenerator jsonGenerator, SerializerProvider sp) throws IOException {
        .
        .
        .
    }
}

Environment (please complete the following information):

Ubuntu 20.04.1 LTS. Graalvm-ce-java11-linux-amd64-20.2.0. Quarkus 1.8.1

@banifou banifou added the kind/bug Something isn't working label Sep 25, 2020
@geoand
Copy link
Contributor

geoand commented Sep 28, 2020

Hi,

How do you register your serializer with Jackson?

@banifou
Copy link
Author

banifou commented Sep 28, 2020

Hi, in the entity bean like this @JsonSerialize(using = BookSerializer.class)

@gsmet
Copy link
Member

gsmet commented Sep 28, 2020

We have some code to deal with that but apparently we're missing something.

Could you prepare a small reproducer so that we can have a look?

Thanks!

@banifou
Copy link
Author

banifou commented Sep 28, 2020

Here is my reproducer project, can checkout it? https://github.com/banifou/jdbc-jackson-serialiser

@zipper01
Copy link

zipper01 commented Jan 9, 2023

Hi, I still got this problem when running the GraalVM generated native image:

Exception in thread "Thread-1" java.lang.IllegalArgumentException: Class com.mysys.myclient.sub.Subscriber$Deserializer has no default (no arg) constructor
 at [Source: UNKNOWN; byte offset: #UNKNOWN]
        at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4449)
        at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4380)
        at com.mysys.myclient.ClientMgr.onCtrlLoginSucceeded(ClientMgr.java:570)
        at com.mysys.myclient.ClientMgr.lambda$ctrlLogin$4(ClientMgr.java:400)
        at com.mysys.myclient.net.RelayClientEndpoint.handleSimpleCtrlRsp(RelayClientEndpoint.java:227)
        at com.mysys.myclient.net.RelayClientEndpoint.syncRunCtrlOperation(RelayClientEndpoint.java:206)
        at com.mysys.myclient.ClientMgr.ctrlLogin(ClientMgr.java:395)
        at com.mysys.myclient.ClientMgr.login(ClientMgr.java:241)
        at com.mysys.myclient.ui.UIMgr.lambda$new$2(UIMgr.java:20)
        at com.mysys.myclient.ui.Tui.login(Tui.java:74)
        at com.mysys.myclient.ui.Tui.access$100(Tui.java:37)
        at com.mysys.myclient.ui.Tui$1.run(Tui.java:63)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:775)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:203)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Class com.mysys.myclient.sub.Subscriber$Deserializer has no default (no arg) constructor
 at [Source: UNKNOWN; byte offset: #UNKNOWN]
        at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1909)
        at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:268)
        at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
        at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
        at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:648)
        at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4861)
        at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4442)
        ... 13 more
^C
[root@ecs-45ee downloads]# cat /etc/centos-release
CentOS Linux release 8.2.2004 (Core)

Code:

package com.mysys.myclient.sub;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import static com.mysys.myclient.CfgMgr.jsonObjectMapper;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

@JsonDeserialize(using = Subscriber.Deserializer.class)

public class Subscriber {

    public int statusId;
    public String name;
    public String password;
    public final ConcurrentHashMap<Integer, Account> accounts;

    public Subscriber(int statusId, String name, String password, ConcurrentHashMap<Integer, Account> accounts) {
        this.statusId = statusId;
        this.name = name;
        this.password = password;
        this.accounts = accounts;
    }

    public static class Deserializer extends StdDeserializer<Subscriber> {

        public Deserializer() {
            super(Subscriber.class);
        }

        public Deserializer(Class<?> vc) {
            super(vc);
        }

        @Override
        public Subscriber deserialize(JsonParser jp, DeserializationContext ctx)
                throws IOException, JsonProcessingException {
            JsonNode node = jp.getCodec().readTree(jp);
            if (node.isEmpty()) {
                return null;
            }
            JsonNode v = node.get("statusId");
            int id = v == null ? -1 : v.asInt(-1);
            v = node.get("name");
            String name = v == null ? null : v.asText(null);
            v = node.get("password");
            String password = v == null ? null : v.asText(null);
            ConcurrentHashMap<Integer, Account> accounts = null;
            v = node.get("accounts");
            if (v != null) {
                accounts = jsonObjectMapper.convertValue(v,
                        new TypeReference<ConcurrentHashMap<Integer, Account>>() {
                });
            }
            return new Subscriber(id, name, password, accounts);
        }
    }

}

Environment info:

Version info: 'GraalVM 22.3.0 Java 17 CE'
Java version info: '17.0.5+8-jvmci-22.3-b08'
C compiler: gcc (redhat, x86_64, 8.5.0)
Garbage collector: Serial GC

@geoand
Copy link
Contributor

geoand commented Jan 9, 2023

@zipper01 any chance you can attach a sample application we can try?

zipper01 added a commit to zipper01/reprocedure-for-quarkusio-quarkus-issue-12345 that referenced this issue Jan 9, 2023
@geoand
Copy link
Contributor

geoand commented Jan 9, 2023

What you added does not appear to be a Quarkus project

@zipper01
Copy link

zipper01 commented Jan 9, 2023

@geoand sorry it's not a Quarkus project (at the moment). I am trying to use GraalVM to generate the native image. When googling for the exception I came across this ticket it looks highly matches my case - same exception from the same library.

@geoand
Copy link
Contributor

geoand commented Jan 9, 2023

Quarkus does extra work to make things like that happen - if you don't use Quarkus, you need to configure GraalVM yourself.

@zipper01
Copy link

zipper01 commented Jan 9, 2023

Ok, thank you.

@geoand
Copy link
Contributor

geoand commented Jan 9, 2023

🙏🏼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants