亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Table of Contents
Original implementation and its limitations
Functional programming solutions
1. Define multi-parameter functional interface
2. Unified paging interface and parameter binding
3. Adapt to universal paging calls
4. Reconstruct paging data extraction logic (iterative implementation)
Advantages and Considerations
Advantages
Things to note
Summarize
Home Java javaTutorial Using functional programming to implement generalized Feign paging API calls and parameter binding

Using functional programming to implement generalized Feign paging API calls and parameter binding

Oct 15, 2025 pm 12:48 PM

Using functional programming to implement generalized Feign paging API calls and parameter binding

This article explores how to elegantly generalize Feign paging API calls with different numbers of parameters using functional programming methods. By introducing the parameter binding mechanism and the unified `PagingApi` interface, we can avoid defining a large number of repeated adapter classes for each API, implement more concise and descriptive code, effectively extract paging logic, and improve code reusability and maintainability.

In modern microservice architecture, Feign as a declarative HTTP client is widely used for calls between services. However, when dealing with a large number of Feign APIs with paging capabilities and different parameter structures, it is a common challenge to design a universal and flexible calling mechanism to avoid duplication of code and cumbersome adapter definitions. This article will delve into how to use the functional programming features of Java 8 to build a highly abstract and reusable Feign paging API calling framework.

Original implementation and its limitations

The initial implementation tried to adapt to the Feign API with different number of parameters by defining specific interfaces and wrapper classes. For example, for a paging API with only one extra parameter, you might need to define the SingleParamPagingApi interface and the SingleParamPageableCall class.

The following is the key code structure of the original implementation:

 //Auxiliary class definition@Builder
public static class BaseFeignResult<t> {
    private final ResponseEntity<ivdpagedresponseof>> resp;
    private final RuntimeException excp;
}

//Interface for single-parameter paging API public interface SingleParamPagingApi<t> {
    ResponseEntity<ivdpagedresponseof>> callFeignApi(String arg, int page, int size) throws RuntimeException;
}

// Unified paging call interface public interface PagedCall<t> {
    BaseFeignResult<t> call(int p, int s);
}

// Adapter implementation of single-parameter paging API public static class SingleParamPageableCall<t> implements PagedCall<t> {
    SingleParamPagingApi<t> fun;
    String param;

    public SingleParamPageableCall(SingleParamPagingApi<t> fun, String param) {
        this.fun = fun;
        this.param = param;
    }

    @Override
    public BaseFeignResult<t> call(int p, int s) {
        BaseFeignResult.BaseFeignResultBuilder<t> builder = BaseFeignResult.builder();
        try {
            builder.resp(fun.callFeignApi(param, p, s));
        } catch (RuntimeException e) {
            builder.excp(e);
        }
        return builder.build();
    }
}

//Paging data extraction logic (recursive implementation)
public class FeignDrainer {
    public <t> List<basefeignresult>> drainFeignPageableCall(PagedCall<t> feignCall) {
        BaseFeignResult<t> firstPage = feignCall.call(0, 10);
        List<basefeignresult>> baseFeignResults = new ArrayList();
        baseFeignResults.add(firstPage);
        return drainFeignPageableCall(feignCall, firstPage, baseFeignResults, 1);
    }

    private <t> List<basefeignresult>> drainFeignPageableCall(
            PagedCall<t> feignCall,
            BaseFeignResult<t> dataPage,
            List<basefeignresult>> acc,
            int page
    ) {
        // Assume that the size of each page is 10, use the remainder to determine whether it is the last page if (dataPage.resp != null && dataPage.resp.getBody().getData().size() % 10 > 0) {
            return acc;
        }
        if (dataPage.resp != null && dataPage.resp.getBody().getData().isEmpty()) { // Consider the case where the last page data is empty return acc;
        }

        BaseFeignResult<t> res = feignCall.call(page, 10);
        acc.add(res);

