generated from chadbaldwin/simple-blog-bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from StevenPG/pair-of-new-articles
Pair of new articles
- Loading branch information
Showing
2 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
--- | ||
layout: post | ||
title: "Jdk 23 Streams - Using Gather" | ||
toc: true | ||
date: 2024-09-17 12:00:00 -0500 | ||
categories: | ||
- software | ||
- java | ||
--- | ||
|
||
# It's finally here! JDK 23 | ||
TODO - make small XXXTODOXXX | ||
|
||
Just kidding, this isn't an LTS release | ||
|
||
The next LTS release that will include all of the changes in JDK 23 is XXXTODOXXX and | ||
that won't be available until XXXTODOXXX | ||
|
||
The link to the release notes for Jdk23 are right here: https://openjdk.org/projects/jdk/23/ | ||
|
||
But this article is going to focus on a pretty powerful addition for anyone that's been | ||
leveraging Java Streams heavily for stream processing! | ||
|
||
Specifically Gatherers, the JEP is right over here: https://openjdk.org/jeps/473 | ||
|
||
## JEP-473 | ||
|
||
Stream Gatherers is a preview API delivered in JDK 22 that's in preview again | ||
in JDK 23. Gatherers allow for stream pipelines to transform | ||
data through intermediate operations instead of needing to perform | ||
a terminating operation and generate a new stream. | ||
|
||
Today, if we want to process a list of elements, then perform an operation on the entire list, | ||
and then continue processing the list, we'd have to do it like this: | ||
|
||
```java | ||
TODO - add an example here | ||
``` | ||
With Gatherers, we're able to do this in a cleaner way by | ||
doing our extra processing in an intermediate method! | ||
|
||
```java | ||
TODO - add an example here | ||
``` | ||
|
||
Here's the full example code (and we don't need a default class anymore with JDK 23!) | ||
|
||
```java | ||
import java.util.function.Predicate; | ||
import java.util.stream.Gatherer; | ||
import java.util.stream.Stream; | ||
|
||
void main(String[] args) { | ||
|
||
var result = Stream.of(1, 2, 3) // The Stream | ||
.filter((integer -> integer > 0)) // Intermediate Operation | ||
// TODO - gather example | ||
.toList(); // The Terminal Operation | ||
System.out.println(result); | ||
} | ||
|
||
``` | ||
|
||
```bash | ||
$ javac demo.java --enable-preview -source 23 | ||
$ java --enable-preview demo | ||
``` | ||
|
||
TODO - find real life example | ||
- distinctBy | ||
- grouping and applying a change to the whole collection | ||
|
||
[soby-chako]: https://github.com/sobychacko |
187 changes: 187 additions & 0 deletions
187
_posts/2024-09-19-Easy-Spring-Rest-Client-with-OAuth2.markdown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
--- | ||
layout: post | ||
title: "Easy Spring Rest Client w/ OAuth2" | ||
toc: true | ||
date: 2024-09-19 12:00:00 -0500 | ||
categories: | ||
- software | ||
- spring boot | ||
- java | ||
--- | ||
|
||
# Brief | ||
|
||
My goal is to make posts like this the SIMPLEST place on the internet to learn how to do things | ||
that caused me trouble. That way, if this is found, someone doesn't have to do the same digging I had to do. | ||
|
||
# What is OAuth2? | ||
|
||
OAuth2 is a popular authorization framework that allows users to grant | ||
third-party applications access to their data without revealing their | ||
credentials. It's often used for services like social media logins, API integrations, and more. | ||
|
||
### Key Components of OAuth2 | ||
|
||
- Authorization Server: Issues access tokens to clients after user authorization. | ||
- Resource Server: Protects resources that can only be accessed with valid access tokens. | ||
- Client: The application requesting access to resources. | ||
- User: The person granting or denying access. | ||
|
||
### How OAuth2 Works | ||
|
||
- User Authorization: The user grants permission to the client to access specific resources. | ||
- Token Exchange: The client exchanges an authorization code for an access token. | ||
- Resource Access: The client uses the access token to access protected resources. | ||
|
||
### Why RestClient? | ||
|
||
While **RestTemplate** has been a staple for many years, its limitations and the | ||
introduction of more modern alternatives have led to its deprecation in recent | ||
versions of Spring. Let's dive into the key differences between WebClient | ||
and RestClient and why RestTemplate is being phased out. | ||
|
||
**WebClient** is built on top of Project Reactor, a reactive | ||
programming framework. This means it can handle asynchronous operations efficiently, | ||
making it well-suited for scenarios where concurrent requests and non-blocking I/O | ||
are essential. | ||
|
||
However, with RestTemplate's deprecation, the only real Spring alternative is WebClient. | ||
This requires including the spring-webflux dependencies and calling `.block()` when making | ||
blocking API calls. It feels shoe-horned into place. | ||
|
||
In comes [RestClient][restClientBlogAnnouncement], a client written in the same functional style as WebClient, but supports | ||
synchronous and asynchronous operations out of the box. This lets us remove the spring-webflux | ||
dependency and use spring-web-mvc as the primary HTTP dependency for server and client applications. | ||
|
||
## The Setup (Currently a Milestone Release but this will be updated!) | ||
|
||
Here's everything you need to get RestClient working with OAuth2! | ||
|
||
build.gradle | ||
```groovy | ||
plugins { | ||
id 'org.springframework.boot' version '3.3.3' | ||
} | ||
// ... The rest of the stuff, this is just what's required | ||
dependencies { | ||
implementation 'org.springframework.boot:spring-boot-starter-security' | ||
implementation 'org.springframework.boot:spring-boot-starter-web' | ||
implementation 'org.springframework.security:spring-security-oauth2-client:6.4.0-M3' | ||
} | ||
} | ||
``` | ||
|
||
application.yaml | ||
```yaml | ||
spring: | ||
security: | ||
oauth2: | ||
client: | ||
registration: | ||
my-oauth-client: | ||
client-id: ${oauthClientId} | ||
client-secret: ${oauthClientSecret} | ||
provider: my-oauth-provider | ||
authorization-grant-type: client_credentials | ||
scope: openid | ||
provider: | ||
my-oauth-provider: | ||
token-uri: ${oauth2ServerUri}/protocol/openid-connect/token | ||
issuer-uri: ${oauth2ServerUri} | ||
``` | ||
application-local.yaml | ||
```yaml | ||
oauth2ServerUri: http://myServerUri:9090 | ||
oauthClientId: clientId | ||
oauth2ClientSecret: mySecretSecret | ||
``` | ||
RestClientConfiguration.java using the new [OAuth2ClientHttpRequestInterceptor][oAuth2ClientHttpRequestInterceptor] | ||
```java | ||
@Configuration | ||
public class RestClientConfiguration | ||
{ | ||
// This needs to match the YAML configuration | ||
private static final String CLIENT_REGISTRATION_ID = "my-oauth-client"; | ||
|
||
@Bean | ||
public OAuth2AuthorizedClientManager authorizedClientManager ( | ||
ClientRegistrationRepository clientRegistrationRepository, | ||
OAuth2AuthorizedClientService authorizedClientService | ||
){ | ||
// We create a manager using the autowired clientRegistrations from YAML and connect it to the service | ||
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = | ||
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService); | ||
|
||
// Setting the clientManager to look for a clientCredentials configuration | ||
authorizedClientManager.setAuthorizedClientProvider(OAuth2AuthorizedClientProviderBuilder.builder() | ||
.clientCredentials() | ||
.build()); | ||
return authorizedClientManager; | ||
} | ||
|
||
@Bean | ||
public RestClient oauth2RestClient( | ||
OAuth2AuthorizedClientManager authorizedClientManager, | ||
LogbookClientHttpRequestInterceptor logbookClientHttpRequestInterceptor) { | ||
|
||
// This is the new class!!! We instantiate a new one and provide it the client registration to match | ||
OAuth2ClientHttpRequestInterceptor oAuth2ClientHttpRequestInterceptor = | ||
new OAuth2ClientHttpRequestInterceptor(authorizedClientManager, request -> CLIENT_REGISTRATION_ID); | ||
|
||
// From here we simply return the client with any custom configuration, and we're good to go! | ||
return RestClient.builder() | ||
.baseUrl("http://myBaseUrl:8080") | ||
.requestInterceptor(oAuth2ClientHttpRequestInterceptor) | ||
.build(); | ||
} | ||
} | ||
``` | ||
|
||
### Bonus: Setting up HttpServiceProxyFactory (not required but useful!) | ||
|
||
[HttpServiceProxyFactory][httpServiceProxyFactory] is new in [Spring 6][httpServiceProxyFactoryJavadoc]! | ||
|
||
```java | ||
public interface MyHttpService { | ||
|
||
@PostExchange("api/my/path") | ||
SomeResponse post(@RequestBody MyPostBody request); | ||
} | ||
``` | ||
|
||
```java | ||
@Configuration | ||
public class HttpServiceFactory | ||
{ | ||
@Bean | ||
public MyHttpService getMyHttpService(RestClient oauth2RestClient) { | ||
// We're simply injecting our restClient into the factory and creating a concrete instance of the interface | ||
HttpServiceProxyFactory factory = HttpServiceProxyFactory | ||
.builderFor(RestClientAdapter.create(oauth2RestClient)) | ||
.build(); | ||
return factory.createClient(MyHttpService.class); | ||
} | ||
} | ||
``` | ||
|
||
## Summary | ||
|
||
The new RestClient is already a popular alternative for developers in the Spring ecosystem. | ||
The lack of an OAuth2 component has been a sore spot for new users converting over from WebClient. So with | ||
this new feature releasing in Spring Boot 3.4.0, it can now take it's rightful place as the default, non-webflux | ||
HTTP Client for Spring MVC! | ||
|
||
## Update Note | ||
|
||
Once this is available in the official spring release, I'll update this from milestone versions and | ||
hook up the JavaDoc instead of the originating Github Issue! | ||
|
||
[restClientBlogAnnouncement]: https://spring.io/blog/2023/07/13/new-in-spring-6-1-restclient | ||
[oAuth2ClientHttpRequestInterceptor]: https://github.com/spring-projects/spring-security/issues/13588 | ||
[httpServiceProxyFactoryJavadoc]: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/service/invoker/HttpServiceProxyFactory.html | ||
[httpServiceProxyFactory]: https://www.baeldung.com/spring-6-http-interface | ||
[soby-chako]: https://github.com/sobychacko |