Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flux type response should be corresponding to List #2199

Merged
merged 7 commits into from Oct 14, 2023

Conversation

gromspys
Copy link
Contributor

@gromspys gromspys commented Oct 11, 2023

Fixes: #1869

Summary by CodeRabbit

  • New Feature: Introduced ReactiveDecoder, ReactorDecoder, and RxJavaDecoder classes to support reactive decoding capabilities for Feign clients, enhancing the ability to handle Mono and Flux types from the Reactor library and Flowable type from RxJava.
  • Refactor: Improved modularity by moving the resolveLastTypeParameter method from Util class to Types class.
  • Documentation: Updated README.md to reflect changes in the GitHubReactor interface and usage examples for Reactor and RxJava2.
  • Test: Enhanced ReactiveFeignIntegrationTest to cover new features and changes, providing better test coverage.
  • New Feature: Added ConsoleLogger for improved logging during testing.
  • Documentation: Added ReactorGitHubExample and RxJavaGitHubExample classes to demonstrate the usage of Feign with Reactor and RxJava respectively.

@coderabbitai
Copy link

coderabbitai bot commented Oct 11, 2023

Walkthrough

This pull request introduces significant enhancements to the Feign library, adding support for reactive programming with Reactor and RxJava. It includes new decoders for handling Mono and Flux types, updates to the GitHubReactor interface, and examples demonstrating the usage of Feign with Reactor and RxJava.

Changes

File(s) Summary
core/src/main/java/feign/Types.java, core/src/main/java/feign/Util.java Introduced new methods for handling type parameters and moved resolveLastTypeParameter method for improved modularity.
reactive/README.md Updated the GitHubReactor interface and the ExampleReactor class to handle Flux and Mono responses.
reactive/src/main/java/feign/reactive/ReactiveDecoder.java, reactive/src/main/java/feign/reactive/ReactorDecoder.java, reactive/src/main/java/feign/reactive/RxJavaDecoder.java Added new classes implementing the Decoder interface to provide reactive decoding capabilities.
reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java Modified the invoke method to handle Flux types more efficiently.
reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java Updated tests to reflect the new reactive features and decoders.
reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java Added a new ConsoleLogger class for logging.
reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java, reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java Added examples demonstrating the usage of Feign with Reactor and RxJava.

🐇

"In the land of code, where the shadows lie,

A rabbit hopped, with a twinkle in its eye.

With each line changed, and each test passed,

The code evolved, and it was a blast!

Now Feign is reactive, oh what a sight,

For developers, it's pure delight! 🎉"


Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • Mention @coderabbitai in any review comment for bot assistance.
  • Note: Review comments are made on code diffs or files, not on the PR overview.

Pause Incremental Reviews

  • Insert @coderabbitai: ignore in the PR description to halt the bot's ongoing reviews. Remove the line to resume.
  • Additionally, enter @coderabbitai pause to halt the bot's ongoing reviews as any issue or review comment. To
    resume reviews, enter @coderabbitai resume as any issue or review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 3

Commits Files that changed from the base of the PR and between 34a7272 and ac5af83.
Files selected for processing (4)
  • core/src/main/java/feign/Types.java (2 hunks)
  • core/src/main/java/feign/Util.java (1 hunks)
  • reactive/README.md (2 hunks)
  • reactive/src/main/java/feign/reactive/ReactiveDecoder.java (1 hunks)
Files skipped from review due to trivial changes (1)
  • core/src/main/java/feign/Util.java
Additional comments (Suppressed): 4
reactive/README.md (1)
  • 37-38: The ReactorFeign.builder() now includes a decoder method call. Ensure that the ReactiveDecoder class is properly implemented and that it correctly handles Mono and Flux types.
