Skip to content

Commit

Permalink
SUPPORT-28804 add custom deserializer for attrs in import api (#748)
Browse files Browse the repository at this point in the history
  • Loading branch information
lojzatran authored Nov 20, 2024
1 parent a248061 commit e04ab17
Show file tree
Hide file tree
Showing 10 changed files with 1,118 additions and 239 deletions.
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ a8ec45c8ea4ba559247b654d01b0d35b21a68865
d0129c1095216d5c830900c8a6223ef5d4274de1
4bc5c823b8ebf5a00491c7e63e1ea49d29bf5ee7
352051999507bd78542e177d67ce1548a0752691
bbe9f971763ca1b27687a6a51067a385a0d23b04
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ public void execute() {
}
}

private <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>> void deleteAllResources(
private static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>> void deleteAllResources(
SimplePagedQueryResourceRequest<TMethod, TResult, ?> request, Consumer<TElement> deleteFn) {

QueryUtils.queryAll(request, list -> {
list.forEach(deleteFn);
}, 100).toCompletableFuture().join();
}

private void checkDepends(Runnable block) {
public static void checkDepends(Runnable block) {
assertEventually(Duration.ofSeconds(60), Duration.ofMillis(1000), block);
}

Expand Down Expand Up @@ -212,7 +212,7 @@ private void deleteAllCategories() {
} while (response.getResults().size() != 0);
}

private void deleteAllCartDiscounts() {
public static void deleteAllCartDiscounts() {
checkDepends(() -> Assertions.assertThat(
CommercetoolsTestUtils.getProjectApiRoot().discountCodes().get().executeBlocking().getBody().getCount())
.isZero());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

package commercetools.cart_discount;

import static cleanup.DeleteEverythingIntegrationTest.deleteAllCartDiscounts;
import static commercetools.cart_discount.CartDiscountFixtures.*;
import static commercetools.type.TypeFixtures.getFieldName;

Expand All @@ -16,10 +17,18 @@
import commercetools.utils.CommercetoolsTestUtils;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

public class CartDiscountIntegrationTests {

@BeforeAll
@AfterAll
public static void deleteCartDiscounts() {
deleteAllCartDiscounts();
}

@Test
public void ref() {
Optional<ReferenceTypeId> optional = ReferenceTypeId.findEnumViaJsonName("product-type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public ApiModule(ModuleOptions options) {
}
else {
addDeserializer(AttributeImpl.class,
new AtrributeDeserializer(attributeAsDateString, attributeNumberAsDouble));
new AttributeDeserializer(attributeAsDateString, attributeNumberAsDouble));
}
if (customFieldAsJsonNode) {
addDeserializer(FieldContainerImpl.class, new CustomFieldJsonNodeDeserializer());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,247 +1,20 @@

package com.commercetools.api.json;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.regex.Pattern;

import com.commercetools.api.models.common.LocalizedString;
import com.commercetools.api.models.common.Reference;
import com.commercetools.api.models.common.TypedMoney;
import com.commercetools.api.models.product.*;
import com.commercetools.api.models.product_type.AttributeLocalizedEnumValue;
import com.commercetools.api.models.product_type.AttributePlainEnumValue;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;

public class AtrributeDeserializer extends JsonDeserializer<AttributeImpl> {

private static Pattern p = Pattern.compile("^[0-9]");
private static Pattern dateTime = Pattern
.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]{1,6})?(Z|[+-][0-9]{2}:[0-9]{2})");
private static Pattern date = Pattern.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}");
private static Pattern time = Pattern.compile("^[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]{1,6})?");

private final boolean deserializeAsDate;

private final boolean deserializeNumberAsDouble;

/**
* @deprecated typo in the class name, use AttributeDeserializer instead
*/
@Deprecated
public class AtrributeDeserializer extends AttributeDeserializer {
public AtrributeDeserializer(boolean deserializeAsDateString) {
this.deserializeAsDate = !deserializeAsDateString;
this.deserializeNumberAsDouble = false;
super(deserializeAsDateString);
}

public AtrributeDeserializer(boolean deserializeAsDateString, boolean deserializeNumberAsDouble) {
this.deserializeAsDate = !deserializeAsDateString;
this.deserializeNumberAsDouble = deserializeNumberAsDouble;
super(deserializeAsDateString, deserializeNumberAsDouble);
}

public AtrributeDeserializer() {
this.deserializeAsDate = true;
this.deserializeNumberAsDouble = false;
}

@Override
public AttributeImpl deserialize(JsonParser p, DeserializationContext ctx) throws IOException {

JsonNode node = p.readValueAsTree();
JsonNode valueNode = node.get("value");

AttributeBuilder builder = Attribute.builder();
builder.name(node.get("name").asText());

return (AttributeImpl) builder.value(p.getCodec().treeAsTokens(valueNode).readValueAs(typeRef(valueNode)))
.build();
}

private TypeReference<?> typeRef(JsonNode valueNode) {
JsonNodeType valueNodeType = valueNode.getNodeType();
switch (valueNodeType) {
case BOOLEAN:
return new TypeReference<Boolean>() {
};
case NUMBER:
if (!deserializeNumberAsDouble && (valueNode.isInt() || valueNode.isLong())) {
return new TypeReference<Long>() {
};
}
return new TypeReference<Double>() {
};
case STRING:
if (deserializeAsDate) {
String val = valueNode.asText();
if (p.matcher(val).find()) {
if (dateTime.matcher(val).find()) {
return new TypeReference<ZonedDateTime>() {
};
}
if (date.matcher(val).matches()) {
return new TypeReference<LocalDate>() {
};
}
if (time.matcher(val).matches()) {
return new TypeReference<LocalTime>() {
};
}
}
}
return new TypeReference<String>() {
};
case OBJECT:
if (valueNode.has("key") && valueNode.has("label")) {
JsonNode label = valueNode.get("label");
if (label.getNodeType() == JsonNodeType.OBJECT) {
return new TypeReference<AttributeLocalizedEnumValue>() {
};
}
return new TypeReference<AttributePlainEnumValue>() {
};
}
if (valueNode.has("currencyCode")) {
return new TypeReference<TypedMoney>() {
};
}
if (valueNode.has("typeId")) {
return new TypeReference<Reference>() {
};
}
if (valueNode.has("value")) {
return new TypeReference<Attribute>() {
};
}
return new TypeReference<LocalizedString>() {
};
case ARRAY:
JsonNode first = valueNode.get(0);
switch (elemType(first)) {
case STRING:
return new TypeReference<List<String>>() {
};
case DATE:
return new TypeReference<List<LocalDate>>() {
};
case DATETIME:
return new TypeReference<List<ZonedDateTime>>() {
};
case TIME:
return new TypeReference<List<LocalTime>>() {
};
case NUMBER:
return new TypeReference<List<Double>>() {
};
case LONG:
return new TypeReference<List<Long>>() {
};
case BOOLEAN:
return new TypeReference<List<Boolean>>() {
};
case ENUM:
return new TypeReference<List<AttributePlainEnumValue>>() {
};
case LOCALIZED_ENUM:
return new TypeReference<List<AttributeLocalizedEnumValue>>() {
};
case LOCALIZED_STRING:
return new TypeReference<List<LocalizedString>>() {
};
case MONEY:
return new TypeReference<List<TypedMoney>>() {
};
case REFERENCE:
return new TypeReference<List<Reference>>() {
};
case NESTED:
return new TypeReference<List<Attribute>>() {
};
case SET_NESTED:
return new TypeReference<List<List<Attribute>>>() {
};
default:
return new TypeReference<List<JsonNode>>() {
};
}
default:
return new TypeReference<JsonNode>() {
};
}
}

private ElemType elemType(JsonNode valueNode) {
if (valueNode == null) {
return ElemType.JSON_NODE;
}
JsonNodeType valueNodeType = valueNode.getNodeType();
switch (valueNodeType) {
case OBJECT:
if (valueNode.has("key") && valueNode.has("label")) {
JsonNode label = valueNode.get("label");
if (label.getNodeType() == JsonNodeType.OBJECT) {
return ElemType.LOCALIZED_ENUM;
}
return ElemType.ENUM;
}
if (valueNode.has("currencyCode")) {
return ElemType.MONEY;
}
if (valueNode.has("typeId")) {
return ElemType.REFERENCE;
}
if (valueNode.has("value")) {
return ElemType.NESTED;
}
return ElemType.LOCALIZED_STRING;
case NUMBER:
if (!deserializeNumberAsDouble && (valueNode.isInt() || valueNode.isLong())) {
return ElemType.LONG;
}
return ElemType.NUMBER;
case STRING:
if (deserializeAsDate) {
String val = valueNode.asText();
if (p.matcher(val).find()) {
if (dateTime.matcher(val).find()) {
return ElemType.DATETIME;
}
if (date.matcher(val).matches()) {
return ElemType.DATE;
}
if (time.matcher(val).matches()) {
return ElemType.TIME;
}
}
}
return ElemType.STRING;
case ARRAY:
return ElemType.SET_NESTED;
case BOOLEAN:
return ElemType.BOOLEAN;
default:
return ElemType.JSON_NODE;
}
}

private enum ElemType {
STRING,
DATE,
DATETIME,
TIME,
NUMBER,
LONG,
BOOLEAN,
ENUM,
LOCALIZED_ENUM,
LOCALIZED_STRING,
REFERENCE,
MONEY,
JSON_NODE,
NESTED,
SET_NESTED
super();
}
}
Loading

0 comments on commit e04ab17

Please sign in to comment.