Skip to content

Commit e57c6b4

Browse files
committed
FINERACT-2380: move retrofit client based test to feign
1 parent 47e8674 commit e57c6b4

File tree

77 files changed

+4625
-4491
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+4625
-4491
lines changed

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/FineractFeignClient.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.apache.fineract.client.feign.services.EntityFieldConfigurationApi;
6262
import org.apache.fineract.client.feign.services.ExternalAssetOwnerLoanProductAttributesApi;
6363
import org.apache.fineract.client.feign.services.ExternalAssetOwnersApi;
64+
import org.apache.fineract.client.feign.services.ExternalAssetOwnersApiExtension;
6465
import org.apache.fineract.client.feign.services.ExternalEventConfigurationApi;
6566
import org.apache.fineract.client.feign.services.ExternalServicesApi;
6667
import org.apache.fineract.client.feign.services.FetchAuthenticatedUserDetailsApi;
@@ -95,10 +96,13 @@
9596
import org.apache.fineract.client.feign.services.LoanCollateralApi;
9697
import org.apache.fineract.client.feign.services.LoanCollateralManagementApi;
9798
import org.apache.fineract.client.feign.services.LoanDisbursementDetailsApi;
99+
import org.apache.fineract.client.feign.services.LoanDisbursementDetailsApiExtension;
98100
import org.apache.fineract.client.feign.services.LoanInterestPauseApi;
99101
import org.apache.fineract.client.feign.services.LoanProductsApi;
102+
import org.apache.fineract.client.feign.services.LoanProductsApiExtension;
100103
import org.apache.fineract.client.feign.services.LoanReschedulingApi;
101104
import org.apache.fineract.client.feign.services.LoanTransactionsApi;
105+
import org.apache.fineract.client.feign.services.LoanTransactionsApiExtension;
102106
import org.apache.fineract.client.feign.services.LoansApi;
103107
import org.apache.fineract.client.feign.services.LoansPointInTimeApi;
104108
import org.apache.fineract.client.feign.services.MakerCheckerOr4EyeFunctionalityApi;
@@ -392,6 +396,10 @@ public ExternalAssetOwnersApi externalAssetOwners() {
392396
return create(ExternalAssetOwnersApi.class);
393397
}
394398

399+
public ExternalAssetOwnersApiExtension externalAssetOwnersExtension() {
400+
return create(ExternalAssetOwnersApiExtension.class);
401+
}
402+
395403
public ExternalEventConfigurationApi externalEventConfiguration() {
396404
return create(ExternalEventConfigurationApi.class);
397405
}
@@ -528,6 +536,10 @@ public LoanDisbursementDetailsApi loanDisbursementDetails() {
528536
return create(LoanDisbursementDetailsApi.class);
529537
}
530538

539+
public LoanDisbursementDetailsApiExtension loanDisbursementDetailsExtension() {
540+
return create(LoanDisbursementDetailsApiExtension.class);
541+
}
542+
531543
public LoanInterestPauseApi loanInterestPause() {
532544
return create(LoanInterestPauseApi.class);
533545
}
@@ -536,6 +548,10 @@ public LoanProductsApi loanProducts() {
536548
return create(LoanProductsApi.class);
537549
}
538550

551+
public LoanProductsApiExtension loanProductsExtension() {
552+
return create(LoanProductsApiExtension.class);
553+
}
554+
539555
public LoanReschedulingApi loanRescheduling() {
540556
return create(LoanReschedulingApi.class);
541557
}
@@ -544,6 +560,10 @@ public LoanTransactionsApi loanTransactions() {
544560
return create(LoanTransactionsApi.class);
545561
}
546562