core/src/main/java/feign/Types.java (3)
  • 327-358: The new method resolveLastTypeParameter is introduced to resolve the last type parameter of a parameterized supertype. It throws an IllegalStateException if the supertype cannot be resolved into a parameterized type using the provided context. This method is copied from retrofit.RestMethodInfo. Ensure that the copied method is compatible with the current codebase and that it doesn't introduce any licensing issues.

  • 360-362: The new method parameterize is introduced to create a new ParameterizedTypeImpl instance. It takes a raw class and an array of type arguments as parameters. This method improves the modularity of the code by providing a way to create ParameterizedTypeImpl instances.

  • 364-366: The ParameterizedTypeImpl class is now made package-private (default access modifier in Java). This change restricts the visibility of the class to the package in which it is defined. Ensure that this change doesn't break any code outside the package that might be using this class.

Comment on lines 16 to +20
@RequestLine("GET /repos/{owner}/{repo}/contributors")
Flux<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
Flux<Contributor> contributorsFlux(@Param("owner") String owner, @Param("repo") String repo);

@RequestLine("GET /repos/{owner}/{repo}/contributors")
Mono<List<Contributor>> contributorsMono(@Param("owner") String owner, @Param("repo") String repo);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The contributorsFlux and contributorsMono methods have the same @RequestLine annotation. This could lead to confusion and potential errors. Consider renaming these methods to better reflect their return types or the data they are fetching.

Comment on lines 89 to +92
### Iterable and Collections responses

Due to the Synchronous nature of Feign requests, methods that return `Iterable` types must specify the collection
in the `Publisher`. For `Reactor` types, this limits the use of `Flux` as a response type. If you
want to use `Flux`, you will need to manually convert the `Mono` or `Iterable` response types into
`Flux` using the `fromIterable` method.

in the `Publisher`. For `Reactor` types, this limits the use of `Flux` as a response type.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the example code that demonstrates how to manually convert Mono or Iterable response types into Flux using the fromIterable method could potentially confuse users. Consider adding a similar example or providing a link to documentation that explains this process.

reactive/src/main/java/feign/reactive/ReactiveDecoder.java Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Commits Files that changed from the base of the PR and between ac5af83 and bffdd7e.
Files selected for processing (1)
  • reactive/src/main/java/feign/reactive/ReactiveDecoder.java (1 hunks)

reactive/src/main/java/feign/reactive/ReactiveDecoder.java Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Commits Files that changed from the base of the PR and between bffdd7e and 321cdc3.
Files selected for processing (1)
  • reactive/src/main/java/feign/reactive/ReactiveDecoder.java (1 hunks)

reactive/src/main/java/feign/reactive/ReactiveDecoder.java Outdated Show resolved Hide resolved
Copy link
Member

@velo velo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with the change, but can we get at least one test?

@gromspys
Copy link
Contributor Author

I'm good with the change, but can we get at least one test?

Sure. I'll add.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 3

Commits Files that changed from the base of the PR and between 321cdc3 and dd2b4ae.
Files selected for processing (9)
  • reactive/README.md (3 hunks)
  • reactive/src/main/java/feign/reactive/ReactiveDelegatingContract.java (1 hunks)
  • reactive/src/main/java/feign/reactive/ReactorDecoder.java (1 hunks)
  • reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java (1 hunks)
  • reactive/src/main/java/feign/reactive/RxJavaDecoder.java (1 hunks)
  • reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java (12 hunks)
  • reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java (1 hunks)
  • reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java (1 hunks)
  • reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java (1 hunks)
Files skipped from review due to trivial changes (1)
  • reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java
Additional comments (Suppressed): 20
reactive/src/main/java/feign/reactive/ReactorDecoder.java (1)
  • 27-50: The ReactorDecoder class is implementing the Decoder interface and overriding the decode method to handle Mono and Flux types. However, for Flux type, it seems to be decoding the response into a List. This might not be the expected behavior as Flux is a stream of 0 to N items, and decoding it into a List might cause memory issues for large data streams. Consider returning a Flux instead of a List.
-            Type listType = Types.parameterize(List.class, lastType);
-            return delegate.decode(response, listType);
+            return Flux.fromIterable((List<?>) delegate.decode(response, listType));
reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java (1)
  • 31-36: The RxJavaDecoder is being used with JacksonDecoder which is a good practice for handling JSON responses. However, ensure that the JacksonDecoder is compatible with the data being returned from the API calls. If the API returns a different data format, you may need to use a different decoder.
reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java (5)
  • 33-37: The ReactorFeign.builder() is correctly configured with the new ReactorDecoder and JacksonDecoder. The logger and log level are also set appropriately. The target URL is correctly set to "https://api.github.com".

  • 39-45: The contributorsFlux method is used to fetch a list of contributors using a Flux type. The collectList() method is used to convert the Flux to a List, and the block() method is used to subscribe to the Flux and block until it completes. The contributors are then printed to the console. This is a correct usage of the Flux type.

  • 47-52: The contributorsMono method is used to fetch a list of contributors using a Mono type. The block() method is used to subscribe to the Mono and block until it completes. The contributors are then printed to the console. This is a correct usage of the Mono type.

  • 56-61: The GitHub interface is correctly defined with two methods: contributorsFlux and contributorsMono. Both methods use the @RequestLine annotation to define the HTTP request, and the @Param annotation to define the path parameters. The contributorsFlux method returns a Flux<Contributor>, and the contributorsMono method returns a Mono<List<Contributor>>.

  • 63-74: The Contributor class is correctly defined with two fields: login and contributions. The setLogin and setContributions methods are used to set the values of these fields.

reactive/src/main/java/feign/reactive/ReactiveDelegatingContract.java (1)
  • 55-59: The new hunk has replaced the direct assignment of the first type argument to the method's return type with a call to the type() method. This change could potentially alter the behavior of the code if the type() method does not return the first type argument as expected. Please verify that the type() method is implemented correctly and that this change does not introduce any unexpected behavior.
reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java (1)
  • 36-42: The new hunk introduces a flatMapIterable operation on the Flux type. This operation transforms the elements of the Flux into Iterables and then flattens these Iterables into a new Flux. This change implies that the method now expects the elements of the Flux to be Iterables. Ensure that this change is compatible with the expected return types of the methods that will be invoked by this handler. If the methods are not returning Iterables, this could lead to a ClassCastException.
- return Flux.from(invocation).flatMapIterable(e -> (Iterable) e).subscribeOn(scheduler);
+ return Flux.from(invocation).subscribeOn(scheduler);
reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java (6)
  • 86-97: The ReactorDecoder is being used instead of the JacksonDecoder. This change is in line with the PR's goal of handling Flux type responses in Feign clients. Ensure that the ReactorDecoder is compatible with all the places where this function is used.

  • 105-126: The test testReactorTargetFull has been updated to include tests for service.usersFlux() and service.usersMono(). This is a good practice as it ensures that the new methods are tested.

  • 134-139: The RxJavaDecoder is being used instead of the JacksonDecoder. This change is in line with the PR's goal of handling Flux type responses in Feign clients. Ensure that the RxJavaDecoder is compatible with all the places where this function is used.

  • 315-320: In all these instances, the ReactorDecoder or RxJavaDecoder is being used instead of the Decoder.Default(). This change is in line with the PR's goal of handling Flux type responses in Feign clients. Ensure that these decoders are compatible with all the places where these functions are used.

  • 329-338: The TestReactorService interface has been updated to include usersFlux() and usersMono(). This is a good practice as it ensures that the new methods are included in the interface.

  • 346-354: The TestReactiveXService interface has been updated to include users(). This is a good practice as it ensures that the new method is included in the interface.

reactive/src/main/java/feign/reactive/RxJavaDecoder.java (1)
  • 25-43: The RxJavaDecoder class is well implemented. It delegates the decoding to another Decoder instance, which allows for flexibility in choosing the decoding strategy. The decode method checks if the response type is assignable from Flowable, and if so, it resolves the last type parameter of the Flowable and decodes the response using that type. This is a good approach to handle Flowable types in the response. However, it would be beneficial to handle the case where the delegate.decode method might throw an exception. Wrapping the decode calls in a try-catch block and handling the exceptions appropriately would make the code more robust.
    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        Class<?> rawType = Types.getRawType(type);
        if (rawType.isAssignableFrom(Flowable.class)) {
            Type lastType = Types.resolveLastTypeParameter(type, Flowable.class);
            try {
                return delegate.decode(response, lastType);
            } catch (IOException | FeignException e) {
                // handle exception
            }
        }

        try {
            return delegate.decode(response, type);
        } catch (IOException | FeignException e) {
            // handle exception
        }
    }
