2323import org .slf4j .Logger ;
2424import org .slf4j .LoggerFactory ;
2525
26- import com .fasterxml .jackson .annotation .JsonInclude ;
27- import com .fasterxml .jackson .databind .AnnotationIntrospector ;
28- import com .fasterxml .jackson .databind .DeserializationFeature ;
29- import com .fasterxml .jackson .databind .MapperFeature ;
3026import com .fasterxml .jackson .databind .ObjectMapper ;
31- import com .fasterxml .jackson .databind .introspect .JacksonAnnotationIntrospector ;
32- import com .fasterxml .jackson .databind .type .TypeFactory ;
3327import com .fasterxml .jackson .jaxrs .json .JacksonJaxbJsonProvider ;
34- import com .fasterxml .jackson .module .jaxb .JaxbAnnotationIntrospector ;
3528import com .github .rholder .retry .Attempt ;
3629import com .github .rholder .retry .RetryException ;
3730import com .github .rholder .retry .RetryListener ;
4134import com .github .rholder .retry .WaitStrategies ;
4235import com .shopify .exceptions .ShopifyClientException ;
4336import com .shopify .exceptions .ShopifyErrorResponseException ;
37+ import com .shopify .mappers .ShopifySdkObjectMapper ;
4438import com .shopify .model .Count ;
4539import com .shopify .model .Image ;
4640import com .shopify .model .ImageAltTextCreationRequest ;
5044import com .shopify .model .Shop ;
5145import com .shopify .model .ShopifyAccessTokenRoot ;
5246import com .shopify .model .ShopifyCancelOrderRequest ;
47+ import com .shopify .model .ShopifyCustomer ;
48+ import com .shopify .model .ShopifyCustomerRoot ;
49+ import com .shopify .model .ShopifyCustomerUpdateRequest ;
50+ import com .shopify .model .ShopifyCustomerUpdateRoot ;
5351import com .shopify .model .ShopifyFulfillment ;
5452import com .shopify .model .ShopifyFulfillmentCreationRequest ;
5553import com .shopify .model .ShopifyFulfillmentRoot ;
6765import com .shopify .model .ShopifyOrderRisk ;
6866import com .shopify .model .ShopifyOrderRisksRoot ;
6967import com .shopify .model .ShopifyOrderRoot ;
68+ import com .shopify .model .ShopifyOrderShippingAddressUpdateRequest ;
69+ import com .shopify .model .ShopifyOrderUpdateRoot ;
7070import com .shopify .model .ShopifyOrdersRoot ;
7171import com .shopify .model .ShopifyProduct ;
7272import com .shopify .model .ShopifyProductCreationRequest ;
@@ -171,9 +171,12 @@ public class ShopifySdk {
171171 private long minimumRequestRetryRandomDelayMilliseconds ;
172172 private long maximumRequestRetryRandomDelayMilliseconds ;
173173 private long maximumRequestRetryTimeoutMilliseconds ;
174+ private final ShopifySdkRetryListener shopifySdkRetryListener = new ShopifySdkRetryListener ();
174175
175176 private static final Client CLIENT = buildClient ();
176177
178+ private static final String CUSTOMERS = "customers" ;
179+
177180 public static interface OptionalsStep {
178181
179182 /**
@@ -623,6 +626,25 @@ public ShopifyOrder createOrder(final ShopifyOrderCreationRequest shopifyOrderCr
623626 return shopifyOrderRootResponse .getOrder ();
624627 }
625628
629+ public ShopifyOrder updateOrderShippingAddress (
630+ final ShopifyOrderShippingAddressUpdateRequest shopifyOrderUpdateRequest ) {
631+ final ShopifyOrderUpdateRoot shopifyOrderRoot = new ShopifyOrderUpdateRoot ();
632+ shopifyOrderRoot .setOrder (shopifyOrderUpdateRequest );
633+ final Response response = put (getWebTarget ().path (ORDERS ).path (shopifyOrderUpdateRequest .getId ()),
634+ shopifyOrderRoot );
635+ final ShopifyOrderRoot shopifyOrderRootResponse = response .readEntity (ShopifyOrderRoot .class );
636+ return shopifyOrderRootResponse .getOrder ();
637+ }
638+
639+ public ShopifyCustomer updateCustomer (final ShopifyCustomerUpdateRequest shopifyCustomerUpdateRequest ) {
640+ final ShopifyCustomerUpdateRoot shopifyCustomerUpdateRequestRoot = new ShopifyCustomerUpdateRoot ();
641+ shopifyCustomerUpdateRequestRoot .setCustomer (shopifyCustomerUpdateRequest );
642+ final Response response = put (getWebTarget ().path (CUSTOMERS ).path (shopifyCustomerUpdateRequest .getId ()),
643+ shopifyCustomerUpdateRequestRoot );
644+ final ShopifyCustomerRoot shopifyCustomerRootResponse = response .readEntity (ShopifyCustomerRoot .class );
645+ return shopifyCustomerRootResponse .getCustomer ();
646+ }
647+
626648 public ShopifyFulfillment cancelFulfillment (final String orderId , final String fulfillmentId ) {
627649 final Response response = post (
628650 getWebTarget ().path (ORDERS ).path (orderId ).path (FULFILLMENTS ).path (fulfillmentId ).path (CANCEL ),
@@ -811,6 +833,7 @@ private <T> Response put(final WebTarget webTarget, final T object) {
811833 }
812834
813835 private Response handleResponse (final Response response , final Status ... expectedStatus ) {
836+
814837 if ((response .getHeaders () != null ) && response .getHeaders ().containsKey (DEPRECATED_REASON_HEADER )) {
815838 LOGGER .error (DEPRECATED_SHOPIFY_CALL_ERROR_MESSAGE , response .getLocation (), response .getStatus (),
816839 response .getStringHeaders ());
@@ -820,7 +843,8 @@ private Response handleResponse(final Response response, final Status... expecte
820843 if (expectedStatusCodes .contains (response .getStatus ())) {
821844 return response ;
822845 }
823- throw new ShopifyErrorResponseException (response );
846+
847+ throw new ShopifyErrorResponseException (response , shopifySdkRetryListener .getResponseBody ());
824848 }
825849
826850 private List <Integer > getExpectedStatusCodes (final Status ... expectedStatus ) {
@@ -842,7 +866,7 @@ private Retryer<Response> buildResponseRetyer() {
842866 TimeUnit .MILLISECONDS , maximumRequestRetryRandomDelayMilliseconds , TimeUnit .MILLISECONDS ))
843867 .withStopStrategy (
844868 StopStrategies .stopAfterDelay (maximumRequestRetryTimeoutMilliseconds , TimeUnit .MILLISECONDS ))
845- .withRetryListener (new ShopifySdkRetryListener () ).build ();
869+ .withRetryListener (shopifySdkRetryListener ).build ();
846870 }
847871
848872 private static boolean shouldRetryResponse (final Response response ) {
@@ -859,9 +883,10 @@ private static boolean isServerError(final Response response) {
859883 }
860884
861885 private static boolean hasNotBeenSaved (final Response response ) {
886+ response .bufferEntity ();
862887 if ((UNPROCESSABLE_ENTITY_STATUS_CODE == response .getStatus ()) && response .hasEntity ()) {
863- response .bufferEntity ();
864888 final String shopifyErrorResponse = response .readEntity (String .class );
889+ LOGGER .debug (shopifyErrorResponse );
865890 return shopifyErrorResponse .contains (COULD_NOT_BE_SAVED_SHOPIFY_ERROR_MESSAGE );
866891 }
867892 return false ;
@@ -909,43 +934,38 @@ private WebTarget getWebTarget() {
909934 }
910935
911936 private static Client buildClient () {
912- final ObjectMapper mapper = buildMapper ();
937+ final ObjectMapper mapper = ShopifySdkObjectMapper . buildMapper ();
913938 final JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider ();
914939 provider .setMapper (mapper );
915940
916941 return ClientBuilder .newClient ().register (JacksonFeature .class ).register (provider );
917942 }
918943
919- static ObjectMapper buildMapper () {
920- final ObjectMapper mapper = new ObjectMapper ();
921- mapper .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
922- mapper .setSerializationInclusion (JsonInclude .Include .NON_NULL );
923-
924- final AnnotationIntrospector pair = AnnotationIntrospector .pair (
925- new JaxbAnnotationIntrospector (TypeFactory .defaultInstance ()), new JacksonAnnotationIntrospector ());
926- mapper .setAnnotationIntrospector (pair );
927-
928- mapper .enable (MapperFeature .USE_ANNOTATIONS );
929- return mapper ;
930- }
931-
932- private static class ShopifySdkRetryListener implements RetryListener {
944+ public class ShopifySdkRetryListener implements RetryListener {
933945
934- private static final String RETRY_EXCEPTION_ATTEMPT_MESSAGE = "An exception occurred while making an API call to shopify on attempt number {} and {} seconds since first attempt with exception {} " ;
946+ private static final String RETRY_EXCEPTION_ATTEMPT_MESSAGE = "An exception occurred while making an API call to shopify: {} on attempt number {} and {} seconds since first attempt" ;
935947 private static final String RETRY_INVALID_RESPONSE_ATTEMPT_MESSAGE = "Waited {} seconds since first retry attempt. This is attempt {}. Please review the following failed request information.\n Request Location of {}\n Response Status Code of {}\n Response Headers of:\n {}\n Response Body of:\n {}" ;
936948
949+ private String responseBody ;
950+
937951 @ Override
938952 public <V > void onRetry (final Attempt <V > attempt ) {
939- if (LOGGER . isWarnEnabled () && attempt .hasResult ()) {
953+ if (attempt .hasResult ()) {
940954 final Response response = (Response ) attempt .getResult ();
955+
941956 response .bufferEntity ();
942- if (shouldRetryResponse (response ) && !hasExceededRateLimit (response )) {
957+ this .responseBody = response .readEntity (String .class );
958+
959+ if (LOGGER .isWarnEnabled () && !hasExceededRateLimit (response ) && shouldRetryResponse (response )) {
960+
943961 final long delaySinceFirstAttemptInSeconds = convertMillisecondsToSeconds (
944962 attempt .getDelaySinceFirstAttempt ());
945963 LOGGER .warn (RETRY_INVALID_RESPONSE_ATTEMPT_MESSAGE , delaySinceFirstAttemptInSeconds ,
946964 attempt .getAttemptNumber (), response .getLocation (), response .getStatus (),
947- response .getStringHeaders (), response .readEntity (String .class ));
965+ response .getStringHeaders (), this .responseBody );
966+
948967 }
968+
949969 } else if (LOGGER .isWarnEnabled () && attempt .hasException ()) {
950970
951971 final long delaySinceFirstAttemptInSeconds = convertMillisecondsToSeconds (
@@ -955,9 +975,14 @@ public <V> void onRetry(final Attempt<V> attempt) {
955975 }
956976 }
957977
978+ public String getResponseBody () {
979+ return responseBody ;
980+ }
981+
958982 private long convertMillisecondsToSeconds (final long milliiseconds ) {
959983 return TimeUnit .SECONDS .convert (milliiseconds , TimeUnit .MILLISECONDS );
960984 }
985+
961986 }
962987
963988}
0 commit comments