        // Recursive call return drainFeignPageableCall(feignCall, res, acc, page);
    }
}</t></basefeignresult></t></t></basefeignresult></t></basefeignresult></t></t></basefeignresult></t></t></t></t></t></t></t></t></t></ivdpagedresponseof></t></ivdpagedresponseof></t>

The limitation of this method is that whenever you encounter a Feign API with a different number of parameters (for example, zero extra parameters, two extra parameters, etc.), you need to redefine the corresponding XParamPagingApi interface and XParamPageableCall class, resulting in a lot of boilerplate code and low code reusability. This is far from the goal of "descriptively implementing parameter mapping".

Functional programming solutions

In order to solve the above problems, we can introduce the idea of ??functional programming and use Java 8's lambda expressions and functional interfaces to dynamically bind the pre-parameters of Feign API, thereby realizing a highly versatile paging API calling mechanism.

The core idea is:

  1. Define a series of functional interfaces for different number of parameters to describe the original signature of Feign API.
  2. Create a unified PagingApi interface, which only receives page and size parameters.
  3. Provide a static factory method (of method) in the PagingApi interface, bind the pre-parameters of the specific Feign API through lambda expressions, and return a unified PagingApi instance.

1. Define multi-parameter functional interface

First, we define functional interfaces for different numbers of preparameters. These interfaces will be used to match the actual API method signatures in the Feign client.

 // Auxiliary class: Assume that IVDPagedResponseOf is the response body containing paging information public class IVDPagedResponseOf<t> {
    private List<t> data;
    // ...Other paging information, such as total number of pages, total number of records, etc. public List<t> getData() { return data; }
    public void setData(List<t> data) { this.data = data; }
}

// Paging API interface @FunctionalInterface for an additional parameter
public interface PagingApi1<t a0> {
    ResponseEntity<ivdpagedresponseof>> callFeignApi(A0 arg0, int page, int size) throws RuntimeException;
}

// Paging API interface @FunctionalInterface for two additional parameters
public interface PagingApi2<t a0 a1> {
    ResponseEntity<ivdpagedresponseof>> callFeignApi(A0 arg0, A1 arg1, int page, int size) throws RuntimeException;
}

// You can define interfaces with more parameters as needed, such as PagingApi0, PagingApi3, etc.</ivdpagedresponseof></t></ivdpagedresponseof></t></t></t></t></t>

2. Unified paging interface and parameter binding

Next, we define a unified PagingApi interface, which only cares about the page and size parameters. The most important thing is that we use the static of method to bind the multi-parameter PagingApiX instance to specific parameters and convert it into this unified PagingApi instance.

 @FunctionalInterface
public interface PagingApi<t> {
    ResponseEntity<ivdpagedresponseof>> callFeignApi(int page, int size) throws RuntimeException;

    // Static factory method: bind an additional parameter static <t a0> PagingApi<t> of(PagingApi1<t a0> api, A0 arg0) {
        return (p, s) -> api.callFeignApi(arg0, p, s);
    }

    // Static factory method: bind two additional parameters static <t a0 a1> PagingApi<t> of(PagingApi2<t a0 a1> api, A0 arg0, A1 arg1) {
        return (p, s) -> api.callFeignApi(arg0, arg1, p, s);
    }
    // You can continue to add more parameters to the of method}</t></t></t></t></t></t></ivdpagedresponseof></t>

Through the PagingApi.of method, we can bind the Feign client's specific method reference (such as ordersFeignClient::getOrdersBySampleIds) with its front parameters (such as "34596") at runtime to generate a PagingApi instance that only accepts page and size.

3. Adapt to universal paging calls

With the unified PagingApi interface, we can now create a general PageableCall class, which no longer needs to care about how many pre-parameters the original Feign API has, and only needs to receive a PagingApi instance.

 // Unified BaseFeignResult definition @Builder
