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

decoupling unmatched handling from kubernetesdeserializer #4034

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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,53 @@
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();
}
}
}

@Override
protected void _checkInvalidCopy(java.lang.Class<?> exp) {

}

};
static {
JSON_MAPPER.registerModules(new JavaTimeModule(), UNMATCHED_FIELD_TYPE_MODULE);
}
Expand Down Expand Up @@ -407,14 +447,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 @@ -46,7 +46,7 @@ class SettableBeanPropertyDelegateTest {
void setUp() {
delegateMock = mock(SettableBeanProperty.class, RETURNS_DEEP_STUBS);
anySetterMock = mock(SettableAnyProperty.class);
settableBeanPropertyDelegate = new SettableBeanPropertyDelegate(delegateMock, anySetterMock, () -> false);
settableBeanPropertyDelegate = new SettableBeanPropertyDelegate(delegateMock, anySetterMock, () -> true);
}

@Test
Expand Down
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