Skip to content

Commit

Permalink
Merge pull request #6 from StevenPG/pair-of-new-articles
Browse files Browse the repository at this point in the history
Pair of new articles
  • Loading branch information
StevenPG authored Sep 20, 2024
2 parents 05460ad + 0c43b1b commit 4e5fee7
Show file tree
Hide file tree
Showing 2 changed files with 260 additions and 0 deletions.
73 changes: 73 additions & 0 deletions _drafts/2024-09-17-Java-Streams-Gather-Jdk-23.markdown
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 _posts/2024-09-19-Easy-Spring-Rest-Client-with-OAuth2.markdown
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

0 comments on commit 4e5fee7

Please sign in to comment.