public static class BaseFeignResult<t> {
    private final ResponseEntity<ivdpagedresponseof>> resp;
    private final RuntimeException excp;
    // Getter methods
    public ResponseEntity<ivdpagedresponseof>> getResp() { return resp; }
    public RuntimeException getExcp() { return excp; }
}

// Universal PageableCall adapter public static class PageableCall<t> implements PagedCall<t> {
    PagingApi<t> fun;

    public PageableCall(PagingApi<t> fun) {
        this.fun = fun;
    }

    @Override
    public BaseFeignResult<t> call(int p, int s) {
        BaseFeignResult.BaseFeignResultBuilder<t> builder = BaseFeignResult.builder();
        try {
            builder.resp(fun.callFeignApi(p, s));
        } catch (RuntimeException e) {
            builder.excp(e);
        }
        return builder.build();
    }
}</t></t></t></t></t></t></ivdpagedresponseof></ivdpagedresponseof></t>

4. Reconstruct paging data extraction logic (iterative implementation)

The original paged data extraction logic uses recursion, which may cause stack overflow when processing large amounts of paged data, and is not as readable as iteration. It is recommended to refactor this into an iterative implementation.

 public class FeignDrainer {
    private final int pageSize;

    public FeignDrainer(int pageSize) {
        this.pageSize = pageSize;
    }

    /**
     * Extract all paging data, using iterative method* @param feignCall unified paging calling interface* @param <t> data type* @return data list of all pages*/
    public <t> List<basefeignresult>> drainAllPages(PagedCall<t> feignCall) {
        List<basefeignresult>> allResults = new ArrayList();
        int page = 0;
        boolean hasMoreData = true;

        while (hasMoreData) {
            BaseFeignResult<t> currentPageResult = feignCall.call(page, pageSize);
            allResults.add(currentPageResult);

            if (currentPageResult.getResp() == null || currentPageResult.getExcp() != null) {
                // If the request fails or there is no response body, stop extracting hasMoreData = false;
            } else {
                List<t> data = currentPageResult.getResp().getBody().getData();
                // Determine whether it is the last page: If the amount of data returned is less than the requested page size, it means it is the last page // or the data is empty, it is also regarded as the last page if (data == null || data.size() <h3> Complete example and calling method</h3>
<p> Suppose we have a Feign client ordersFeignClient, which contains a method getOrdersBySampleIds:</p>
<pre class="brush:php;toolbar:false"> // Assume this is your Feign client interface public interface OrdersFeignClient {
    ResponseEntity<ivdpagedresponseof>> getOrdersBySampleIds(String sampleId, int page, int size);
    // Assume there are other paging APIs, such as:
    // ResponseEntity<ivdpagedresponseof>> getProductsByCategory(String category, String brand, int page, int size);
}

// Assume GetOrderInfoDto is the data structure of order information public class GetOrderInfoDto {
    private String orderId;
    // ...
}</ivdpagedresponseof></ivdpagedresponseof>

Now, we can call the general paging extraction logic like this:

 // Instantiate the Feign client (this is a simplification, it should actually be injected through Spring, etc.)
OrdersFeignClient ordersFeignClient = new OrdersFeignClient() {
    @Override
    public ResponseEntity<ivdpagedresponseof>> getOrdersBySampleIds(String sampleId, int page, int size) {
        // Simulate API call result List<getorderinfodto> data = new ArrayList();
        if (page == 0) {
            data.add(new GetOrderInfoDto() {{ setOrderId("order-1"); }});
            data.add(new GetOrderInfoDto() {{ setOrderId("order-2"); }});
        } else if (page == 1) {
            data.add(new GetOrderInfoDto() {{ setOrderId("order-3"); }});
        }
        IVDPagedResponseOf<getorderinfodto> responseOf = new IVDPagedResponseOf();
        responseOf.setData(data);
        return ResponseEntity.ok(responseOf);
    }
};

// Instantiate the paging extractor and specify the size of each page FeignDrainer feignDrainer = new FeignDrainer(2); // Assume that the size of each page is 2

// Calling method:
List<basefeignresult>> allOrders = feignDrainer.drainAllPages(
        new PageableCall(
                PagingApi.of(ordersFeignClient::getOrdersBySampleIds, "34596")
        )
);

System.out.println("Fetched " allOrders.size() " pages of orders.");
allOrders.forEach(result -> {
    if (result.getResp() != null && result.getResp().getBody() != null) {
        result.getResp().getBody().getData().forEach(order -> System.out.println("Order ID: " order.getOrderId()));
    }
});

// If there is another API, such as getProductsByCategory(String category, String brand, int page, int size)
// Assume that ProductInfo class exists // List<basefeignresult>> allProducts = feignDrainer.drainAllPages(
// new PageableCall(
// PagingApi.of(ordersFeignClient::getProductsByCategory, "Electronics", "Sony")
// )
// );</basefeignresult></basefeignresult></getorderinfodto></getorderinfodto></ivdpagedresponseof>

In this way, we only need to define the of method with different number of parameters in PagingApi to adapt to various Feign APIs. When calling, we use the method reference ordersFeignClient::getOrdersBySampleIds and specific parameter values, bind through PagingApi.of, generate a unified PagingApi instance, and then pass it to PageableCall and FeignDrainer.

Advantages and Considerations

Advantages

  1. Reduce boilerplate code: Avoid creating dedicated interface and adapter classes for each Feign API with different number of parameters.
  2. Improved readability: Through the PagingApi.of method, the parameter binding process is more intuitive and descriptive.
  3. Enhanced flexibility: Easily support Feign API with any number of pre-parameters by extending the PagingApiX interface and PagingApi.of method.
  4. Comply with the functional programming paradigm: Use lambda expressions and method references to make your code more concise and expressive.

Things to note

  1. Interface merging: To further simplify, PagingApi and PagedCall can actually be merged into one interface, and the exception handling logic of the call method is directly implemented in PagingApi. For example:

     @FunctionalInterface
    public interface UnifiedPagedApi<t> {
        BaseFeignResult<t> call(int p, int s);
    
        static <t a0> UnifiedPagedApi<t> of(PagingApi1<t a0> api, A0 arg0) {
            return (p, s) -> {
                BaseFeignResult.BaseFeignResultBuilder<t> builder = BaseFeignResult.builder();
                try {
                    builder.resp(api.callFeignApi(arg0, p, s));
                } catch (RuntimeException e) {
                    builder.excp(e);
                }
                return builder.build();
            };
        }
        // ...other of methods}
    // Then FeignDrainer uses UnifiedPagedApi directly
    // public <t> List<basefeignresult>> drainAllPages(UnifiedPagedApi<t> feignCall) { ... }</t></basefeignresult></t></t></t></t></t></t></t>
  2. Robustness of paging logic: The logic to determine the end of paging in the drainAllPages method needs to be adjusted based on the actual API response. For example, some APIs will return the total number of pages or total records, which is more accurate than just judging whether the current page data volume is less than pageSize.

  3. Exception handling: The design of BaseFeignResult effectively encapsulates normal responses and runtime exceptions, which is very useful for unified processing of API call results.

  4. Generics and type safety: When using PagingApiX and PagingApi, ensure that the generic parameter T is passed correctly to maintain type safety.

Summarize

By introducing the parameter binding mechanism of functional programming, we have successfully raised the universal calling of Feign paging API to a new level. This method not only significantly reduces boilerplate code and improves code reusability and maintainability, but also makes the API call logic clearer and more descriptive. This pattern provides an elegant and powerful solution in scenarios where you deal with a large number of paginated APIs with different parameter signatures.

The above is the detailed content of Using functional programming to implement generalized Feign paging API calls and parameter binding. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

ArtGPT

ArtGPT

AI image generator for creative art from text prompts.

Stock Market GPT

Stock Market GPT

AI powered investment research for smarter decisions

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

How to add a JAR file to the classpath in Java? How to add a JAR file to the classpath in Java? Sep 21, 2025 am 05:09 AM

Use the -cp parameter to add the JAR to the classpath, so that the JVM can load its internal classes and resources, such as java-cplibrary.jarcom.example.Main, which supports multiple JARs separated by semicolons or colons, and can also be configured through CLASSPATH environment variables or MANIFEST.MF.

How to create a file in Java How to create a file in Java Sep 21, 2025 am 03:54 AM

UseFile.createNewFile()tocreateafileonlyifitdoesn’texist,avoidingoverwriting;2.PreferFiles.createFile()fromNIO.2formodern,safefilecreationthatfailsifthefileexists;3.UseFileWriterorPrintWriterwhencreatingandimmediatelywritingcontent,withFileWriterover

Building Extensible Applications with the Java Service Provider Interface (SPI) Building Extensible Applications with the Java Service Provider Interface (SPI) Sep 21, 2025 am 03:50 AM

JavaSPI is a built-in service discovery mechanism in JDK, and implements interface-oriented dynamic expansion through ServiceLoader. 1. Define the service interface and create a file with the full name of the interface under META-INF/services/, and write the fully qualified name of the implementation class; 2. Use ServiceLoader.load() to load the implementation class, and the JVM will automatically read the configuration and instantiate it; 3. The interface contract should be clarified during design, support priority and conditional loading, and provide default implementation; 4. Application scenarios include multi-payment channel access and plug-in verification; 5. Pay attention to performance, classpath, exception isolation, thread safety and version compatibility; 6. In Java9, provide can be used in combination with module systems.

How to implement an interface in Java? How to implement an interface in Java? Sep 18, 2025 am 05:31 AM

Use the implements keyword to implement the interface. The class needs to provide specific implementations of all methods in the interface. It supports multiple interfaces and is separated by commas to ensure that the methods are public. The default and static methods after Java 8 do not need to be rewrite.

Understanding Java Generics and Wildcards Understanding Java Generics and Wildcards Sep 20, 2025 am 01:58 AM

Javagenericsprovidecompile-timetypesafetyandeliminatecastingbyallowingtypeparametersonclasses,interfaces,andmethods;wildcards(?,?extendsType,?superType)handleunknowntypeswithflexibility.1.UseunboundedwildcardwhentypeisirrelevantandonlyreadingasObject

A deep understanding of HTTP persistent connections: policies and practices for sending multiple requests on the same socket A deep understanding of HTTP persistent connections: policies and practices for sending multiple requests on the same socket Sep 21, 2025 pm 01:51 PM

This article explores in-depth the mechanism of sending multiple HTTP requests on the same TCP Socket, namely, HTTP persistent connection (Keep-Alive). The article clarifies the difference between HTTP/1.x and HTTP/2 protocols, emphasizes the importance of server-side support for persistent connections, and how to correctly handle Connection: close response headers. By analyzing common errors and providing best practices, we aim to help developers build efficient and robust HTTP clients.

Java Tutorial: How to Flatten a Nested ArrayList and Fill its Elements into an Array Java Tutorial: How to Flatten a Nested ArrayList and Fill its Elements into an Array Sep 18, 2025 am 07:24 AM

This tutorial details how to efficiently process nested ArrayLists containing other ArrayLists in Java and merge all its internal elements into a single array. The article will provide two core solutions through the flatMap operation of the Java 8 Stream API: first flattening into a list and then filling the array, and directly creating a new array to meet the needs of different scenarios.

How to get the calling method's name in Java? How to get the calling method's name in Java? Sep 24, 2025 am 06:41 AM

The answer is to use Thread.currentThread().getStackTrace() to get the call method name, and obtain the someMethod name of the call anotherMethod through index 2. Since index 0 is getStackTrace, 1 is the current method, and 2 is the caller, the example output is "Calledbymethod:someMethod", which can also be implemented by Throwable, but attention should be paid to performance, obfuscation, security and inline impact.

See all articles