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

Kubernetes client extension native: IntOrString$Serializer has no default (no arg) constructor #3505

Closed
jglick opened this issue Aug 14, 2019 · 2 comments · Fixed by #3504
Closed
Labels
kind/bug Something isn't working
Milestone

Comments

@jglick
Copy link

jglick commented Aug 14, 2019

Describe the bug

I have a Quarkus app which manipulates K8s resources using the standard extension for the Fabric8 client. It works fine in OpenJDK. When I run it in native mode, I get a cryptic error from Jackson.

Vaguely reminiscent of #3077, but distinct, and not due to use of watches.

Expected behavior

Call works as in regular JVM mode.

Actual behavior

I get

io.fabric8.kubernetes.client.KubernetesClientException: Operation: [replace]  for kind: [StatefulSet]  with name: […]  in namespace: […]  failed.
	at io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation.lambda$replace$1(HasMetadataOperation.java:101)
	at io.fabric8.kubernetes.api.model.apps.DoneableStatefulSet.done(DoneableStatefulSet.java:27)
	at io.fabric8.kubernetes.api.model.apps.DoneableStatefulSet.done(DoneableStatefulSet.java:6)
	at io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation.replace(HasMetadataOperation.java:105)
	at io.fabric8.kubernetes.client.dsl.internal.RollableScalableResourceOperation.replace(RollableScalableResourceOperation.java:159)
	at io.fabric8.kubernetes.client.dsl.internal.RollableScalableResourceOperation.replace(RollableScalableResourceOperation.java:42)
	at io.fabric8.kubernetes.client.dsl.base.BaseOperation.createOrReplace(BaseOperation.java:387)
	at io.fabric8.kubernetes.client.dsl.base.BaseOperation.createOrReplace(BaseOperation.java:382)
	at …
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Class io.fabric8.kubernetes.api.model.IntOrString$Serializer has no default (no arg) constructor (through reference chain: io.fabric8.kubernetes.api.model.apps.StatefulSet["spec"]->io.fabric8.kubernetes.api.model.apps.StatefulSetSpec["template"]->io.fabric8.kubernetes.api.model.PodTemplateSpec["spec"]->io.fabric8.kubernetes.api.model.PodSpec["containers"]->java.util.ArrayList[0]->io.fabric8.kubernetes.api.model.Container["livenessProbe"]->io.fabric8.kubernetes.api.model.Probe["httpGet"]->io.fabric8.kubernetes.api.model.HTTPGetAction["port"])
	at com.fasterxml.jackson.databind.SerializerProvider.reportMappingProblem(SerializerProvider.java:1223)
	at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1341)
	at com.fasterxml.jackson.databind.SerializerProvider.findPrimaryPropertySerializer(SerializerProvider.java:668)
	at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddPrimarySerializer(PropertySerializerMap.java:64)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._findAndAddDynamic(BeanPropertyWriter.java:897)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:705)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	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.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	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.ObjectMapper._configAndWriteValue(ObjectMapper.java:3906)
	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3220)
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleReplace(OperationSupport.java:270)
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleReplace(OperationSupport.java:252)
	at io.fabric8.kubernetes.client.dsl.base.BaseOperation.handleReplace(BaseOperation.java:801)
	at io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation.lambda$replace$1(HasMetadataOperation.java:99)
	... 79 more
Caused by: java.lang.IllegalArgumentException: Class io.fabric8.kubernetes.api.model.IntOrString$Serializer has no default (no arg) constructor
	at com.fasterxml.jackson.databind.util.ClassUtil.createInstance(ClassUtil.java:554)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializerInstance(DefaultSerializerProvider.java:135)
	at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerFromAnnotation(BasicSerializerFactory.java:489)
	at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:136)
	at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1388)
	at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1336)
	... 114 more

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

$ javap -classpath ~/.m2/repository/io/fabric8/kubernetes-model/4.3.1/kubernetes-model-4.3.1.jar 'io.fabric8.kubernetes.api.model.IntOrString$Serializer'
Compiled from "IntOrString.java"
public class io.fabric8.kubernetes.api.model.IntOrString$Serializer extends com.fasterxml.jackson.databind.JsonSerializer<io.fabric8.kubernetes.api.model.IntOrString> {
  public io.fabric8.kubernetes.api.model.IntOrString$Serializer();
  public void serialize(io.fabric8.kubernetes.api.model.IntOrString, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) throws java.io.IOException, com.fasterxml.jackson.core.JsonProcessingException;
  public void serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider) throws java.io.IOException;
}

To Reproduce

The problematic code does something like

@Inject KubernetesClient k8sClient;
// …
StatefulSet sts = k8sClient.apps().statefulSets().withName(…).get();
sts.getSpec().setReplicas(1);
k8sClient.apps().statefulSets().createOrReplace(sts);

and am building in -Pnative mode using quay.io/quarkus/centos-quarkus-maven:19.1.1. The resource in question seems OK acc. to kubectl get -o json sts/… | jq '.spec.template.spec.containers[0].livenessProbe':

{
  "failureThreshold": 3,
  "httpGet": {
    "path": "/…",
    "port": 8080,
    "scheme": "HTTP"
  },
  "initialDelaySeconds": 300,
  "periodSeconds": 10,
  "successThreshold": 1,
  "timeoutSeconds": 10
}

(Can try to produce a minimal test case if the problem is not obvious from what is here already.)

Configuration

No relevant configuration.

Environment (please complete the following information):

Microk8s on Ubuntu. GraalVM as per above image. Quarkus 0.20.0.

@jglick jglick added the kind/bug Something isn't working label Aug 14, 2019
@jglick
Copy link
Author

jglick commented Aug 14, 2019

I suspect

final String[] deserializerClasses = combinedIndexBuildItem.getIndex()
.getAllKnownSubclasses(DotName.createSimple("com.fasterxml.jackson.databind.JsonDeserializer"))
.stream()
.map(c -> c.name().toString())
.filter(s -> s.startsWith("io.fabric8.kubernetes"))
.toArray(String[]::new);
reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, deserializerClasses));
needs to be extended to process JsonSerializers so that resources can be modified and not merely retrieved.

@jglick
Copy link
Author

jglick commented Aug 14, 2019

Confirmed fixed in 0.21.0. Thanks for the amazingly fast resolution!

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.

2 participants