563+
public LoanTransactionsApiExtension loanTransactionsExtension() {
564+
return create(LoanTransactionsApiExtension.class);
565+
}
566+
547567
public LoansApi loans() {
548568
return create(LoansApi.class);
549569
}

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/FineractFeignClientConfig.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import javax.net.ssl.SSLContext;
3333
import javax.net.ssl.TrustManager;
3434
import javax.net.ssl.X509TrustManager;
35+
import org.apache.fineract.client.feign.support.HeaderCapturingDecoder;
3536
import org.apache.hc.client5.http.config.RequestConfig;
3637
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
3738
import org.apache.hc.client5.http.impl.classic.HttpClients;
@@ -95,7 +96,8 @@ public <T> T createClient(Class<T> apiType) {
9596
Encoder multipartEncoder = new FineractMultipartEncoder(jacksonEncoder);
9697

9798
return Feign.builder().client(getOrCreateHttpClient()).encoder(multipartEncoder)
98-
.decoder(new JacksonDecoder(ObjectMapperFactory.getShared())).errorDecoder(new FineractErrorDecoder())
99+
.decoder(new HeaderCapturingDecoder(new JacksonDecoder(ObjectMapperFactory.getShared())))
100+
.errorDecoder(new FineractErrorDecoder())
99101
.options(new Request.Options(connectTimeout, TimeUnit.MILLISECONDS, readTimeout, TimeUnit.MILLISECONDS, true))
100102
.retryer(Retryer.NEVER_RETRY).requestInterceptor(new BasicAuthRequestInterceptor(username, password))
101103
.requestInterceptor(new TenantIdRequestInterceptor(tenantId)).logger(new Slf4jLogger(apiType))
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.client.feign.services;
20+
21+
import feign.Headers;
22+
import feign.Param;
23+
import feign.QueryMap;
24+
import feign.RequestLine;
25+
import java.util.Map;
26+
import org.apache.fineract.client.models.ExternalAssetOwnerRequest;
27+
import org.apache.fineract.client.models.PostInitiateTransferResponse;
28+
29+
public interface ExternalAssetOwnersApiExtension {
30+
31+
@RequestLine("POST /v1/external-asset-owners/transfers/{id}")
32+
@Headers("Content-Type: application/json")
33+
PostInitiateTransferResponse transferRequestWithIdWithBody(@Param("id") Long id, ExternalAssetOwnerRequest body,
34+
@QueryMap Map<String, Object> queryParams);
35+
36+
@RequestLine("POST /v1/external-asset-owners/transfers/external-id/{externalId}")
37+
@Headers("Content-Type: application/json")
38+
PostInitiateTransferResponse transferRequestWithId1WithBody(@Param("externalId") String externalId, ExternalAssetOwnerRequest body,
39+
@QueryMap Map<String, Object> queryParams);
40+
}

fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanProductsCustomApi.java renamed to fineract-client-feign/src/main/java/org/apache/fineract/client/feign/services/LoanDisbursementDetailsApiExtension.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
package org.apache.fineract.test.stepdef.loan;
19+
package org.apache.fineract.client.feign.services;
2020

21-
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
22-
import retrofit2.Call;
23-
import retrofit2.http.GET;
21+
import feign.Param;
22+
import feign.RequestLine;
23+
import org.apache.fineract.client.models.PostAddAndDeleteDisbursementDetailRequest;
2424

25-
public interface LoanProductsCustomApi {
25+
public interface LoanDisbursementDetailsApiExtension {
26+
27+
@RequestLine("PUT /v1/loans/{loanId}/disbursements/editDisbursements")
28+
PostAddAndDeleteDisbursementDetailRequest addAndDeleteDisbursementDetail(@Param("loanId") Long loanId,
29+
PostAddAndDeleteDisbursementDetailRequest postAddAndDeleteDisbursementDetailRequest);
2630

27-
@GET("v1/loanproducts/{productId}")
28-
Call<GetLoanProductsProductIdResponse> retrieveLoanProductDetails(@retrofit2.http.Path("productId") Long productId,
29-
@retrofit2.http.Query("template") String isTemplate);
3031
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.client.feign.services;
20+
21+
import feign.Param;
22+
import feign.QueryMap;
23+
import feign.RequestLine;
24+
import java.util.Map;
25+
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
26+
27+
public interface LoanProductsApiExtension {
28+
29+
/**
30+
* Retrieve Loan Product Details with query parameters
31+
*
32+
* @param productId
33+
* Loan Product ID
34+
* @param queryParams
35+
* Query parameters (e.g., template=true)
36+
* @return GetLoanProductsProductIdResponse
37+
*/
38+
@RequestLine("GET /v1/loanproducts/{productId}")
39+
GetLoanProductsProductIdResponse retrieveLoanProductDetails(@Param("productId") Long productId,
40+
@QueryMap Map<String, Object> queryParams);
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.client.feign.services;
20+
21+
import feign.HeaderMap;
22+
import feign.Param;
23+
import feign.QueryMap;
24+
import feign.RequestLine;
25+
import java.util.Map;
26+
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
27+
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
28+
29+
public interface LoanTransactionsApiExtension {
30+
31+
@RequestLine("POST /v1/loans/{loanId}/transactions")
32+
PostLoansLoanIdTransactionsResponse executeLoanTransaction(@Param("loanId") Long loanId,
33+
PostLoansLoanIdTransactionsRequest postLoansLoanIdTransactionsRequest, @QueryMap Map<String, Object> queryParams,
34+
@HeaderMap Map<String, String> headers);
35+
36+
@RequestLine("POST /v1/loans/external-id/{loanExternalId}/transactions")
37+
PostLoansLoanIdTransactionsResponse executeLoanTransaction1(@Param("loanExternalId") String loanExternalId,
38+
PostLoansLoanIdTransactionsRequest postLoansLoanIdTransactionsRequest, @QueryMap Map<String, Object> queryParams,
39+
@HeaderMap Map<String, String> headers);
40+
41+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.client.feign.support;
20+
21+
import feign.Response;
22+
import java.util.Collection;
23+
import java.util.Collections;
24+
import java.util.Map;
25+
26+
/**
27+
* Thread-local holder for the last Feign response headers. This is primarily used by E2E tests that need to assert on
28+
* HTTP headers when using Feign clients that otherwise only expose the deserialized body.
29+
*/
30+
public final class FeignResponseHeaderHolder {
31+
32+
private static final ThreadLocal<Map<String, Collection<String>>> LAST_HEADERS = new ThreadLocal<>();
33+
34+
private FeignResponseHeaderHolder() {}
35+
36+
public static void store(Response response) {
37+
LAST_HEADERS.set(response != null ? response.headers() : null);
38+
}
39+
40+
public static Map<String, Collection<String>> getHeaders() {
41+
Map<String, Collection<String>> headers = LAST_HEADERS.get();
42+
return headers == null ? Collections.emptyMap() : headers;
43+
}
44+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.client.feign.support;
20+
21+
import feign.Response;
22+
import feign.codec.Decoder;
23+
import java.io.IOException;
24+
import java.lang.reflect.Type;
25+
26+
/**
27+
* Decorator that captures response headers into a thread-local holder before delegating decoding.
28+
*/
29+
public final class HeaderCapturingDecoder implements Decoder {
30+
31+
private final Decoder delegate;
32+
33+
public HeaderCapturingDecoder(Decoder delegate) {
34+
this.delegate = delegate;
35+
}
36+
37+
@Override
38+
public Object decode(Response response, Type type) throws IOException {
39+
FeignResponseHeaderHolder.store(response);
40+
return delegate.decode(response, type);
41+
}
42+
}

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/util/CallFailedRuntimeException.java

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@
1818
*/
1919
package org.apache.fineract.client.feign.util;
2020

21-
import com.fasterxml.jackson.databind.JsonNode;
22-
import com.fasterxml.jackson.databind.ObjectMapper;
23-
import feign.FeignException;
24-
import java.io.IOException;
25-
import java.nio.charset.StandardCharsets;
2621
import lombok.Getter;
2722
import lombok.extern.slf4j.Slf4j;
23+
import org.apache.fineract.client.feign.FeignException;
2824

2925
/**
3026
* Exception thrown by {@link FeignCalls} utility when Feign calls fail.
@@ -49,7 +45,7 @@ private static String createMessage(FeignException e) {
4945
sb.append(", request=").append(e.request().url());
5046
}
5147

52-
String contentString = e.contentUTF8();
48+
String contentString = e.responseBodyAsString();
5349
if (contentString != null && !contentString.isEmpty()) {
5450
sb.append(", errorBody=").append(contentString);
5551
}
@@ -58,34 +54,9 @@ private static String createMessage(FeignException e) {
5854
}
5955

6056
private static String extractDeveloperMessage(FeignException e) {
61-
try {
62-
byte[] content = e.content();
63-
if (content == null || content.length == 0) {
64-
return e.getMessage();
65-
}
66-
67-
String contentString = new String(content, StandardCharsets.UTF_8);
68-
ObjectMapper mapper = new ObjectMapper();
69-
JsonNode root = mapper.readTree(contentString);
70-
71-
if (root.has("developerMessage")) {
72-
return root.get("developerMessage").asText();
73-
}
74-
75-
if (root.has("errors")) {
76-
JsonNode errors = root.get("errors");
77-
if (errors.isArray() && errors.size() > 0) {
78-
JsonNode firstError = errors.get(0);
79-
if (firstError.has("developerMessage")) {
80-
return firstError.get("developerMessage").asText();
81-
}
82-
}
83-
}
84-
85-
return contentString;
86-
} catch (IOException ex) {
87-
log.warn("Failed to extract developer message from error response", ex);
88-
return e.getMessage();
57+
if (e.getDeveloperMessage() != null) {
58+
return e.getDeveloperMessage();
8959
}
60+
return e.getMessage();
9061
}
9162
}

0 commit comments

Comments
 (0)