Skip to content

Commit 2e761f4

Browse files
Yury-Fridlyandshohamazon
authored andcommitted
Java: Shadow netty dependencies. - breaking change (#3004)
* Shadow `netty` dependencies. Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
1 parent 11d2155 commit 2e761f4

File tree

18 files changed

+106
-146
lines changed

18 files changed

+106
-146
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@
7878
* Java: Change `BZMPOP` and `ZMPOP` to return `Map<String, Object>` and `Map<GlideString, Object>` instead of `Object[]` ([#3733](https://github.com/valkey-io/valkey-glide/pull/3733))
7979
* Go: Change parameters of `EchoWithOptions` to be more user-friendly ([#3806](https://github.com/valkey-io/valkey-glide/pull/3806))
8080

81+
* Java: Shadow netty dependencies. ([#3004](https://github.com/valkey-io/valkey-glide/pull/3004))
82+
8183
#### Fixes
8284

8385
* Go, Java: Fix response handling for `customCommand` API for cluster client ([#3593](https://github.com/valkey-io/valkey-glide/pull/3593))

java/client/build.gradle

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ dependencies {
2222
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '4.29.1'
2323
shadow group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0'
2424

25-
shadow group: 'io.netty', name: 'netty-handler', version: '4.1.121.Final'
25+
implementation group: 'io.netty', name: 'netty-handler', version: '4.1.121.Final'
2626
// https://github.com/netty/netty/wiki/Native-transports
2727
// At the moment, Windows is not supported
28-
shadow group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.121.Final', classifier: 'linux-x86_64'
29-
shadow group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.121.Final', classifier: 'linux-aarch_64'
30-
shadow group: 'io.netty', name: 'netty-transport-native-kqueue', version: '4.1.121.Final', classifier: 'osx-aarch_64'
28+
implementation group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.121.Final', classifier: 'linux-x86_64'
29+
implementation group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.121.Final', classifier: 'linux-aarch_64'
30+
implementation group: 'io.netty', name: 'netty-transport-native-kqueue', version: '4.1.121.Final', classifier: 'osx-aarch_64'
3131

3232
// junit
3333
testImplementation group: 'org.mockito', name: 'mockito-inline', version: '3.12.4'
@@ -255,9 +255,64 @@ jar {
255255
archiveClassifier = osdetector.classifier
256256
}
257257

258+
import com.github.jengelman.gradle.plugins.shadow.transformers.CacheableTransformer
259+
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
260+
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
261+
import org.apache.tools.zip.ZipOutputStream
262+
import org.apache.tools.zip.ZipEntry
263+
264+
// https://github.com/grpc/grpc-java/blob/b3db8c2489af25b0d10b6f45e60fd50771aa93d1/netty/shaded/build.gradle#L149
265+
/**
266+
* A Transformer which updates the Netty JAR META-INF/ resources to accurately
267+
* reference shaded class names.
268+
*/
269+
@CacheableTransformer
270+
class NettyResourceTransformer implements Transformer {
271+
272+
// A map of resource file paths to be modified
273+
private Map<String, String> resources = [:]
274+
275+
@Override
276+
boolean canTransformResource(FileTreeElement fileTreeElement) {
277+
fileTreeElement.name.startsWith("META-INF/native-image/io.netty")
278+
}
279+
280+
@Override
281+
void transform(TransformerContext context) {
282+
String updatedPath = context.path.replace("io.netty", "glide.io.netty")
283+
String updatedContent = context.is.getText().replace("io.netty", "glide.io.netty")
284+
resources.put(updatedPath, updatedContent)
285+
}
286+
287+
@Override
288+
boolean hasTransformedResource() {
289+
resources.size() > 0
290+
}
291+
292+
@Override
293+
void modifyOutputStream(ZipOutputStream outputStream, boolean preserveFileTimestamps) {
294+
for (resourceEntry in resources) {
295+
ZipEntry entry = new ZipEntry(resourceEntry.key)
296+
entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time)
297+
298+
outputStream.putNextEntry(entry)
299+
outputStream.write(resourceEntry.value.getBytes())
300+
outputStream.closeEntry()
301+
}
302+
}
303+
}
304+
258305
shadowJar {
259306
dependsOn('copyNativeLib')
260307
archiveClassifier = osdetector.classifier
308+
excludes.remove("module-info.class")
309+
relocate('io.netty', 'glide.io.netty')
310+
relocate('com.google.protobuf', 'glide.com.google.protobuf')
311+
mergeServiceFiles()
312+
313+
relocate 'META-INF/native/libnetty', 'META-INF/native/libglide_netty'
314+
relocate 'META-INF/native/netty', 'META-INF/native/glide_netty'
315+
transform(NettyResourceTransformer.class)
261316
}
262317

263318
sourcesJar {

java/client/src/main/java/glide/api/BaseClient.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,8 @@ protected static class ClientBuilder {
360360
protected static <T extends BaseClient> CompletableFuture<T> createClient(
361361
@NonNull BaseClientConfiguration config, Function<ClientBuilder, T> constructor) {
362362
try {
363-
ThreadPoolResource threadPoolResource = config.getThreadPoolResource();
364-
if (threadPoolResource == null) {
365-
threadPoolResource =
366-
ThreadPoolResourceAllocator.getOrCreate(Platform.getThreadPoolResourceSupplier());
367-
}
363+
ThreadPoolResource threadPoolResource =
364+
ThreadPoolResourceAllocator.getOrCreate(Platform.getThreadPoolResourceSupplier());
368365
MessageHandler messageHandler = buildMessageHandler(config);
369366
ChannelHandler channelHandler = buildChannelHandler(threadPoolResource, messageHandler);
370367
ConnectionManager connectionManager = buildConnectionManager(channelHandler);

java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
22
package glide.api.models.configuration;
33

4-
import glide.connectors.resources.ThreadPoolResource;
54
import java.util.List;
65
import lombok.Builder;
76
import lombok.Getter;
@@ -60,12 +59,6 @@ public abstract class BaseClientConfiguration {
6059
*/
6160
private final String clientName;
6261

63-
/**
64-
* Advanced users can pass an extended {@link ThreadPoolResource} to pass a user-defined event
65-
* loop group. If set, users are responsible for shutting the resource down when no longer in use.
66-
*/
67-
private final ThreadPoolResource threadPoolResource;
68-
6962
/**
7063
* Serialization protocol to be used with the server. If not set, {@link ProtocolVersion#RESP3}
7164
* will be used.

java/client/src/main/java/glide/connectors/resources/EpollResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Implementation of ThreadPoolResource for Epoll-based systems. Enabling custom/default
1010
* configurations.
1111
*/
12-
public class EpollResource extends ThreadPoolResource {
12+
class EpollResource extends ThreadPoolResource {
1313
private static final String EPOLL_EVENT_LOOP_IDENTIFIER = "glide-channel-epoll-elg";
1414

1515
public EpollResource() {

java/client/src/main/java/glide/connectors/resources/KQueuePoolResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Implementation of ThreadPoolResource for Kqueue-based systems. Enabling custom/default
1010
* configurations.
1111
*/
12-
public class KQueuePoolResource extends ThreadPoolResource {
12+
class KQueuePoolResource extends ThreadPoolResource {
1313
private static final String KQUEUE_EVENT_LOOP_IDENTIFIER = "glide-channel-kqueue-elg";
1414

1515
public KQueuePoolResource() {

java/client/src/main/java/glide/connectors/resources/ThreadPoolResource.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,15 @@
44
import io.netty.channel.EventLoopGroup;
55
import io.netty.channel.unix.DomainSocketChannel;
66
import lombok.Getter;
7-
import lombok.NonNull;
7+
import lombok.RequiredArgsConstructor;
88

99
/**
1010
* Abstract base class that provides the EventLoopGroup and DomainSocketChannel to be used by the
1111
* Netty protocol.
1212
*/
1313
@Getter
14+
@RequiredArgsConstructor
1415
public abstract class ThreadPoolResource {
15-
private EventLoopGroup eventLoopGroup;
16-
private Class<? extends DomainSocketChannel> domainSocketChannelClass;
17-
18-
public ThreadPoolResource(
19-
@NonNull EventLoopGroup eventLoopGroup,
20-
@NonNull Class<? extends DomainSocketChannel> domainSocketChannelClass) {
21-
this.eventLoopGroup = eventLoopGroup;
22-
this.domainSocketChannelClass = domainSocketChannelClass;
23-
}
16+
private final EventLoopGroup eventLoopGroup;
17+
private final Class<? extends DomainSocketChannel> domainSocketChannelClass;
2418
}

java/client/src/main/java/module-info.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
exports glide.api.logging;
55
exports glide.api.models;
66
exports glide.api.models.commands;
7+
exports glide.api.models.commands.batch;
78
exports glide.api.models.commands.bitmap;
89
exports glide.api.models.commands.geospatial;
910
exports glide.api.models.commands.function;
@@ -15,13 +16,7 @@
1516
exports glide.api.models.exceptions;
1617
exports glide.api.commands.servermodules;
1718

18-
requires com.google.protobuf;
19-
requires io.netty.codec;
20-
requires io.netty.common;
21-
requires io.netty.transport;
22-
requires io.netty.transport.classes.epoll;
23-
requires io.netty.transport.classes.kqueue;
24-
requires io.netty.transport.unix.common;
25-
requires lombok;
19+
requires java.logging; // required by shadowed protobuf
20+
requires static lombok;
2621
requires org.apache.commons.lang3;
2722
}

java/client/src/test/java/glide/api/GlideClientCreateTest.java

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,18 @@
77
import static glide.api.GlideClient.buildConnectionManager;
88
import static glide.api.GlideClient.createClient;
99
import static org.junit.jupiter.api.Assertions.assertEquals;
10-
import static org.junit.jupiter.api.Assertions.assertThrows;
1110
import static org.mockito.ArgumentMatchers.any;
1211
import static org.mockito.ArgumentMatchers.eq;
1312
import static org.mockito.Mockito.mock;
1413
import static org.mockito.Mockito.mockStatic;
1514
import static org.mockito.Mockito.when;
1615

1716
import glide.api.models.configuration.GlideClientConfiguration;
18-
import glide.api.models.exceptions.ClosingException;
1917
import glide.connectors.handlers.ChannelHandler;
2018
import glide.connectors.handlers.MessageHandler;
21-
import glide.connectors.resources.ThreadPoolResource;
22-
import glide.connectors.resources.ThreadPoolResourceAllocator;
2319
import glide.managers.CommandManager;
2420
import glide.managers.ConnectionManager;
2521
import java.util.concurrent.CompletableFuture;
26-
import java.util.concurrent.ExecutionException;
2722
import lombok.SneakyThrows;
2823
import org.junit.jupiter.api.AfterEach;
2924
import org.junit.jupiter.api.BeforeEach;
@@ -37,7 +32,6 @@ public class GlideClientCreateTest {
3732
private ConnectionManager connectionManager;
3833
private CommandManager commandManager;
3934
private MessageHandler messageHandler;
40-
private ThreadPoolResource threadPoolResource;
4135

4236
@BeforeEach
4337
public void init() {
@@ -47,19 +41,12 @@ public void init() {
4741
commandManager = mock(CommandManager.class);
4842
connectionManager = mock(ConnectionManager.class);
4943
messageHandler = mock(MessageHandler.class);
50-
threadPoolResource = mock(ThreadPoolResource.class);
5144

5245
mockedClient.when(() -> buildChannelHandler(any(), any())).thenReturn(channelHandler);
5346
mockedClient.when(() -> buildConnectionManager(channelHandler)).thenReturn(connectionManager);
5447
mockedClient.when(() -> buildCommandManager(channelHandler)).thenReturn(commandManager);
5548
mockedClient.when(() -> buildMessageHandler(any())).thenReturn(messageHandler);
5649
mockedClient.when(() -> createClient(any(), any())).thenCallRealMethod();
57-
58-
var threadPoolResource = ThreadPoolResourceAllocator.getOrCreate(() -> null);
59-
if (threadPoolResource != null) {
60-
threadPoolResource.getEventLoopGroup().shutdownGracefully();
61-
ThreadPoolResourceAllocator.getOrCreate(() -> null);
62-
}
6350
}
6451

6552
@AfterEach
@@ -86,46 +73,5 @@ public void createClient_with_default_config_successfully_returns_GlideClient()
8673
assertEquals(commandManager, client.commandManager);
8774
}
8875

89-
@Test
90-
@SneakyThrows
91-
public void createClient_with_custom_config_successfully_returns_GlideClient() {
92-
// setup
93-
CompletableFuture<Void> connectToValkeyFuture = new CompletableFuture<>();
94-
connectToValkeyFuture.complete(null);
95-
GlideClientConfiguration config =
96-
GlideClientConfiguration.builder().threadPoolResource(threadPoolResource).build();
97-
98-
when(connectionManager.connectToValkey(eq(config))).thenReturn(connectToValkeyFuture);
99-
100-
// exercise
101-
CompletableFuture<GlideClient> result = createClient(config);
102-
GlideClient client = result.get();
103-
104-
// verify
105-
assertEquals(connectionManager, client.connectionManager);
106-
assertEquals(commandManager, client.commandManager);
107-
}
108-
109-
@SneakyThrows
110-
@Test
111-
public void createClient_error_on_connection_throws_ExecutionException() {
112-
// setup
113-
CompletableFuture<Void> connectToValkeyFuture = new CompletableFuture<>();
114-
ClosingException exception = new ClosingException("disconnected");
115-
connectToValkeyFuture.completeExceptionally(exception);
116-
GlideClientConfiguration config =
117-
GlideClientConfiguration.builder().threadPoolResource(threadPoolResource).build();
118-
119-
when(connectionManager.connectToValkey(eq(config))).thenReturn(connectToValkeyFuture);
120-
121-
// exercise
122-
CompletableFuture<GlideClient> result = createClient(config);
123-
124-
ExecutionException executionException = assertThrows(ExecutionException.class, result::get);
125-
126-
// verify
127-
assertEquals(exception, executionException.getCause());
128-
}
129-
13076
// TODO check message queue and subscriptionConfiguration
13177
}

java/integTest/build.gradle

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,12 @@ dependencies {
1515
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0'
1616
implementation 'com.google.code.gson:gson:2.10.1'
1717

18-
// https://github.com/netty/netty/wiki/Native-transports
19-
// At the moment, Windows is not supported
20-
implementation group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.121.Final', classifier: 'linux-x86_64'
21-
implementation group: 'io.netty', name: 'netty-transport-native-kqueue', version: '4.1.121.Final', classifier: 'osx-x86_64'
22-
implementation group: 'io.netty', name: 'netty-transport-native-kqueue', version: '4.1.121.Final', classifier: 'osx-aarch_64'
23-
2418
// junit
2519
testImplementation 'org.mockito:mockito-junit-jupiter:3.12.4'
2620
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.10.2'
2721

2822
// semver4j for semantic versioning
29-
implementation 'com.vdurmont:semver4j:3.1.0'
23+
implementation group: 'org.semver4j', name: 'semver4j', version: '5.6.0'
3024

3125
//lombok
3226
testCompileOnly 'org.projectlombok:lombok:1.18.32'

0 commit comments

Comments
 (0)