Skip to content

Commit 0436726

Browse files
Merge pull request #180 from commercetools/179-fix-attribute-reference-replacement
179 fix attribute reference replacement
2 parents 0d05b8b + 1b7c07b commit 0436726

21 files changed

Lines changed: 326 additions & 15 deletions

src/main/java/com/commercetools/sync/products/helpers/VariantReferenceResolver.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
1111
import com.fasterxml.jackson.databind.node.ObjectNode;
1212
import io.sphere.sdk.products.PriceDraft;
13+
import io.sphere.sdk.products.Product;
1314
import io.sphere.sdk.products.ProductVariantDraft;
1415
import io.sphere.sdk.products.ProductVariantDraftBuilder;
1516
import io.sphere.sdk.products.attributes.AttributeDraft;
@@ -33,6 +34,9 @@ public final class VariantReferenceResolver extends BaseReferenceResolver<Produc
3334
private final PriceReferenceResolver priceReferenceResolver;
3435
private final ProductService productService;
3536

37+
public static final String REFERENCE_TYPE_ID_FIELD = "typeId";
38+
public static final String REFERENCE_ID_FIELD = "id";
39+
3640
/**
3741
* Takes a {@link ProductSyncOptions} instance, {@link TypeService}, a {@link ChannelService} and a
3842
* {@link ProductService} to instantiate a {@link VariantReferenceResolver} instance that could be used to resolve
@@ -140,26 +144,26 @@ private CompletionStage<JsonNode> resolveAttributeReferenceValue(@Nonnull final
140144

141145
static boolean isProductReference(@Nonnull final JsonNode referenceValue) {
142146
return getReferenceTypeIdIfReference(referenceValue)
143-
.map(referenceTypeId -> Objects.equals(referenceTypeId, "product"))
147+
.map(referenceTypeId -> Objects.equals(referenceTypeId, Product.referenceTypeId()))
144148
.orElse(false);
145149
}
146150

147151
private static Optional<String> getReferenceTypeIdIfReference(@Nonnull final JsonNode referenceValue) {
148-
final JsonNode typeId = referenceValue.get("typeId");
152+
final JsonNode typeId = referenceValue.get(REFERENCE_TYPE_ID_FIELD);
149153
return typeId != null ? Optional.ofNullable(typeId.asText()) : Optional.empty();
150154
}
151155

152156
CompletionStage<Optional<String>> getResolvedIdFromKeyInReference(@Nonnull final JsonNode referenceValue) {
153-
final JsonNode idField = referenceValue.get("id");
157+
final JsonNode idField = referenceValue.get(REFERENCE_ID_FIELD);
154158
return idField != null
155159
? productService.fetchCachedProductId(idField.asText())
156160
: CompletableFuture.completedFuture(Optional.empty());
157161
}
158162

159163
private JsonNode createProductReferenceJson(@Nonnull final String productId) {
160164
final ObjectNode productReferenceJsonNode = JsonNodeFactory.instance.objectNode();
161-
productReferenceJsonNode.put("id", productId);
162-
productReferenceJsonNode.put("typeId", "product");
165+
productReferenceJsonNode.put(REFERENCE_ID_FIELD, productId);
166+
productReferenceJsonNode.put(REFERENCE_TYPE_ID_FIELD, Product.referenceTypeId());
163167
return productReferenceJsonNode;
164168
}
165169

src/main/java/com/commercetools/sync/products/utils/VariantReferenceReplacementUtils.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.commercetools.sync.products.utils;
22

3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.node.ArrayNode;
35
import io.sphere.sdk.channels.Channel;
4-
import io.sphere.sdk.json.JsonException;
56
import io.sphere.sdk.models.Reference;
67
import io.sphere.sdk.products.Price;
78
import io.sphere.sdk.products.PriceDraft;
@@ -23,6 +24,7 @@
2324
import java.util.stream.Collectors;
2425

2526
import static com.commercetools.sync.commons.utils.SyncUtils.replaceReferenceIdWithKey;
27+
import static com.commercetools.sync.products.helpers.VariantReferenceResolver.REFERENCE_TYPE_ID_FIELD;
2628
import static java.util.stream.Collectors.toList;
2729
import static java.util.stream.Collectors.toSet;
2830

@@ -128,11 +130,10 @@ static Optional<Reference<Product>> replaceAttributeReferenceIdWithKey(@Nonnull
128130
}
129131

130132
private static Optional<Reference<Product>> getProductReference(@Nonnull final Attribute attribute) {
131-
try {
132-
return Optional.of(attribute.getValue(AttributeAccess.ofProductReference()));
133-
} catch (final JsonException exception) {
134-
return Optional.empty();
135-
}
133+
return Optional.of(attribute)
134+
.filter(VariantReferenceReplacementUtils::isProductReference)
135+
.map(productReferenceAttribute -> productReferenceAttribute
136+
.getValue(AttributeAccess.ofProductReference()));
136137
}
137138

138139
@SuppressWarnings("ConstantConditions") // NPE cannot occur due to being checked in replaceReferenceIdWithKey
@@ -147,10 +148,27 @@ static Optional<Set<Reference<Product>>> replaceAttributeReferenceSetIdsWithKeys
147148
}
148149

149150
private static Optional<Set<Reference<Product>>> getProductReferenceSet(@Nonnull final Attribute attribute) {
150-
try {
151-
return Optional.of(attribute.getValue(AttributeAccess.ofProductReferenceSet()));
152-
} catch (final JsonException exception) {
153-
return Optional.empty();
151+
return Optional.of(attribute)
152+
.filter(VariantReferenceReplacementUtils::isProductReferenceSet)
153+
.map(productReferenceSetAttribute -> productReferenceSetAttribute
154+
.getValue(AttributeAccess.ofProductReferenceSet()));
155+
}
156+
157+
static boolean isProductReference(@Nonnull final Attribute attribute) {
158+
final JsonNode valueAsJsonNode = attribute.getValueAsJsonNode();
159+
return !(valueAsJsonNode instanceof ArrayNode) && isValueAProductReference(valueAsJsonNode);
160+
}
161+
162+
static boolean isProductReferenceSet(@Nonnull final Attribute attribute) {
163+
final JsonNode valueAsJsonNode = attribute.getValueAsJsonNode();
164+
return (valueAsJsonNode instanceof ArrayNode) && isValueAProductReference(valueAsJsonNode.elements().next());
165+
}
166+
167+
private static boolean isValueAProductReference(@Nonnull final JsonNode valueAsJsonNode) {
168+
if (valueAsJsonNode.isContainerNode()) {
169+
final JsonNode typeIdNode = valueAsJsonNode.get(REFERENCE_TYPE_ID_FIELD);
170+
return typeIdNode != null && Product.referenceTypeId().equals(typeIdNode.asText());
154171
}
172+
return false;
155173
}
156174
}

src/test/java/com/commercetools/sync/products/ProductSyncMockUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ public class ProductSyncMockUtils {
5353
public static final String PRODUCT_TYPE_RESOURCE_PATH = "product-type.json";
5454
public static final String PRODUCT_TYPE_NO_KEY_RESOURCE_PATH = "product-type-no-key.json";
5555
public static final String CATEGORY_KEY_1_RESOURCE_PATH = "category-key-1.json";
56+
public static final String BOOLEAN_ATTRIBUTE = "boolean-attribute.json";
57+
public static final String TEXT_ATTRIBUTE = "text-attribute.json";
58+
public static final String LTEXT_ATTRIBUTE = "ltext-attribute.json";
59+
public static final String ENUM_ATTRIBUTE = "enum-attribute.json";
60+
public static final String LENUM_ATTRIBUTE = "lenum-attribute.json";
61+
public static final String NUMBER_ATTRIBUTE = "number-attribute.json";
62+
public static final String MONEY_ATTRIBUTE = "money-attribute.json";
63+
public static final String DATE_ATTRIBUTE = "date-attribute.json";
64+
public static final String TIME_ATTRIBUTE = "time-attribute.json";
65+
public static final String DATE_TIME_ATTRIBUTE = "datetime-attribute.json";
66+
public static final String PRODUCT_REFERENCE_ATTRIBUTE = "product-reference-attribute.json";
67+
public static final String CATEGORY_REFERENCE_ATTRIBUTE = "category-reference-attribute.json";
68+
public static final String PRODUCT_REFERENCE_SET_ATTRIBUTE = "product-reference-set-attribute.json";
69+
public static final String LTEXT_SET_ATTRIBUTE = "ltext-set-attribute.json";
70+
71+
72+
5673

5774
/**
5875
* Unfortunately, <a href="http://dev.commercetools.com/http-api-projects-products.html#category-order-hints">

src/test/java/com/commercetools/sync/products/utils/VariantReferenceReplacementUtilsTest.java

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,26 @@
2222
import java.util.Set;
2323
import java.util.UUID;
2424

25+
import static com.commercetools.sync.products.ProductSyncMockUtils.BOOLEAN_ATTRIBUTE;
26+
import static com.commercetools.sync.products.ProductSyncMockUtils.CATEGORY_REFERENCE_ATTRIBUTE;
27+
import static com.commercetools.sync.products.ProductSyncMockUtils.DATE_ATTRIBUTE;
28+
import static com.commercetools.sync.products.ProductSyncMockUtils.DATE_TIME_ATTRIBUTE;
29+
import static com.commercetools.sync.products.ProductSyncMockUtils.ENUM_ATTRIBUTE;
30+
import static com.commercetools.sync.products.ProductSyncMockUtils.LENUM_ATTRIBUTE;
31+
import static com.commercetools.sync.products.ProductSyncMockUtils.LTEXT_ATTRIBUTE;
32+
import static com.commercetools.sync.products.ProductSyncMockUtils.LTEXT_SET_ATTRIBUTE;
33+
import static com.commercetools.sync.products.ProductSyncMockUtils.MONEY_ATTRIBUTE;
34+
import static com.commercetools.sync.products.ProductSyncMockUtils.NUMBER_ATTRIBUTE;
2535
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_KEY_1_RESOURCE_PATH;
36+
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_REFERENCE_ATTRIBUTE;
37+
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_REFERENCE_SET_ATTRIBUTE;
38+
import static com.commercetools.sync.products.ProductSyncMockUtils.TEXT_ATTRIBUTE;
39+
import static com.commercetools.sync.products.ProductSyncMockUtils.TIME_ATTRIBUTE;
2640
import static com.commercetools.sync.products.ProductSyncMockUtils.getChannelMock;
2741
import static com.commercetools.sync.products.ProductSyncMockUtils.getPriceMockWithChannelReference;
2842
import static com.commercetools.sync.products.ProductSyncMockUtils.getProductVariantMockWithPrices;
43+
import static com.commercetools.sync.products.utils.VariantReferenceReplacementUtils.isProductReference;
44+
import static com.commercetools.sync.products.utils.VariantReferenceReplacementUtils.isProductReferenceSet;
2945
import static com.commercetools.sync.products.utils.VariantReferenceReplacementUtils.replaceAttributeReferenceIdWithKey;
3046
import static com.commercetools.sync.products.utils.VariantReferenceReplacementUtils.replaceAttributeReferenceSetIdsWithKeys;
3147
import static com.commercetools.sync.products.utils.VariantReferenceReplacementUtils.replaceAttributesReferencesIdsWithKeys;
@@ -298,4 +314,113 @@ public void replaceAttributesReferencesIdsWithKeys_WithNoAttributes_ShouldNotRep
298314
final List<AttributeDraft> replacedDrafts = replaceAttributesReferencesIdsWithKeys(variant);
299315
assertThat(replacedDrafts).isEmpty();
300316
}
317+
318+
@Test
319+
public void replaceAttributesReferencesIdsWithKeys_WithAttributesWithNoReferences_ShouldNotChangeAttributes() {
320+
final Product product = readObjectFromResource(PRODUCT_KEY_1_RESOURCE_PATH, Product.class);
321+
final ProductVariant masterVariant = product.getMasterData().getStaged().getMasterVariant();
322+
final List<AttributeDraft> replacedDrafts = replaceAttributesReferencesIdsWithKeys(masterVariant);
323+
replacedDrafts.forEach(attributeDraft -> {
324+
final String name = attributeDraft.getName();
325+
final Attribute originalAttribute = masterVariant.getAttribute(name);
326+
assertThat(originalAttribute).isNotNull();
327+
assertThat(originalAttribute.getValueAsJsonNode()).isEqualTo(attributeDraft.getValue());
328+
});
329+
}
330+
331+
@Test
332+
public void isProductReference_WithDifferentAttributeTypes_ShouldBeTrueForProductReferenceAttributeOnly() {
333+
final Attribute booleanAttribute = readObjectFromResource(BOOLEAN_ATTRIBUTE, Attribute.class);
334+
assertThat(isProductReference(booleanAttribute)).isFalse();
335+
336+
final Attribute textAttribute = readObjectFromResource(TEXT_ATTRIBUTE, Attribute.class);
337+
assertThat(isProductReference(textAttribute)).isFalse();
338+
339+
final Attribute ltextAttribute = readObjectFromResource(LTEXT_ATTRIBUTE, Attribute.class);
340+
assertThat(isProductReference(ltextAttribute)).isFalse();
341+
342+
final Attribute enumAttribute = readObjectFromResource(ENUM_ATTRIBUTE, Attribute.class);
343+
assertThat(isProductReference(enumAttribute)).isFalse();
344+
345+
final Attribute lenumAttribute = readObjectFromResource(LENUM_ATTRIBUTE, Attribute.class);
346+
assertThat(isProductReference(lenumAttribute)).isFalse();
347+
348+
final Attribute numberAttribute = readObjectFromResource(NUMBER_ATTRIBUTE, Attribute.class);
349+
assertThat(isProductReference(numberAttribute)).isFalse();
350+
351+
final Attribute moneyAttribute = readObjectFromResource(MONEY_ATTRIBUTE, Attribute.class);
352+
assertThat(isProductReference(moneyAttribute)).isFalse();
353+
354+
final Attribute dateAttribute = readObjectFromResource(DATE_ATTRIBUTE, Attribute.class);
355+
assertThat(isProductReference(dateAttribute)).isFalse();
356+
357+
final Attribute timeAttribute = readObjectFromResource(TIME_ATTRIBUTE, Attribute.class);
358+
assertThat(isProductReference(timeAttribute)).isFalse();
359+
360+
final Attribute dateTimeAttribute = readObjectFromResource(DATE_TIME_ATTRIBUTE, Attribute.class);
361+
assertThat(isProductReference(dateTimeAttribute)).isFalse();
362+
363+
final Attribute productReferenceSetAttribute =
364+
readObjectFromResource(PRODUCT_REFERENCE_SET_ATTRIBUTE, Attribute.class);
365+
assertThat(isProductReference(productReferenceSetAttribute)).isFalse();
366+
367+
final Attribute categoryReferenceAttribute =
368+
readObjectFromResource(CATEGORY_REFERENCE_ATTRIBUTE, Attribute.class);
369+
assertThat(isProductReference(categoryReferenceAttribute)).isFalse();
370+
371+
final Attribute ltextSetAttribute = readObjectFromResource(LTEXT_SET_ATTRIBUTE, Attribute.class);
372+
assertThat(isProductReference(ltextSetAttribute)).isFalse();
373+
374+
final Attribute productReferenceAttribute =
375+
readObjectFromResource(PRODUCT_REFERENCE_ATTRIBUTE, Attribute.class);
376+
assertThat(isProductReference(productReferenceAttribute)).isTrue();
377+
}
378+
379+
@Test
380+
public void isProductReferenceSet_WithDifferentAttributeTypes_ShouldBeTrueForProductReferenceSetAttributeOnly() {
381+
final Attribute booleanAttribute = readObjectFromResource(BOOLEAN_ATTRIBUTE, Attribute.class);
382+
assertThat(isProductReferenceSet(booleanAttribute)).isFalse();
383+
384+
final Attribute textAttribute = readObjectFromResource(TEXT_ATTRIBUTE, Attribute.class);
385+
assertThat(isProductReferenceSet(textAttribute)).isFalse();
386+
387+
final Attribute ltextAttribute = readObjectFromResource(LTEXT_ATTRIBUTE, Attribute.class);
388+
assertThat(isProductReferenceSet(ltextAttribute)).isFalse();
389+
390+
final Attribute enumAttribute = readObjectFromResource(ENUM_ATTRIBUTE, Attribute.class);
391+
assertThat(isProductReferenceSet(enumAttribute)).isFalse();
392+
393+
final Attribute lenumAttribute = readObjectFromResource(LENUM_ATTRIBUTE, Attribute.class);
394+
assertThat(isProductReferenceSet(lenumAttribute)).isFalse();
395+
396+
final Attribute numberAttribute = readObjectFromResource(NUMBER_ATTRIBUTE, Attribute.class);
397+
assertThat(isProductReferenceSet(numberAttribute)).isFalse();
398+
399+
final Attribute moneyAttribute = readObjectFromResource(MONEY_ATTRIBUTE, Attribute.class);
400+
assertThat(isProductReferenceSet(moneyAttribute)).isFalse();
401+
402+
final Attribute dateAttribute = readObjectFromResource(DATE_ATTRIBUTE, Attribute.class);
403+
assertThat(isProductReferenceSet(dateAttribute)).isFalse();
404+
405+
final Attribute timeAttribute = readObjectFromResource(TIME_ATTRIBUTE, Attribute.class);
406+
assertThat(isProductReferenceSet(timeAttribute)).isFalse();
407+
408+
final Attribute dateTimeAttribute = readObjectFromResource(DATE_TIME_ATTRIBUTE, Attribute.class);
409+
assertThat(isProductReferenceSet(dateTimeAttribute)).isFalse();
410+
411+
final Attribute productReferenceAttribute =
412+
readObjectFromResource(PRODUCT_REFERENCE_ATTRIBUTE, Attribute.class);
413+
assertThat(isProductReferenceSet(productReferenceAttribute)).isFalse();
414+
415+
final Attribute categoryReferenceAttribute =
416+
readObjectFromResource(CATEGORY_REFERENCE_ATTRIBUTE, Attribute.class);
417+
assertThat(isProductReferenceSet(categoryReferenceAttribute)).isFalse();
418+
419+
final Attribute ltextSetAttribute = readObjectFromResource(LTEXT_SET_ATTRIBUTE, Attribute.class);
420+
assertThat(isProductReferenceSet(ltextSetAttribute)).isFalse();
421+
422+
final Attribute productReferenceSetAttribute =
423+
readObjectFromResource(PRODUCT_REFERENCE_SET_ATTRIBUTE, Attribute.class);
424+
assertThat(isProductReferenceSet(productReferenceSetAttribute)).isTrue();
425+
}
301426
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "boolean",
3+
"value": true
4+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "categoryReference",
3+
"value":
4+
{
5+
"id": "53c4a8b4-754f-4b95-b6f2-3e1e70e3d0c3",
6+
"typeId": "category"
7+
}
8+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "date",
3+
"value": "2017-11-09"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "onlineDate",
3+
"value": "2016-05-20T01:02:46.290Z"
4+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "enum",
3+
"value": {
4+
"label": "Product",
5+
"key": "productType_product"
6+
}
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "lenum",
3+
"value": {
4+
"fr": "#FR Legal Text",
5+
"it": "#IT Legal Text",
6+
"de": "#DE Legal Text",
7+
"en": "#EN Legal Text"
8+
}
9+
}

0 commit comments

Comments
 (0)