reactive/README.md (4)
  • 14-33: The contributors method has been split into two methods: contributorsFlux and contributorsMono, returning a Flux and a Mono respectively. This change provides more flexibility in handling the response, allowing for both a stream of contributors and a single emission of a list of contributors. However, ensure that all calls to the original contributors method throughout the codebase have been updated to use one of the new methods.

  • 36-46: The ExampleReactor class has been updated to use the new ReactorDecoder in the ReactorFeign.builder() call. This change allows for reactive decoding of the response. The contributorsFlux and contributorsMono methods are used to retrieve contributors, demonstrating the use of both Flux and Mono response types. The block() method is used to subscribe to the Flux and Mono and block until they emit their items, collecting them into a list. This is a good use of the reactive capabilities provided by the Reactor library.

  • 64-69: The ExampleRxJava2 class has been updated to use the new RxJavaDecoder in the RxJavaFeign.builder() call. This change allows for reactive decoding of the response using RxJava. However, the contributors method has not been updated to match the changes in the GitHubReactor interface. Please verify if this is intentional or if the GitHubReactiveX interface should also be updated.

  • 90-94: The section on Iterable and Collections responses has been updated to remove the information about manually converting Mono or Iterable response types into Flux using the fromIterable method. This is consistent with the changes in the GitHubReactor interface, which now provides a Flux response type directly. However, the statement "this limits the use of Flux as a response type" may no longer be accurate, as the contributorsFlux method does return a Flux. Please verify if this statement should be updated or removed.

Comment on lines +48 to +50
@RequestLine("GET /repos/{owner}/{repo}/contributors")
Flowable<List<Contributor>> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The contributors method is returning a Flowable<List<Contributor>>. This means that it will emit multiple lists of contributors. If the API only returns a single list of contributors, consider changing the return type to Single<List<Contributor>> to better reflect the expected response.

