Skip to content

Commit

Permalink
decoupling unmatched handling from kubernetesdeserializer
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Apr 4, 2022
1 parent 6266644 commit 43bbd62
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.fabric8.kubernetes.api.model.GenericKubernetesResource;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.utils.serialization.UnmatchedFieldTypeModule;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand All @@ -39,16 +42,48 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import io.fabric8.kubernetes.client.utils.serialization.UnmatchedFieldTypeModule;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

public class Serialization {
private Serialization() { }

private static final String TEMPLATE_CLASS_NAME = "io.fabric8.openshift.api.model.Template";

public static final UnmatchedFieldTypeModule UNMATCHED_FIELD_TYPE_MODULE = new UnmatchedFieldTypeModule();

private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
private interface ExceptionalSupplier<T> {
public T get() throws IOException;
}

private static final ObjectMapper JSON_MAPPER = new ObjectMapper() {
@Override
protected Object _readValue(com.fasterxml.jackson.databind.DeserializationConfig cfg,
com.fasterxml.jackson.core.JsonParser p, com.fasterxml.jackson.databind.JavaType valueType) throws IOException {
return templateAware(() -> super._readValue(cfg, p, valueType), valueType);
}

@Override
protected Object _readMapAndClose(com.fasterxml.jackson.core.JsonParser p0,
com.fasterxml.jackson.databind.JavaType valueType) throws IOException {
return templateAware(() -> super._readMapAndClose(p0, valueType), valueType);
}

protected Object templateAware(ExceptionalSupplier<Object> function, com.fasterxml.jackson.databind.JavaType valueType)
throws IOException {
boolean inTemplate = false;
if (!UnmatchedFieldTypeModule.isInTemplate()
&& TEMPLATE_CLASS_NAME.equals(valueType.getRawClass().getName())) {
UnmatchedFieldTypeModule.setInTemplate();
inTemplate = true;
}
try {
return function.get();
} finally {
if (inTemplate) {
UnmatchedFieldTypeModule.removeInTemplate();
}
}
}

};
static {
JSON_MAPPER.registerModules(new JavaTimeModule(), UNMATCHED_FIELD_TYPE_MODULE);
}
Expand Down Expand Up @@ -407,14 +442,8 @@ public static <T> T clone(T resource) {
// if full serialization seems too expensive, there is also
//return (T) JSON_MAPPER.convertValue(resource, resource.getClass());
try {
return JSON_MAPPER.readValue(
JSON_MAPPER.writeValueAsString(resource), new TypeReference<T>() {
@Override
public Type getType() {
// Force KubernetesResource so that the KubernetesDeserializer takes over any resource configured deserializer
return resource instanceof GenericKubernetesResource ? resource.getClass() : KubernetesResource.class;
}
});
return (T) JSON_MAPPER.readValue(
JSON_MAPPER.writeValueAsString(resource), resource.getClass());
} catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import io.fabric8.kubernetes.internal.KubernetesDeserializer;

import java.io.IOException;
import java.lang.annotation.Annotation;
Expand All @@ -41,37 +40,37 @@ public class SettableBeanPropertyDelegate extends SettableBeanProperty {

private final SettableBeanProperty delegate;
private final SettableAnyProperty anySetter;
private final transient Supplier<Boolean> restrictToTemplates;
private final transient Supplier<Boolean> useAnySetter;

SettableBeanPropertyDelegate(SettableBeanProperty delegate, SettableAnyProperty anySetter, Supplier<Boolean> restrictToTemplates) {
SettableBeanPropertyDelegate(SettableBeanProperty delegate, SettableAnyProperty anySetter, Supplier<Boolean> useAnySetter) {
super(delegate);
this.delegate = delegate;
this.anySetter = anySetter;
this.restrictToTemplates = restrictToTemplates;
this.useAnySetter = useAnySetter;
}

/**
* {@inheritDoc}
*/
@Override
public SettableBeanProperty withValueDeserializer(JsonDeserializer<?> deser) {
return new SettableBeanPropertyDelegate(delegate.withValueDeserializer(deser), anySetter, restrictToTemplates);
return new SettableBeanPropertyDelegate(delegate.withValueDeserializer(deser), anySetter, useAnySetter);
}

/**
* {@inheritDoc}
*/
@Override
public SettableBeanProperty withName(PropertyName newName) {
return new SettableBeanPropertyDelegate(delegate.withName(newName), anySetter, restrictToTemplates);
return new SettableBeanPropertyDelegate(delegate.withName(newName), anySetter, useAnySetter);
}

/**
* {@inheritDoc}
*/
@Override
public SettableBeanProperty withNullProvider(NullValueProvider nva) {
return new SettableBeanPropertyDelegate(delegate.withNullProvider(nva), anySetter, restrictToTemplates);
return new SettableBeanPropertyDelegate(delegate.withNullProvider(nva), anySetter, useAnySetter);
}

/**
Expand Down Expand Up @@ -171,9 +170,6 @@ private boolean shouldUseAnySetter() {
if (anySetter == null) {
return false;
}
if (Boolean.TRUE.equals(restrictToTemplates.get()) ) {
return KubernetesDeserializer.isInTemplate();
}
return true;
return Boolean.TRUE.equals(useAnySetter.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class UnmatchedFieldTypeModule extends SimpleModule {
private boolean logWarnings;
private boolean restrictToTemplates;

private static final ThreadLocal<Boolean> IN_TEMPLATE = ThreadLocal.withInitial(() -> false);

public UnmatchedFieldTypeModule() {
this(true, true);
}
Expand All @@ -52,7 +54,7 @@ public UnmatchedFieldTypeModule(boolean logWarnings, boolean restrictToTemplates
@Override
public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
builder.getProperties().forEachRemaining(p ->
builder.addOrReplaceProperty(new SettableBeanPropertyDelegate(p, builder.getAnySetter(), UnmatchedFieldTypeModule.this::isRestrictToTemplates) {
builder.addOrReplaceProperty(new SettableBeanPropertyDelegate(p, builder.getAnySetter(), UnmatchedFieldTypeModule.this::useAnySetter) {
}, true));
return builder;
}
Expand Down Expand Up @@ -85,6 +87,10 @@ boolean isRestrictToTemplates() {
return restrictToTemplates;
}

boolean useAnySetter() {
return !restrictToTemplates || isInTemplate();
}

/**
* Sets if the DeserializerModifier should only be applied to Templates or object trees contained in Templates.
*
Expand All @@ -93,4 +99,17 @@ boolean isRestrictToTemplates() {
public void setRestrictToTemplates(boolean restrictToTemplates) {
this.restrictToTemplates = restrictToTemplates;
}

public static boolean isInTemplate() {
return Boolean.TRUE.equals(IN_TEMPLATE.get());
}

public static void setInTemplate() {
IN_TEMPLATE.set(true);
}

public static void removeInTemplate() {
IN_TEMPLATE.remove();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,11 @@ public boolean equals(Object obj) {

}

private static final String TEMPLATE_CLASS_NAME = "io.fabric8.openshift.api.model.Template";
private static final String KIND = "kind";
private static final String API_VERSION = "apiVersion";

private static final Mapping mapping = new Mapping();

private static final ThreadLocal<Boolean> IN_TEMPLATE = ThreadLocal.withInitial(() -> false);

public static boolean isInTemplate() {
return IN_TEMPLATE.get();
}

@Override
public KubernetesResource deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonNode node = jp.readValueAsTree();
Expand Down Expand Up @@ -121,18 +114,7 @@ private static KubernetesResource fromObjectNode(JsonParser jp, JsonNode node) t
if (resourceType == null) {
return jp.getCodec().treeToValue(node, GenericKubernetesResource.class);
} else if (KubernetesResource.class.isAssignableFrom(resourceType)){
boolean inTemplate = false;
if (TEMPLATE_CLASS_NAME.equals(resourceType.getName())) {
inTemplate = true;
IN_TEMPLATE.set(true);
}
try {
return jp.getCodec().treeToValue(node, resourceType);
} finally {
if (inTemplate) {
IN_TEMPLATE.remove();
}
}
return jp.getCodec().treeToValue(node, resourceType);
}
}
return null;
Expand Down

0 comments on commit 43bbd62

Please sign in to comment.