Magento 2 GraphQL API provides a flexible and efficient way to interact with Magento e-commerce platforms. This Java implementation demonstrates comprehensive integration with Magento 2's GraphQL API for various e-commerce operations.
Magento 2 GraphQL Overview
Key GraphQL operations:
- Product catalog browsing and searching
- Shopping cart management
- Customer accounts and authentication
- Order management and history
- Checkout process
- CMS content retrieval
Dependencies and Setup
Maven Configuration:
<dependencies> <!-- GraphQL Client --> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java</artifactId> <version>20.4</version> </dependency> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java-client</artifactId> <version>2.0.0</version> </dependency> <!-- HTTP Client --> <dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.2.1</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <!-- Caching --> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.1.6</version> </dependency> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JWT for authentication --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> </dependencies>
Configuration Management
MagentoConfig.java:
@Configuration @ConfigurationProperties(prefix = "magento") @Data public class MagentoConfig { private String baseUrl; private String graphqlEndpoint = "/graphql"; private String storeCode = "default"; private AuthConfig auth = new AuthConfig(); private CacheConfig cache = new CacheConfig(); private RetryConfig retry = new RetryConfig(); @Data public static class AuthConfig { private String integrationToken; private String customerToken; private String adminToken; private Duration tokenExpiry = Duration.ofHours(2); private boolean enableTokenRefresh = true; } @Data public static class CacheConfig { private boolean enabled = true; private Duration productTtl = Duration.ofMinutes(10); private Duration categoryTtl = Duration.ofMinutes(30); private Duration cartTtl = Duration.ofMinutes(5); private int maxSize = 10000; } @Data public static class RetryConfig { private int maxAttempts = 3; private Duration initialBackoff = Duration.ofSeconds(1); private Duration maxBackoff = Duration.ofSeconds(10); private List<Integer> retryableStatusCodes = Arrays.asList(500, 502, 503, 504); } public String getGraphqlUrl() { return baseUrl + graphqlEndpoint; } public String getStoreHeader() { return "Store"; } } GraphQL Client Service
MagentoGraphQLClient.java:
@Service @Slf4j public class MagentoGraphQLClient { private final MagentoConfig config; private final ObjectMapper objectMapper; private final CloseableHttpClient httpClient; private final Cache<String, Object> cache; public MagentoGraphQLClient(MagentoConfig config) { this.config = config; this.objectMapper = new ObjectMapper(); this.httpClient = createHttpClient(); this.cache = createCache(); } public GraphQLResponse executeQuery(GraphQLRequest request, String token) { return executeQuery(request, token, null); } public GraphQLResponse executeQuery(GraphQLRequest request, String token, String customerToken) { String cacheKey = generateCacheKey(request, token, customerToken); if (config.getCache().isEnabled() && request.isCacheable()) { GraphQLResponse cached = (GraphQLResponse) cache.getIfPresent(cacheKey); if (cached != null) { log.debug("Cache hit for query: {}", request.getOperationName()); return cached; } } return executeWithRetry(request, token, customerToken, cacheKey); } public GraphQLResponse executeMutation(GraphQLRequest request, String token) { return executeMutation(request, token, null); } public GraphQLResponse executeMutation(GraphQLRequest request, String token, String customerToken) { // Mutations are not cached return executeWithRetry(request, token, customerToken, null); } private GraphQLResponse executeWithRetry(GraphQLRequest request, String token, String customerToken, String cacheKey) { int attempt = 0; Exception lastException = null; while (attempt < config.getRetry().getMaxAttempts()) { try { GraphQLResponse response = executeGraphQLCall(request, token, customerToken); if (response.isSuccess() && cacheKey != null && config.getCache().isEnabled()) { cache.put(cacheKey, response); } return response; } catch (Exception e) { lastException = e; attempt++; if (shouldRetry(e) && attempt < config.getRetry().getMaxAttempts()) { long backoff = calculateBackoff(attempt); log.warn("GraphQL call failed (attempt {}), retrying in {}ms: {}", attempt, backoff, e.getMessage()); try { Thread.sleep(backoff); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new MagentoException("GraphQL call interrupted", ie); } } else { break; } } } throw new MagentoException("GraphQL call failed after " + attempt + " attempts", lastException); } private GraphQLResponse executeGraphQLCall(GraphQLRequest request, String token, String customerToken) { try { HttpPost httpPost = new HttpPost(config.getGraphqlUrl()); // Set headers httpPost.setHeader("Content-Type", "application/json"); httpPost.setHeader("Accept", "application/json"); if (token != null) { httpPost.setHeader("Authorization", "Bearer " + token); } if (customerToken != null) { httpPost.setHeader("X-Customer-Token", customerToken); } httpPost.setHeader(config.getStoreHeader(), config.getStoreCode()); // Set request body String requestBody = objectMapper.writeValueAsString(request); httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8)); // Execute request try (CloseableHttpResponse response = httpClient.execute(httpPost)) { return parseResponse(response, request); } } catch (Exception e) { throw new MagentoException("GraphQL execution failed", e); } } private GraphQLResponse parseResponse(CloseableHttpResponse httpResponse, GraphQLRequest request) { try { String responseBody = EntityUtils.toString(httpResponse.getEntity()); int statusCode = httpResponse.getCode(); if (statusCode >= 200 && statusCode < 300) { JsonNode jsonResponse = objectMapper.readTree(responseBody); // Check for GraphQL errors if (jsonResponse.has("errors")) { List<GraphQLError> errors = parseGraphQLErrors(jsonResponse.get("errors")); return GraphQLResponse.builder() .success(false) .errors(errors) .rawResponse(responseBody) .build(); } return GraphQLResponse.builder() .success(true) .data(jsonResponse.get("data")) .rawResponse(responseBody) .extensions(jsonResponse.has("extensions") ? jsonResponse.get("extensions") : null) .build(); } else { return GraphQLResponse.builder() .success(false) .errors(List.of(new GraphQLError( "HTTP_ERROR", "HTTP " + statusCode + ": " + responseBody ))) .rawResponse(responseBody) .build(); } } catch (Exception e) { throw new MagentoException("Failed to parse GraphQL response", e); } } private List<GraphQLError> parseGraphQLErrors(JsonNode errorsNode) { List<GraphQLError> errors = new ArrayList<>(); if (errorsNode.isArray()) { for (JsonNode errorNode : errorsNode) { GraphQLError error = new GraphQLError( errorNode.has("extensions") && errorNode.get("extensions").has("category") ? errorNode.get("extensions").get("category").asText() : "UNKNOWN", errorNode.has("message") ? errorNode.get("message").asText() : "Unknown error" ); if (errorNode.has("path")) { error.setPath(parsePath(errorNode.get("path"))); } if (errorNode.has("locations")) { error.setLocations(parseLocations(errorNode.get("locations"))); } errors.add(error); } } return errors; } private List<String> parsePath(JsonNode pathNode) { List<String> path = new ArrayList<>(); if (pathNode.isArray()) { for (JsonNode node : pathNode) { path.add(node.asText()); } } return path; } private List<GraphQLError.Location> parseLocations(JsonNode locationsNode) { List<GraphQLError.Location> locations = new ArrayList<>(); if (locationsNode.isArray()) { for (JsonNode locationNode : locationsNode) { locations.add(new GraphQLError.Location( locationNode.get("line").asInt(), locationNode.get("column").asInt() )); } } return locations; } private CloseableHttpClient createHttpClient() { return HttpClients.custom() .setConnectionManager(new PoolingHttpClientConnectionManager()) .setDefaultRequestConfig(RequestConfig.custom() .setConnectTimeout(10000) .setSocketTimeout(30000) .build()) .build(); } private Cache<String, Object> createCache() { if (!config.getCache().isEnabled()) { return null; } return Caffeine.newBuilder() .maximumSize(config.getCache().getMaxSize()) .expireAfterWrite(config.getCache().getProductTtl()) .build(); } private String generateCacheKey(GraphQLRequest request, String token, String customerToken) { String key = request.getQuery() + "|" + request.getVariables() + "|" + request.getOperationName() + "|" + token + "|" + customerToken; return Integer.toHexString(key.hashCode()); } private boolean shouldRetry(Exception e) { if (e instanceof MagentoException) { // Check if it's a retryable HTTP status code String message = e.getMessage(); for (int statusCode : config.getRetry().getRetryableStatusCodes()) { if (message.contains("HTTP " + statusCode)) { return true; } } } return false; } private long calculateBackoff(int attempt) { long backoff = config.getRetry().getInitialBackoff().toMillis() * (long) Math.pow(2, attempt - 1); return Math.min(backoff, config.getRetry().getMaxBackoff().toMillis()); } public void clearCache() { if (cache != null) { cache.invalidateAll(); } } public void clearCacheForPattern(String pattern) { if (cache != null) { cache.asMap().keySet().stream() .filter(key -> key.contains(pattern)) .forEach(cache::invalidate); } } } Product Service
ProductService.java:
```java
@Service
@Slf4j
public class ProductService {
private final MagentoGraphQLClient graphQLClient; private final MagentoConfig config; public ProductService(MagentoGraphQLClient graphQLClient, MagentoConfig config) { this.graphQLClient = graphQLClient; this.config = config; } public ProductResponse getProducts(ProductSearchCriteria criteria) { try { String query = buildProductsQuery(criteria); Map<String, Object> variables = buildProductsVariables(criteria); GraphQLRequest request = GraphQLRequest.builder() .query(query) .variables(variables) .operationName("GetProducts") .cacheable(true) .build(); GraphQLResponse response = graphQLClient.executeQuery(request, config.getAuth().getIntegrationToken()); if (response.isSuccess()) { return parseProductsResponse(response.getData(), criteria); } else { return ProductResponse.builder() .success(false) .errors(response.getErrors().stream() .map(GraphQLError::getMessage) .collect(Collectors.toList())) .build(); } } catch (Exception e) { log.error("Failed to fetch products", e); return ProductResponse.builder() .success(false) .errors(List.of("Failed to fetch products: " + e.getMessage())) .build(); } } public ProductDetailResponse getProductBySku(String sku, String currency) { try { String query = buildProductDetailQuery(); Map<String, Object> variables = Map.of( "sku", sku, "currency", currency != null ? currency : "USD" ); GraphQLRequest request = GraphQLRequest.builder() .query(query) .variables(variables) .operationName("GetProductDetail") .cacheable(true) .build(); GraphQLResponse response = graphQLClient.executeQuery(request, config.getAuth().getIntegrationToken()); if (response.isSuccess()) { return parseProductDetailResponse(response.getData()); } else { return ProductDetailResponse.builder() .success(false) .errors(response.getErrors().stream() .map(GraphQLError::getMessage) .collect(Collectors.toList())) .build(); } } catch (Exception e) { log.error("Failed to fetch product by SKU: {}", sku, e); return ProductDetailResponse.builder() .success(false) .errors(List.of("Failed to fetch product: " + e.getMessage())) .build(); } } public ProductDetailResponse getProductByUrlKey(String urlKey, String currency) { try { String query = buildProductByUrlKeyQuery(); Map<String, Object> variables = Map.of( "urlKey", urlKey, "currency", currency != null ? currency : "USD" ); GraphQLRequest request = GraphQLRequest.builder() .query(query) .variables(variables) .operationName("GetProductByUrlKey") .cacheable(true) .build(); GraphQLResponse response = graphQLClient.executeQuery(request, config.getAuth().getIntegrationToken()); if (response.isSuccess()) { return parseProductDetailResponse(response.getData()); } else { return ProductDetailResponse.builder() .success(false) .errors(response.getErrors().stream() .map(GraphQLError::getMessage) .collect(Collectors.toList())) .build(); } } catch (Exception e) { log.error("Failed to fetch product by URL key: {}", urlKey, e); return ProductDetailResponse.builder() .success(false) .errors(List.of("Failed to fetch product: " + e.getMessage())) .build(); } } public CategoryResponse getCategories(CategorySearchCriteria criteria) { try { String query = buildCategoriesQuery(criteria); Map<String, Object> variables = buildCategoriesVariables(criteria); GraphQLRequest request = GraphQLRequest.builder() .query(query) .variables(variables) .operationName("GetCategories") .cacheable(true) .build(); GraphQLResponse response = graphQLClient.executeQuery(request, config.getAuth().getIntegrationToken()); if (response.isSuccess()) { return parseCategoriesResponse(response.getData()); } else { return CategoryResponse.builder() .success(false) .errors(response.getErrors().stream() .map(GraphQLError::getMessage) .collect(Collectors.toList())) .build(); } } catch (Exception e) { log.error("Failed to fetch categories", e); return CategoryResponse.builder() .success(false) .errors(List.of("Failed to fetch categories: " + e.getMessage())) .build(); } } public SearchResponse searchProducts(SearchCriteria criteria) { try { String query = buildSearchQuery(criteria); Map<String, Object> variables = buildSearchVariables(criteria); GraphQLRequest request = GraphQLRequest.builder() .query(query) .variables(variables) .operationName("SearchProducts") .cacheable(true) .build(); GraphQLResponse response = graphQLClient.executeQuery(request, config.getAuth().getIntegrationToken()); if (response.isSuccess()) { return parseSearchResponse(response.getData(), criteria); } else { return SearchResponse.builder() .success(false) .errors(response.getErrors().stream() .map(GraphQLError::getMessage) .collect(Collectors.toList())) .build(); } } catch (Exception e) { log.error("Failed to search products", e); return SearchResponse.builder() .success(false) .errors(List.of("Failed to search products: " + e.getMessage())) .build(); } } private String buildProductsQuery(ProductSearchCriteria criteria) { return """ query GetProducts($filter: ProductAttributeFilterInput, $pageSize: Int, $currentPage: Int, $sort: ProductAttributeSortInput) { products( filter: $filter pageSize: $pageSize currentPage: $currentPage sort: $sort ) { items { id sku name url_key image { url label } price_range { minimum_price { regular_price { value currency } final_price { value currency } discount { amount_off percent_off } } } stock_status ... on ConfigurableProduct { configurable_options { attribute_code attribute_uid label values { label swatch_data { value } } } variants { product { sku price_range { minimum_price { final_price { value currency } } } } } } } page_info { page_size current_page total_pages } total_count } } """; } private String buildProductDetailQuery() { return """ query GetProductDetail($sku: String!, $currency: CurrencyEnum) { products(filter: { sku: { eq: $sku } }) { items { id sku name description { html } short_description { html } url_key image { url label } media_gallery { url label position } price_range { minimum_price { regular_price { value currency } final_price { value currency } discount { amount_off percent_off } } } stock_status ... on ConfigurableProduct { configurable_options { attribute_code attribute_uid label values { label swatch_data { value } } } variants { product { sku price_range { minimum_price { final_price { value currency } } } } } } ... on BundleProduct { items { option_id title required type position sku options { id quantity position is_default price price_type can_change_quantity product { id name sku price_range { minimum_price { final_price { value currency } } } } } } } ... on GroupedProduct { items { qty position product { id name sku price_range { minimum_price { final_price { value currency } } } } } } } } } """; } private String buildProductByUrlKeyQuery() { return """ query GetProductByUrlKey($urlKey: String!, $currency: CurrencyEnum) { products(filter: { url_key: { eq: $urlKey } }) { items { id sku name description { html } short_description { html } url_key image { url label } media_gallery { url label position } price_range { minimum_price { regular_price { value currency } final_price { value currency } discount { amount_off percent_off } } } stock_status ... on ConfigurableProduct { configurable_options { attribute_code attribute_uid label values { label swatch_data { value } } } variants { product { sku price_range { minimum_price { final_price { value currency } } } } } } } } } """; } private String buildCategoriesQuery(CategorySearchCriteria criteria) { return """ query GetCategories($filters: CategoryFilterInput, $pageSize: Int, $currentPage: Int) { categoryList(filters: $filters) { id uid name url_key url_path description image product_count children { id uid name url_key url_path product_count } } } """; } private String buildSearchQuery(SearchCriteria criteria) { return """ query SearchProducts($search: String, $filter: ProductAttributeFilterInput, $pageSize: Int, $currentPage: Int, $sort: ProductAttributeSortInput) { products( search: $search filter: $filter pageSize: $pageSize currentPage: $currentPage sort: $sort ) { items { id sku name url_key image { url label } price_range { minimum_price { regular_price { value currency } final_price { value currency } discount { amount_off percent_off } } } stock_status } page_info { page_size current_page total_pages } total_count aggregations { attribute_code label count options { label value count } } } } """; } private Map<String, Object> buildProductsVariables(ProductSearchCriteria criteria) { Map<String, Object> variables = new HashMap<>(); if (criteria.getFilter() != null && !criteria.getFilter().isEmpty()) { variables.put("filter", criteria.getFilter()); } variables.put("pageSize", criteria.getPageSize()); variables.put("currentPage", criteria.getCurrentPage()); if (criteria.getSort() != null && !criteria.getSort().isEmpty()) { variables.put("sort", criteria.getSort()); } return variables; } private Map<String, Object> buildCategoriesVariables(CategorySearchCriteria criteria) { Map<String, Object> variables = new HashMap<>(); if (criteria.getFilters() != null && !criteria.getFilters().isEmpty()) { variables.put("filters", criteria.getFilters()); } variables.put("pageSize", criteria.getPageSize()); variables.put("currentPage", criteria.getCurrentPage()); return variables; } private Map<String, Object> buildSearchVariables(SearchCriteria criteria) { Map<String, Object> variables = new HashMap<>(); if (criteria.getSearch() != null) { variables.put("search", criteria.getSearch()); } if (criteria.getFilter() != null && !criteria.getFilter().isEmpty()) { variables.put("filter", criteria.getFilter()); } variables.put("pageSize", criteria.getPageSize()); variables.put("currentPage", criteria.getCurrentPage()); if (criteria.getSort() != null && !criteria.getSort().isEmpty()) { variables.put("sort", criteria.getSort()); } return variables; } private ProductResponse parseProductsResponse(JsonNode data, ProductSearchCriteria criteria) { try { JsonNode productsNode = data.get("products"); List<Product> products = parseProductItems(productsNode.get("items")); PaginationInfo pagination = parsePaginationInfo(productsNode.get("page_info")); int totalCount = productsNode.get("total_count").asInt(); return ProductResponse.builder() .success(true) .products(products) .pagination(pagination) .totalCount(totalCount) .build(); } catch (Exception e) { throw new MagentoException("Failed to parse products response", e); } } private ProductDetailResponse parseProductDetailResponse(JsonNode data) { try { JsonNode productsNode = data.get("products"); JsonNode itemsNode = productsNode.get("items"); if (itemsNode.isArray() && itemsNode.size() > 0) { Product product = parseProductDetail(itemsNode.get(0)); return ProductDetailResponse.builder() .success(true) .product(product) .build(); } else { return ProductDetailResponse.builder() .success(false) .errors(List.of("Product not found")) .build(); } } catch (Exception e) { throw new MagentoException("Failed to parse product detail response", e); } } private CategoryResponse parseCategoriesResponse(JsonNode data) { try { JsonNode categoryListNode = data.get("categoryList"); List<Category> categories = parseCategories(categoryListNode); return CategoryResponse.builder() .success(true) .categories(categories) .build(); } catch (Exception e) { throw new MagentoException("Failed to parse categories response", e); } } private SearchResponse parseSearchResponse(JsonNode data, SearchCriteria criteria) { try { JsonNode productsNode = data.get("products"); List<Product> products = parseProductItems(productsNode.get("items")); PaginationInfo pagination = parsePaginationInfo(productsNode.get("page_info")); int totalCount = productsNode.get("total_count").asInt(); List<Aggregation> aggregations = parseAggregations(productsNode.get("aggregations")); return SearchResponse.builder() .success(true) .products(products) .pagination(pagination) .totalCount(totalCount) .aggregations(aggregations) .searchQuery(criteria.getSearch()) .build(); } catch (Exception e) { throw new MagentoException("Failed to parse search response", e); } } private List<Product> parseProductItems(JsonNode itemsNode) { List<Product> products = new ArrayList<>(); if (itemsNode.isArray()) { for (JsonNode itemNode : itemsNode) { products.add(parseProduct(itemNode)); } } return products; } private Product parseProduct(JsonNode productNode) { return Product.builder() .id(productNode.get("id").asText()) .sku(productNode.get("sku").asText()) .name(productNode.get("name").asText()) .urlKey(productNode.has("url_key") ? productNode.get("url_key").asText() : null) .image(parseImage(productNode.get("image"))) .priceRange(parsePriceRange(productNode.get("price_range"))) .stockStatus(productNode.get("stock_status").asText()) .build(); } private Product parseProductDetail(JsonNode productNode) { Product.ProductBuilder builder = Product.builder() .id(productNode.get("id").asText()) .sku(productNode.get("sku").asText()) .name(productNode.get("name").asText()) .urlKey(productNode.has("url_key") ? productNode.get("url_key").asText() : null) .image(parseImage(productNode.get("image"))) .priceRange(parsePriceRange(productNode.get("price_range"))) .stockStatus(productNode.get("stock_status").asText()); if (productNode.has("description")) { builder.description(parseRichText(productNode.get("description"))); } if (productNode.has("short_description")) { builder.shortDescription(parseRichText(productNode.get("short_description"))); } if (productNode.has("media_gallery")) { builder.mediaGallery(parseMediaGallery(productNode.get("media_gallery"))); } // Parse configurable product options if (productNode.has("configurable_options")) { builder.configurableOptions(parseConfigurableOptions(productNode.get("configurable_options"))); } if (productNode.has("variants")) { builder.variants(parseVariants(productNode.get("variants"))); } return builder.build(); } private List<Category> parseCategories(JsonNode categoryListNode) { List<Category> categories = new ArrayList<>(); if (categoryListNode.isArray()) { for (JsonNode categoryNode : categoryListNode) { categories.add(parseCategory(categoryNode)); } } return categories; } private Category parseCategory(JsonNode categoryNode) { Category.CategoryBuilder builder = Category.builder() .id(categoryNode.get("id").asText()) .uid(categoryNode.get("uid").asText()) .name(categoryNode.get("name").asText()) .urlKey(categoryNode.get("url_key").asText()) .urlPath(categoryNode.get("url_path").asText()); if (categoryNode.has("description")) { builder.description(categoryNode.get("description").asText()); } if (categoryNode.has("image")) { builder.image(categoryNode.get("image").asText()); } if (categoryNode.has("product_count")) { builder.productCount(categoryNode.get("product_count").asInt()); } if (categoryNode.has("children")) { builder.children(parseCategories(categoryNode.get("children"))); } return builder.build(); } private List<Aggregation> parseAggregations(JsonNode aggregationsNode) { List<Aggregation> aggregations = new ArrayList<>(); if (aggregationsNode != null && aggregationsNode.isArray()) { for (JsonNode aggNode : aggregationsNode) { aggregations.add(parseAggregation(aggNode)); } } return aggregations; } private Aggregation parseAggregation(JsonNode aggNode) { List<Aggregation.Option> options = new ArrayList<>(); if (aggNode.has("options") && aggNode.get("options").isArray()) { for (JsonNode optionNode : aggNode.get("options")) { options.add(Aggregation.Option.builder() .label(optionNode.get("label").asText()) .value(optionNode.get("value").asText()) .count(optionNode.get("count").asInt()) .build()); } } return Aggregation.builder() .attributeCode(aggNode.get("attribute_code").asText()) .label(aggNode.get("label").asText()) .count(aggNode.has("count") ? aggNode.get("count").asInt() : 0) .options(options) .build(); } private Image parseImage(JsonNode imageNode) { if (imageNode == null || imageNode.isNull()) { return null; } return Image.builder() .url(imageNode.get("url").asText()) .label(imageNode.has("label") ? imageNode.get("label").asText() : null) .build(); } private PriceRange parsePriceRange(JsonNode priceRangeNode) { JsonNode minPriceNode = priceRangeNode.get("minimum_price"); JsonNode regularPriceNode = minPriceNode.get("regular_price"); JsonNode finalPriceNode = minPriceNode.get("final_price"); PriceRange.PriceRangeBuilder builder = PriceRange.builder() .minimumPrice(Price.builder() .regularPrice(Money.builder() .value(regularPriceNode.get("value").asDouble()) .currency(regularPriceNode.get("currency").asText()) .build()) .finalPrice(Money.builder() .value(finalPriceNode.get("value").asDouble()) .currency(finalPriceNode.get("currency").asText()) .build()) .build()); if (minPriceNode.has("discount")) { JsonNode discountNode = minPriceNode.get("discount"); builder.minimumPrice().discount(Discount.builder() .amountOff(discountNode.get("amount_off").asDouble()) .percentOff(discountNode.get("percent_off").asDouble()) .build()); } return builder.build(); } private RichText parseRichText(JsonNode richTextNode) { return RichText.builder() .html(richTextNode.get("html").asText()) .build(); } private List<MediaGalleryItem> parseMediaGallery(JsonNode mediaGalleryNode) { List<MediaGalleryItem> gallery = new ArrayList<>(); if (mediaGalleryNode.isArray()) { for (JsonNode itemNode : mediaGalleryNode) { gallery.add(MediaGalleryItem.builder() .url(itemNode.get("url").asText()) .label(itemNode.has("label") ? itemNode.get("label").asText() : null) .position(itemNode.has("position") ? itemNode.get("position").asInt() : 0) .build()); } } return gallery; } private List<ConfigurableOption> parseConfigurableOptions(JsonNode optionsNode) { List<ConfigurableOption> options = new ArrayList<>(); if (optionsNode.isArray()) { for (JsonNode optionNode : optionsNode) { options.add(parseConfigurableOption(optionNode)); } } return options; } private ConfigurableOption parseConfigurableOption(JsonNode optionNode) { List<ConfigurableOption.Value> values = new ArrayList<>(); if (optionNode.has("values") && optionNode.get("values").isArray()) { for (JsonNode valueNode : optionNode.get("values")) { values.add(parseConfigurableOptionValue(valueNode)); } } return ConfigurableOption.builder() .attributeCode(optionNode.get("attribute_code").asText()) .attributeUid(optionNode.get("attribute_uid").asText()) .label(optionNode.get("label").asText()) .values(values