Comment on lines +52 to +64
static class Contributor {

private String login;
private int contributions;

void setLogin(String login) {
this.login = login;
}

void setContributions(int contributions) {
this.contributions = contributions;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Contributor class is using package-private visibility for its fields and methods. This is generally not recommended as it can lead to issues with encapsulation. Consider changing the visibility to private and providing public getter methods to access the fields.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 7

Commits Files that changed from the base of the PR and between 321cdc3 and dd2b4ae.
Files selected for processing (9)
  • reactive/README.md (3 hunks)
  • reactive/src/main/java/feign/reactive/ReactiveDelegatingContract.java (1 hunks)
  • reactive/src/main/java/feign/reactive/ReactorDecoder.java (1 hunks)
  • reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java (1 hunks)
  • reactive/src/main/java/feign/reactive/RxJavaDecoder.java (1 hunks)
  • reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java (12 hunks)
  • reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java (1 hunks)
  • reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java (1 hunks)
  • reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java (1 hunks)
Additional comments (Suppressed): 16
reactive/src/main/java/feign/reactive/ReactiveDelegatingContract.java (1)
  • 55-59: The new hunk has removed the explicit setting of the return type to the first actual type (actualTypes[0]). Ensure that the type variable being used in metadata.returnType(type); is correctly set and represents the intended return type.
reactive/src/main/java/feign/reactive/RxJavaDecoder.java (2)
  • 33-42: The decode method has been overridden to handle decoding based on the type of the response. If the type is Flowable, it resolves the last type parameter and delegates the decoding to the underlying decoder. This is a good approach to handle different types of responses in a reactive context. However, it's important to ensure that the underlying decoder can handle the resolved type correctly.

  • 29-31: The constructor takes a Decoder as a parameter and assigns it to the delegate field. This allows the RxJavaDecoder to delegate the actual decoding to another Decoder, which can be any implementation of the Decoder interface. This is a good example of the Delegation pattern and promotes code reusability and flexibility.

reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java (1)
  • 32-53: The use of .block() in a reactive stream is generally discouraged as it defeats the purpose of using a non-blocking reactive stream. It would be better to use .subscribe() or .doOnNext() to handle the results of the Flux and Mono streams. However, this might be acceptable in a simple main method for demonstration purposes. Please verify if this is the intended usage.
reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java (2)
  • 31-36: The RxJavaDecoder is being used here, which is a good choice for handling reactive types. However, it's important to ensure that the rest of the codebase is compatible with this change, especially if it was previously using a non-reactive decoder.

  • 48-50: The contributors method returns a Flowable<List<Contributor>>. This is a good use of RxJava's Flowable for handling potentially large lists of data. However, ensure that the API endpoint /repos/{owner}/{repo}/contributors supports streaming responses, as Flowable is designed to handle backpressure in streaming scenarios.

reactive/README.md (4)
  • 14-33: The contributors method in the GitHubReactor interface has been split into two methods: contributorsFlux and contributorsMono. This change allows for differentiation between Flux and Mono responses. Ensure that all calls to these methods throughout the codebase have been updated to match the new method names. Also, the Contributor class no longer has a constructor and instead uses getter and setter methods for the login field. Make sure this change doesn't affect the instantiation of Contributor objects in the codebase.

  • 35-47: The ExampleReactor class now uses a ReactorDecoder with a JacksonDecoder for decoding responses. This change provides reactive decoding capabilities. The contributorsFlux and contributorsMono methods are used to retrieve contributors, and the responses are collected into lists using collectList(). This is a more efficient way of collecting responses compared to the previous method of using collect(Collectors.toList()).

  • 62-69: The ExampleRxJava2 class now uses a RxJavaDecoder with a JacksonDecoder for decoding responses. This change provides reactive decoding capabilities for RxJava. Ensure that the RxJavaDecoder works as expected and doesn't introduce any issues.

  • 90-94: The section on Iterable and Collections responses has been updated to remove the mention of manual conversion from Mono or Iterable to Flux using the fromIterable method. This is because the new ReactorDecoder handles the conversion automatically. Ensure that this change doesn't introduce any issues with handling Flux responses.

reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java (6)
  • 86-97: The ReactorDecoder is being used instead of the JacksonDecoder. This change is likely due to the need to handle Flux type responses in Feign clients. Ensure that the ReactorDecoder is compatible with the rest of the codebase and that it correctly handles all expected response types.

  • 105-126: The test method testReactorTargetFull has been updated to include tests for Flux and Mono responses. This is a good addition as it ensures that the new functionality is being properly tested.

  • 134-139: The RxJavaDecoder is being used instead of the JacksonDecoder. This change is likely due to the need to handle Flux type responses in Feign clients. Ensure that the RxJavaDecoder is compatible with the rest of the codebase and that it correctly handles all expected response types.

  • 315-320: In each of these instances, the ReactorDecoder or RxJavaDecoder is being used instead of the Decoder.Default(). This change is likely due to the need to handle Flux type responses in Feign clients. Ensure that these decoders are compatible with the rest of the codebase and that they correctly handle all expected response types.

  • 329-338: The TestReactorService interface has been updated to include methods for handling Flux and Mono responses. This is a good addition as it allows for testing of the new functionality.

  • 346-354: The TestReactiveXService interface has been updated to include a method for handling Flowable<List<User>> responses. This is a good addition as it allows for testing of the new functionality.

Comment on lines +16 to +22
import feign.Logger;

public class ConsoleLogger extends Logger {
@Override
protected void log(String configKey, String format, Object... args) {
System.out.println(String.format(methodTag(configKey) + format, args));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ConsoleLogger class extends Logger and overrides the log method to print logs to the console. This is a simple and straightforward implementation. However, consider using a proper logging framework like Log4J or SLF4J for more robust logging capabilities, including log levels, log file rotation, and asynchronous logging.

-        System.out.println(String.format(methodTag(configKey) + format, args));
+        // Assuming a logger instance is available
+        logger.info(String.format(methodTag(configKey) + format, args));

Comment on lines +36 to +49
public Object decode(Response response, Type type) throws IOException, FeignException {
Class<?> rawType = Types.getRawType(type);
if (rawType.isAssignableFrom(Mono.class)) {
Type lastType = Types.resolveLastTypeParameter(type, Mono.class);
return delegate.decode(response, lastType);
}
if (rawType.isAssignableFrom(Flux.class)) {
Type lastType = Types.resolveLastTypeParameter(type, Flux.class);
Type listType = Types.parameterize(List.class, lastType);
return delegate.decode(response, listType);
}

return delegate.decode(response, type);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The decode method has been updated to handle Mono and Flux types. It checks the raw type of the response and if it's Mono or Flux, it resolves the last type parameter and delegates the decoding to the underlying decoder. This is a good approach to handle reactive types in Feign clients. However, for Flux types, it's creating a List type to decode the response. This might not be the best approach as it could lead to memory issues for large responses. Consider using a streaming approach to handle Flux types.

-            Type listType = Types.parameterize(List.class, lastType);
-            return delegate.decode(response, listType);
+            return Flux.from(delegate.decode(response, lastType));

Comment on lines 36 to 42
protected Publisher invoke(Method method, MethodHandler methodHandler, Object[] arguments) {
Publisher<?> invocation = this.invokeMethod(methodHandler, arguments);
if (Flux.class.isAssignableFrom(method.getReturnType())) {
return Flux.from(invocation).subscribeOn(scheduler);
return Flux.from(invocation).flatMapIterable(e -> (Iterable) e).subscribeOn(scheduler);
} else if (Mono.class.isAssignableFrom(method.getReturnType())) {
return Mono.from(invocation).subscribeOn(scheduler);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change from subscribeOn to flatMapIterable for Flux types is a significant one. This change ensures that the elements emitted by the Flux are processed sequentially on the scheduler. However, it also assumes that the emitted items are of type Iterable. This might not always be the case and could lead to a ClassCastException if the items are not Iterable. Consider adding a type check before casting to Iterable.

- return Flux.from(invocation).flatMapIterable(e -> (Iterable) e).subscribeOn(scheduler);
+ return Flux.from(invocation).flatMapIterable(e -> e instanceof Iterable ? (Iterable) e : Collections.singletonList(e)).subscribeOn(scheduler);

Comment on lines +55 to +61
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
Flux<Contributor> contributorsFlux(@Param("owner") String owner, @Param("repo") String repo);

@RequestLine("GET /repos/{owner}/{repo}/contributors")
Mono<List<Contributor>> contributorsMono(@Param("owner") String owner, @Param("repo") String repo);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub interface has two methods contributorsFlux and contributorsMono that seem to be doing the same thing but returning different types (Flux<Contributor> and Mono<List<Contributor>>). This might be confusing for users of the interface. Consider consolidating these methods into one or clearly documenting the difference in their behaviors.

Comment on lines +63 to +74
static class Contributor {

private String login;
private int contributions;

void setLogin(String login) {
this.login = login;
}

void setContributions(int contributions) {
this.contributions = contributions;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Contributor class is using manual setters for its fields. Consider using Lombok's @Data or @Setter annotations to generate these methods automatically, which would make the code cleaner and more maintainable.

Comment on lines +38 to +43
System.out.println("Let's fetch and print a list of the contributors to this library.");
List<Contributor> contributorsFromFlux = github.contributors("OpenFeign", "feign")
.blockingLast();
for (Contributor contributor : contributorsFromFlux) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The blockingLast() method is being used to convert the Flowable to a List. This is a blocking operation and may not be ideal in a reactive context. Consider using non-blocking operations to fully leverage the benefits of reactive programming.

Comment on lines +54 to +63
private String login;
private int contributions;

void setLogin(String login) {
this.login = login;
}

void setContributions(int contributions) {
this.contributions = contributions;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Contributor class is mutable, as it provides setters for its fields. This could potentially lead to issues in a multi-threaded environment. Consider making this class immutable if it's safe to do so.

@velo velo merged commit ddb9ff9 into OpenFeign:master Oct 14, 2023
3 checks passed
@gromspys gromspys deleted the feature/add-reactive-decoder branch October 14, 2023 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flux type reponse shoud be corresponding to List
2 participants