Skip to content

Commit e1af859

Browse files
committed
Port base changes from hackathon-2022-extension-methods branch
1 parent ae7047c commit e1af859

22 files changed

Lines changed: 1015 additions & 0 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.model.config.customization;
17+
18+
/**
19+
* Whether the service has API extensions defined apart from the service model.
20+
*/
21+
public class ClientExtensions {
22+
23+
private boolean sync = false;
24+
private boolean async = false;
25+
26+
public boolean getSync() {
27+
return sync;
28+
}
29+
30+
public void setSync(boolean sync) {
31+
this.sync = sync;
32+
}
33+
34+
public boolean getAsync() {
35+
return async;
36+
}
37+
38+
public void setAsync(boolean async) {
39+
this.async = async;
40+
}
41+
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ public class CustomizationConfig {
249249
*/
250250
private String asyncClientDecorator;
251251

252+
/**
253+
* If the client has API extensions to include.
254+
*/
255+
private ClientExtensions clientExtensions;
256+
252257
/**
253258
* Only for s3. A set of customization to related to multipart operations.
254259
*/
@@ -746,6 +751,14 @@ public void setAsyncClientDecorator(String asyncClientDecorator) {
746751
this.asyncClientDecorator = asyncClientDecorator;
747752
}
748753

754+
public ClientExtensions getClientExtensions() {
755+
return clientExtensions;
756+
}
757+
758+
public void setClientExtensions(ClientExtensions clientExtensions) {
759+
this.clientExtensions = clientExtensions;
760+
}
761+
749762
public boolean isDelegateSyncClientClass() {
750763
return delegateSyncClientClass;
751764
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public final class PoetUtils {
3737
.addMember("value", "$S", "software.amazon.awssdk:codegen")
3838
.build();
3939

40+
private static final String EXTENSION_PACKAGE = ".extensions";
41+
private static final String EXTENSION_INTERFACE_SUFFIX = "SdkExtension";
42+
4043
private PoetUtils() {
4144
}
4245

@@ -108,4 +111,10 @@ public static JavaFile buildJavaFile(ClassSpec spec) {
108111
spec.staticImports().forEach(i -> i.memberNames().forEach(m -> builder.addStaticImport(i.className(), m)));
109112
return builder.build();
110113
}
114+
115+
public static ClassName extensionInterfaceClassName(ClassName clientInterfaceName) {
116+
String packageName = clientInterfaceName.packageName() + EXTENSION_PACKAGE;
117+
String className = clientInterfaceName.simpleName() + EXTENSION_INTERFACE_SUFFIX;
118+
return ClassName.get(packageName, className);
119+
}
111120
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static javax.lang.model.element.Modifier.PUBLIC;
2222
import static javax.lang.model.element.Modifier.STATIC;
2323
import static software.amazon.awssdk.codegen.internal.Constant.ASYNC_STREAMING_INPUT_PARAM;
24+
import static software.amazon.awssdk.codegen.poet.PoetUtils.extensionInterfaceClassName;
2425
import static software.amazon.awssdk.codegen.internal.Constant.EVENT_PUBLISHER_PARAM_NAME;
2526
import static software.amazon.awssdk.codegen.internal.Constant.EVENT_RESPONSE_HANDLER_PARAM_NAME;
2627

@@ -35,6 +36,7 @@
3536
import java.util.ArrayList;
3637
import java.util.Comparator;
3738
import java.util.List;
39+
import java.util.Optional;
3840
import java.util.concurrent.CompletableFuture;
3941
import java.util.stream.Stream;
4042
import org.reactivestreams.Publisher;
@@ -47,6 +49,8 @@
4749
import software.amazon.awssdk.codegen.docs.SimpleMethodOverload;
4850
import software.amazon.awssdk.codegen.docs.WaiterDocs;
4951
import software.amazon.awssdk.codegen.model.config.customization.AdditionalBuilderMethod;
52+
import software.amazon.awssdk.codegen.model.config.customization.ClientExtensions;
53+
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
5054
import software.amazon.awssdk.codegen.model.config.customization.UtilitiesMethod;
5155
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
5256
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -111,6 +115,8 @@ protected TypeSpec.Builder createTypeSpec() {
111115

112116
protected void addInterfaceClass(TypeSpec.Builder type) {
113117
type.addSuperinterface(AwsClient.class);
118+
Optional<ClassName> extensionInterface = findExtensionInterface(className, model.getCustomizationConfig());
119+
extensionInterface.ifPresent(type::addSuperinterface);
114120
}
115121

116122
protected void addAnnotations(TypeSpec.Builder type) {
@@ -551,4 +557,13 @@ protected MethodSpec.Builder batchManagerOperationBody(MethodSpec.Builder builde
551557
.addStatement("throw new $T()", UnsupportedOperationException.class);
552558
}
553559

560+
private static Optional<ClassName> findExtensionInterface(ClassName clientInterfaceName,
561+
CustomizationConfig customizationConfig) {
562+
ClientExtensions clientExtensions = customizationConfig.getClientExtensions();
563+
if (clientExtensions != null && clientExtensions.getAsync()) {
564+
return Optional.of(extensionInterfaceClassName(clientInterfaceName));
565+
}
566+
return Optional.empty();
567+
}
568+
554569
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientInterface.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static software.amazon.awssdk.codegen.internal.Constant.SYNC_CLIENT_SOURCE_PATH_PARAM_NAME;
2626
import static software.amazon.awssdk.codegen.internal.Constant.SYNC_STREAMING_INPUT_PARAM;
2727
import static software.amazon.awssdk.codegen.internal.Constant.SYNC_STREAMING_OUTPUT_PARAM;
28+
import static software.amazon.awssdk.codegen.poet.PoetUtils.extensionInterfaceClassName;
2829
import static software.amazon.awssdk.codegen.poet.client.AsyncClientInterface.STREAMING_TYPE_VARIABLE;
2930

3031
import com.squareup.javapoet.ClassName;
@@ -38,6 +39,7 @@
3839
import java.util.ArrayList;
3940
import java.util.Collections;
4041
import java.util.List;
42+
import java.util.Optional;
4143
import java.util.function.Consumer;
4244
import java.util.stream.Stream;
4345
import software.amazon.awssdk.annotations.SdkPublicApi;
@@ -49,6 +51,8 @@
4951
import software.amazon.awssdk.codegen.docs.DocConfiguration;
5052
import software.amazon.awssdk.codegen.docs.SimpleMethodOverload;
5153
import software.amazon.awssdk.codegen.docs.WaiterDocs;
54+
import software.amazon.awssdk.codegen.model.config.customization.ClientExtensions;
55+
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
5256
import software.amazon.awssdk.codegen.model.config.customization.UtilitiesMethod;
5357
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
5458
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -102,6 +106,8 @@ public final TypeSpec poetSpec() {
102106

103107
protected void addInterfaceClass(TypeSpec.Builder type) {
104108
type.addSuperinterface(AwsClient.class);
109+
Optional<ClassName> extensionInterface = findExtensionInterface(className, model.getCustomizationConfig());
110+
extensionInterface.ifPresent(type::addSuperinterface);
105111
}
106112

107113
protected TypeSpec.Builder createTypeSpec() {
@@ -559,4 +565,13 @@ protected MethodSpec.Builder waiterOperationBody(MethodSpec.Builder builder) {
559565
return builder.addModifiers(DEFAULT, PUBLIC)
560566
.addStatement("throw new $T()", UnsupportedOperationException.class);
561567
}
568+
569+
private static Optional<ClassName> findExtensionInterface(ClassName clientInterfaceName,
570+
CustomizationConfig customizationConfig) {
571+
ClientExtensions clientExtensions = customizationConfig.getClientExtensions();
572+
if (clientExtensions != null && clientExtensions.getSync()) {
573+
return Optional.of(extensionInterfaceClassName(clientInterfaceName));
574+
}
575+
return Optional.empty();
576+
}
562577
}

codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,18 @@ public static IntermediateModel batchManagerModels() {
606606
return new IntermediateModelBuilder(models).build();
607607
}
608608

609+
public static IntermediateModel clientExtensionModels() {
610+
File serviceModel = new File(ClientTestModels.class.getResource("client/c2j/clientextensions/service-2.json").getFile());
611+
File customizationModel = new File(ClientTestModels.class.getResource("client/c2j/clientextensions/customization.config").getFile());
612+
613+
C2jModels models = C2jModels.builder()
614+
.serviceModel(getServiceModel(serviceModel))
615+
.customizationConfig(getCustomizationConfig(customizationModel))
616+
.build();
617+
618+
return new IntermediateModelBuilder(models).build();
619+
}
620+
609621
private static ServiceModel getServiceModel(File file) {
610622
return ModelLoaderUtils.loadModel(ServiceModel.class, file);
611623
}

codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterfaceTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static org.hamcrest.MatcherAssert.assertThat;
1919
import static software.amazon.awssdk.codegen.poet.ClientTestModels.batchManagerModels;
20+
import static software.amazon.awssdk.codegen.poet.ClientTestModels.clientExtensionModels;
2021
import static software.amazon.awssdk.codegen.poet.ClientTestModels.restJsonServiceModels;
2122
import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo;
2223

@@ -35,4 +36,10 @@ public void asyncClientInterfaceWithBatchManager() {
3536
ClassSpec asyncClientInterface = new AsyncClientInterface(batchManagerModels());
3637
assertThat(asyncClientInterface, generatesTo("test-json-async-client-interface-batchmanager.java"));
3738
}
39+
40+
@Test
41+
public void asyncClientInterfaceClientExtensions() {
42+
ClassSpec asyncClientInterface = new AsyncClientInterface(clientExtensionModels());
43+
assertThat(asyncClientInterface, generatesTo("test-clientextensions-async-interface.java"));
44+
}
3845
}

codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/SyncClientInterfaceTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package software.amazon.awssdk.codegen.poet.client;
1717

1818
import static org.hamcrest.MatcherAssert.assertThat;
19+
import static software.amazon.awssdk.codegen.poet.ClientTestModels.clientExtensionModels;
1920
import static software.amazon.awssdk.codegen.poet.ClientTestModels.restJsonServiceModels;
2021
import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo;
2122

@@ -28,4 +29,10 @@ public void syncClientInterface() {
2829
ClassSpec syncClientInterface = new SyncClientInterface(restJsonServiceModels());
2930
assertThat(syncClientInterface, generatesTo("test-json-client-interface.java"));
3031
}
32+
33+
@Test
34+
public void syncClientInterfaceClientExtensions() {
35+
ClassSpec syncClientInterface = new SyncClientInterface(clientExtensionModels());
36+
assertThat(syncClientInterface, generatesTo("test-clientextensions-sync-interface.java"));
37+
}
3138
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.poet.utils;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import com.squareup.javapoet.ClassName;
21+
import org.junit.jupiter.api.Test;
22+
import software.amazon.awssdk.codegen.poet.PoetUtils;
23+
24+
/**
25+
* Validate functionality of {@link PoetUtils} methods.
26+
*/
27+
public class PoetUtilsTest {
28+
29+
@Test
30+
public void findExtensionInterface_whenNotExists_returnEmpty() {
31+
ClassName clientName = ClassName.get("software.amazon.awssdk.sdkservice", "SdkServiceClient");
32+
ClassName extensionClass = PoetUtils.extensionInterfaceClassName(clientName);
33+
assertThat(extensionClass).isNotNull();
34+
assertThat(extensionClass.canonicalName())
35+
.isEqualTo("software.amazon.awssdk.sdkservice.extensions.SdkServiceClientSdkExtension");
36+
}
37+
38+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"clientExtensions": {
3+
"sync": true,
4+
"async": true
5+
}
6+
}

0 commit comments

Comments
 (0)