diff --git a/servicetalk-grpc-protoc/gradle/checkstyle/suppressions.xml b/servicetalk-grpc-protoc/gradle/checkstyle/suppressions.xml index 417dd87b76..018924837f 100644 --- a/servicetalk-grpc-protoc/gradle/checkstyle/suppressions.xml +++ b/servicetalk-grpc-protoc/gradle/checkstyle/suppressions.xml @@ -21,4 +21,5 @@ + diff --git a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java index 5295b3147e..9350679810 100644 --- a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java +++ b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java @@ -17,6 +17,7 @@ import com.google.protobuf.DescriptorProtos; import com.google.protobuf.DescriptorProtos.DescriptorProto; +import com.google.protobuf.DescriptorProtos.EnumDescriptorProto; import com.google.protobuf.DescriptorProtos.FileDescriptorProto; import com.google.protobuf.DescriptorProtos.FileOptions; import com.google.protobuf.DescriptorProtos.MethodDescriptorProto; @@ -47,23 +48,24 @@ * A single protoc file for which we will be generating classes */ final class FileDescriptor implements GenerationContext { - private static final String GENERATED_BY_COMMENT = "Generated by ServiceTalk proto compiler"; - + private static final String GENERATED_BY_COMMENT = "Generated by ServiceTalk gRPC protoc plugin"; + /** + * Inferred behavior from protobuf-java is that if no suffix is explicitly provided the root file name will have + * this suffix. See + * java_name_resolver.cc + */ + private static final String OUTER_CLASS_SUFFIX = "OuterClass"; private final FileDescriptorProto protoFile; - private final String sanitizedProtoFileName; @Nullable private final String protoPackageName; private final boolean deprecated; private final boolean multipleClassFiles; - @Nullable private final String javaPackageName; - @Nullable private final String outerClassName; @Nullable private final String typeNameSuffix; private final List serviceClassBuilders; - @Nullable - private Set reservedJavaTypeName; + private final Set reservedJavaTypeName = new HashSet<>(); /** * A single protoc file for which we will be generating classes @@ -74,7 +76,7 @@ final class FileDescriptor implements GenerationContext { FileDescriptor(final FileDescriptorProto protoFile, @Nullable final String typeNameSuffix) { this.protoFile = protoFile; - sanitizedProtoFileName = sanitizeFileName(protoFile.getName()); + final String sanitizedProtoFileName = sanitizeFileName(protoFile.getName()); protoPackageName = protoFile.hasPackage() ? protoFile.getPackage() : null; this.typeNameSuffix = typeNameSuffix; @@ -82,14 +84,18 @@ final class FileDescriptor implements GenerationContext { final FileOptions fileOptions = protoFile.getOptions(); deprecated = fileOptions.hasDeprecated() && fileOptions.getDeprecated(); multipleClassFiles = fileOptions.hasJavaMultipleFiles() && fileOptions.getJavaMultipleFiles(); - javaPackageName = fileOptions.hasJavaPackage() ? fileOptions.getJavaPackage() : null; - outerClassName = fileOptions.hasJavaOuterClassname() ? fileOptions.getJavaOuterClassname() : null; + javaPackageName = fileOptions.hasJavaPackage() ? fileOptions.getJavaPackage() : + inferJavaPackageName(protoPackageName, sanitizedProtoFileName); + outerClassName = fileOptions.hasJavaOuterClassname() ? + sanitizeClassName(fileOptions.getJavaOuterClassname()) : + inferOuterClassName(sanitizedProtoFileName, protoFile); } else { deprecated = false; multipleClassFiles = false; - javaPackageName = null; - outerClassName = null; + javaPackageName = inferJavaPackageName(protoPackageName, sanitizedProtoFileName); + outerClassName = inferOuterClassName(sanitizedProtoFileName, protoFile); } + reservedJavaTypeName.add(outerClassName); serviceClassBuilders = new ArrayList<>(protoFile.getServiceCount()); } @@ -115,26 +121,21 @@ DescriptorProtos.SourceCodeInfo sourceCodeInfo() { } private void addMessageTypes(final List messageTypes, - @Nullable String parentProtoScope, - @Nullable String parentJavaScope, + final @Nullable String parentProtoScope, + final String parentJavaScope, final Map messageTypesMap) { - messageTypes.forEach(t -> { - final String protoTypeName = (parentProtoScope != null ? parentProtoScope : "") + '.' + t.getName(); - final String javaClassName = parentJavaScope + '.' + t.getName(); - messageTypesMap.put(protoTypeName, ClassName.bestGuess(javaClassName)); + final String protoTypeName = parentProtoScope != null ? + (parentProtoScope + '.' + t.getName()) : '.' + t.getName(); + final ClassName className = ClassName.get(parentJavaScope, t.getName()); + messageTypesMap.put(protoTypeName, className); - addMessageTypes(t.getNestedTypeList(), protoTypeName, javaClassName, messageTypesMap); + addMessageTypes(t.getNestedTypeList(), protoTypeName, className.canonicalName(), messageTypesMap); }); } @Override public String deconflictJavaTypeName(final String name) { - if (reservedJavaTypeName == null) { - reservedJavaTypeName = new HashSet<>(); - reservedJavaTypeName.add(outerJavaClassName()); - } - if (reservedJavaTypeName.add(name)) { return name; } @@ -227,13 +228,63 @@ private static void insertSingleFileContent(final String content, String fileNam } private String outerJavaClassName() { - return isNotNullNorEmpty(outerClassName) ? sanitizeClassName(outerClassName) : - sanitizeClassName(sanitizedProtoFileName); + return outerClassName; } private String javaPackageName() { - return isNotNullNorEmpty(javaPackageName) ? javaPackageName : - isNotNullNorEmpty(protoPackageName) ? protoPackageName : sanitizeClassName(sanitizedProtoFileName); + return javaPackageName; + } + + private static String inferOuterClassName(String sanitizedProtoFileName, FileDescriptorProto protoFile) { + final String sanitizeClassName = sanitizeClassName(sanitizedProtoFileName); + return hasConflictingClassName(sanitizeClassName, protoFile) ? + sanitizeClassName + OUTER_CLASS_SUFFIX : sanitizeClassName; + } + + /** + * See java_name_resolver.cc. + * @param sanitizedClassName The sanitized classname to check for conflicts. + * @param protoFile The {@link FileDescriptorProto} to search for conflicting names in. + * @return {@code true} if there is a name conflict, {@code false} otherwise. + */ + private static boolean hasConflictingClassName(String sanitizedClassName, FileDescriptorProto protoFile) { + for (EnumDescriptorProto enumDescriptor : protoFile.getEnumTypeList()) { + if (enumDescriptor.getName().equals(sanitizedClassName)) { + return true; + } + } + for (ServiceDescriptorProto serviceDescriptor : protoFile.getServiceList()) { + if (serviceDescriptor.getName().equals(sanitizedClassName)) { + return true; + } + } + for (DescriptorProto typeDescriptor : protoFile.getMessageTypeList()) { + if (hasConflictingClassName(sanitizedClassName, typeDescriptor)) { + return true; + } + } + return false; + } + + private static boolean hasConflictingClassName(String sanitizedClassName, DescriptorProto typeDescriptor) { + if (typeDescriptor.getName().equals(sanitizedClassName)) { + return true; + } + for (DescriptorProto nestedTypeDescriptor : typeDescriptor.getNestedTypeList()) { + if (hasConflictingClassName(sanitizedClassName, nestedTypeDescriptor)) { + return true; + } + } + for (EnumDescriptorProto enumDescriptor : typeDescriptor.getEnumTypeList()) { + if (enumDescriptor.getName().equals(sanitizedClassName)) { + return true; + } + } + return false; + } + + private static String inferJavaPackageName(@Nullable String protoPackageName, String sanitizedProtoFileName) { + return isNotNullNorEmpty(protoPackageName) ? protoPackageName : sanitizeClassName(sanitizedProtoFileName); } private static String sanitizeFileName(final String v) { diff --git a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Types.java b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Types.java index 78651df314..6feaebe0f4 100644 --- a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Types.java +++ b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Types.java @@ -44,78 +44,80 @@ final class Types { private static final ClassName Collection = ClassName.get("java.util", "Collection"); static final ClassName RouteExecutionStrategy = - bestGuess(routerApiPkg + ".RouteExecutionStrategy"); + ClassName.get(routerApiPkg, "RouteExecutionStrategy"); static final ClassName RouteExecutionStrategyFactory = - bestGuess(routerApiPkg + ".RouteExecutionStrategyFactory"); + ClassName.get(routerApiPkg, "RouteExecutionStrategyFactory"); - static final ClassName BlockingIterable = bestGuess(concurrentPkg + ".BlockingIterable"); + static final ClassName BlockingIterable = ClassName.get(concurrentPkg, "BlockingIterable"); - static final ClassName AsyncCloseable = bestGuess(concurrentApiPkg + ".AsyncCloseable"); - static final ClassName Completable = bestGuess(concurrentApiPkg + ".Completable"); - static final ClassName Publisher = bestGuess(concurrentApiPkg + ".Publisher"); - static final ClassName Single = bestGuess(concurrentApiPkg + ".Single"); + static final ClassName AsyncCloseable = ClassName.get(concurrentApiPkg, "AsyncCloseable"); + static final ClassName Completable = ClassName.get(concurrentApiPkg, "Completable"); + static final ClassName Publisher = ClassName.get(concurrentApiPkg, "Publisher"); + static final ClassName Single = ClassName.get(concurrentApiPkg, "Single"); - static final ClassName BlockingGrpcClient = bestGuess(grpcApiPkg + ".BlockingGrpcClient"); - static final ClassName BlockingGrpcService = bestGuess(grpcApiPkg + ".BlockingGrpcService"); - static final ClassName GrpcClientMetadata = bestGuess(grpcApiPkg + ".GrpcClientMetadata"); - static final ClassName DefaultGrpcClientMetadata = bestGuess(grpcApiPkg + ".DefaultGrpcClientMetadata"); - static final ClassName GrpcClient = bestGuess(grpcApiPkg + ".GrpcClient"); - static final ClassName GrpcClientCallFactory = bestGuess(grpcApiPkg + ".GrpcClientCallFactory"); - static final ClassName GrpcClientFactory = bestGuess(grpcApiPkg + ".GrpcClientFactory"); - static final ClassName GrpcExecutionContext = bestGuess(grpcApiPkg + ".GrpcExecutionContext"); - static final ClassName GrpcExecutionStrategy = bestGuess(grpcApiPkg + ".GrpcExecutionStrategy"); - static final ClassName GrpcStatusException = bestGuess(grpcApiPkg + ".GrpcStatusException"); - static final ClassName Identity = bestGuess(encodingApiPkg + ".Identity"); - static final ClassName BufferDecoderGroup = bestGuess(encodingApiPkg + ".BufferDecoderGroup"); - static final ClassName EmptyBufferDecoderGroup = bestGuess(encodingApiPkg + ".EmptyBufferDecoderGroup"); - static final ClassName BufferEncoder = bestGuess(encodingApiPkg + ".BufferEncoder"); + static final ClassName BlockingGrpcClient = ClassName.get(grpcApiPkg, "BlockingGrpcClient"); + static final ClassName BlockingGrpcService = ClassName.get(grpcApiPkg, "BlockingGrpcService"); + static final ClassName GrpcClientMetadata = ClassName.get(grpcApiPkg, "GrpcClientMetadata"); + static final ClassName DefaultGrpcClientMetadata = ClassName.get(grpcApiPkg, "DefaultGrpcClientMetadata"); + static final ClassName GrpcClient = ClassName.get(grpcApiPkg, "GrpcClient"); + static final ClassName GrpcClientCallFactory = ClassName.get(grpcApiPkg, "GrpcClientCallFactory"); + static final ClassName GrpcClientFactory = ClassName.get(grpcApiPkg, "GrpcClientFactory"); + static final ClassName GrpcExecutionContext = ClassName.get(grpcApiPkg, "GrpcExecutionContext"); + static final ClassName GrpcExecutionStrategy = ClassName.get(grpcApiPkg, "GrpcExecutionStrategy"); + static final ClassName GrpcStatusException = ClassName.get(grpcApiPkg, "GrpcStatusException"); + static final ClassName Identity = ClassName.get(encodingApiPkg, "Identity"); + static final ClassName BufferDecoderGroup = ClassName.get(encodingApiPkg, "BufferDecoderGroup"); + static final ClassName EmptyBufferDecoderGroup = ClassName.get(encodingApiPkg, "EmptyBufferDecoderGroup"); + static final ClassName BufferEncoder = ClassName.get(encodingApiPkg, "BufferEncoder"); static final TypeName BufferEncoderList = ParameterizedTypeName.get(List, BufferEncoder); - static final ClassName ContentCodec = bestGuess(encodingApiPkg + ".ContentCodec"); + static final ClassName ContentCodec = ClassName.get(encodingApiPkg, "ContentCodec"); static final TypeName GrpcSupportedCodings = ParameterizedTypeName.get(List, ContentCodec); - static final ClassName GrpcPayloadWriter = bestGuess(grpcApiPkg + ".GrpcPayloadWriter"); - static final ClassName GrpcRoutes = bestGuess(grpcApiPkg + ".GrpcRoutes"); - static final ClassName GrpcSerializationProvider = bestGuess(grpcApiPkg + ".GrpcSerializationProvider"); - static final ClassName GrpcBindableService = bestGuess(grpcApiPkg + ".GrpcBindableService"); - static final ClassName GrpcService = bestGuess(grpcApiPkg + ".GrpcService"); - static final ClassName GrpcServiceContext = bestGuess(grpcApiPkg + ".GrpcServiceContext"); - static final ClassName GrpcServiceFactory = bestGuess(grpcApiPkg + ".GrpcServiceFactory"); - static final ClassName GrpcMethodDescriptor = bestGuess(grpcApiPkg + ".MethodDescriptor"); - static final ClassName GrpcMethodDescriptors = bestGuess(grpcApiPkg + ".MethodDescriptors"); + static final ClassName GrpcPayloadWriter = ClassName.get(grpcApiPkg, "GrpcPayloadWriter"); + static final ClassName GrpcRoutes = ClassName.get(grpcApiPkg, "GrpcRoutes"); + static final ClassName GrpcSerializationProvider = ClassName.get(grpcApiPkg, "GrpcSerializationProvider"); + static final ClassName GrpcBindableService = ClassName.get(grpcApiPkg, "GrpcBindableService"); + static final ClassName GrpcService = ClassName.get(grpcApiPkg, "GrpcService"); + static final ClassName GrpcServiceContext = ClassName.get(grpcApiPkg, "GrpcServiceContext"); + static final ClassName GrpcServiceFactory = ClassName.get(grpcApiPkg, "GrpcServiceFactory"); + static final ClassName GrpcMethodDescriptor = ClassName.get(grpcApiPkg, "MethodDescriptor"); + static final ClassName GrpcMethodDescriptors = ClassName.get(grpcApiPkg, "MethodDescriptors"); static final ParameterizedTypeName GrpcMethodDescriptorCollection = ParameterizedTypeName.get(Collection, ParameterizedTypeName.get(GrpcMethodDescriptor, Wildcard, Wildcard)); - static final ClassName BlockingClientCall = bestGuess(GrpcClientCallFactory + ".BlockingClientCall"); + static final ClassName BlockingClientCall = GrpcClientCallFactory.nestedClass("BlockingClientCall"); static final ClassName BlockingRequestStreamingClientCall = - bestGuess(GrpcClientCallFactory + ".BlockingRequestStreamingClientCall"); + GrpcClientCallFactory.nestedClass("BlockingRequestStreamingClientCall"); static final ClassName BlockingResponseStreamingClientCall = - bestGuess(GrpcClientCallFactory + ".BlockingResponseStreamingClientCall"); + GrpcClientCallFactory.nestedClass("BlockingResponseStreamingClientCall"); static final ClassName BlockingStreamingClientCall = - bestGuess(GrpcClientCallFactory + ".BlockingStreamingClientCall"); - static final ClassName ClientCall = bestGuess(GrpcClientCallFactory + ".ClientCall"); + GrpcClientCallFactory.nestedClass("BlockingStreamingClientCall"); + static final ClassName ClientCall = GrpcClientCallFactory.nestedClass("ClientCall"); static final ClassName RequestStreamingClientCall = - bestGuess(GrpcClientCallFactory + ".RequestStreamingClientCall"); + GrpcClientCallFactory.nestedClass("RequestStreamingClientCall"); static final ClassName ResponseStreamingClientCall = - bestGuess(GrpcClientCallFactory + ".ResponseStreamingClientCall"); - static final ClassName StreamingClientCall = bestGuess(GrpcClientCallFactory + ".StreamingClientCall"); + GrpcClientCallFactory.nestedClass("ResponseStreamingClientCall"); + static final ClassName StreamingClientCall = GrpcClientCallFactory.nestedClass("StreamingClientCall"); + // Inner protected types need bestGuess to avoid adding imports which aren't visible and causing compile problems. static final ClassName AllGrpcRoutes = bestGuess(grpcRoutesFqcn + ".AllGrpcRoutes"); static final ClassName RequestStreamingRoute = bestGuess(grpcRoutesFqcn + ".RequestStreamingRoute"); static final ClassName ResponseStreamingRoute = bestGuess(grpcRoutesFqcn + ".ResponseStreamingRoute"); static final ClassName Route = bestGuess(grpcRoutesFqcn + ".Route"); static final ClassName StreamingRoute = bestGuess(grpcRoutesFqcn + ".StreamingRoute"); - static final ClassName BlockingRequestStreamingRoute = bestGuess(grpcRoutesFqcn + ".BlockingRequestStreamingRoute"); - static final ClassName BlockingResponseStreamingRoute = bestGuess(grpcRoutesFqcn + - ".BlockingResponseStreamingRoute"); + static final ClassName BlockingRequestStreamingRoute = + bestGuess(grpcRoutesFqcn + ".BlockingRequestStreamingRoute"); + static final ClassName BlockingResponseStreamingRoute = + bestGuess(grpcRoutesFqcn + ".BlockingResponseStreamingRoute"); static final ClassName BlockingRoute = bestGuess(grpcRoutesFqcn + ".BlockingRoute"); static final ClassName BlockingStreamingRoute = bestGuess(grpcRoutesFqcn + ".BlockingStreamingRoute"); @Deprecated static final ClassName ProtoBufSerializationProviderBuilder = - bestGuess(grpcProtobufPkg + ".ProtoBufSerializationProviderBuilder"); - static final ClassName ProtobufSerializerFactory = bestGuess(protobufDataPkg + ".ProtobufSerializerFactory"); + ClassName.get(grpcProtobufPkg, "ProtoBufSerializationProviderBuilder"); + static final ClassName ProtobufSerializerFactory = ClassName.get(protobufDataPkg, "ProtobufSerializerFactory"); - static final TypeName GrpcRouteExecutionStrategyFactory = ParameterizedTypeName.get(RouteExecutionStrategyFactory, - GrpcExecutionStrategy); + static final TypeName GrpcRouteExecutionStrategyFactory = + ParameterizedTypeName.get(RouteExecutionStrategyFactory, GrpcExecutionStrategy); private Types() { // no instances diff --git a/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictEnum.java b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictEnum.java new file mode 100644 index 0000000000..862265d96b --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictEnum.java @@ -0,0 +1,71 @@ +/* + * Copyright © 2022 Apple Inc. and the ServiceTalk project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.servicetalk.grpc.protoc; + +import io.servicetalk.concurrent.api.Single; +import io.servicetalk.grpc.api.GrpcServiceContext; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnum2OuterClass.TestConflictEnum2Resp; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnum2OuterClass.TestConflictEnum2Service.TestConflictEnum2ServiceService; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnum3Resp; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnum3Service.TestConflictEnum3ServiceService; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnumInsideOuterClass.TestConflictEnumInside.TestConflictEnumInsideService; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnumInsideOuterClass.TestConflictEnumInsideResp; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnumReq; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnumResp; +import io.servicetalk.grpc.protoc.test.conflict.enums.TestConflictEnumService.TestConflictEnumServiceService; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ExecutionException; + +import static io.servicetalk.concurrent.api.Single.succeeded; + +class TestConflictEnum { + @Test + void enumConflict() throws ExecutionException, InterruptedException { + new TestConflictEnumServiceService() { + @Override + public Single doNothingRpc( + final GrpcServiceContext ctx, final TestConflictEnumReq request) { + return succeeded(TestConflictEnumResp.newBuilder().build()); + } + + @Override + public Single doNothing( + final GrpcServiceContext ctx, final TestConflictEnumReq request) { + return succeeded(TestConflictEnumResp.newBuilder().build()); + } + }.closeAsync().toFuture().get(); + } + + @Test + void enum2Conflict() throws ExecutionException, InterruptedException { + ((TestConflictEnum2ServiceService) (ctx, request) -> succeeded(TestConflictEnum2Resp.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void enum3Conflict() throws ExecutionException, InterruptedException { + ((TestConflictEnum3ServiceService) (ctx, request) -> succeeded(TestConflictEnum3Resp.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void enumInsideConflict() throws ExecutionException, InterruptedException { + ((TestConflictEnumInsideService) (ctx, request) -> succeeded(TestConflictEnumInsideResp.newBuilder().build())) + .closeAsync().toFuture().get(); + } +} diff --git a/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMessage.java b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMessage.java new file mode 100644 index 0000000000..8e97a8a589 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMessage.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2022 Apple Inc. and the ServiceTalk project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.servicetalk.grpc.protoc; + +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictMessageOuterClass.TestConflictMessageService.TestConflictMessageServiceService; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictMessageOuterClass.TestConflictResp; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictMessageService2.TestConflictMessageService2Service; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictMessageService3.TestConflictMessageService3Service; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictResp2; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictResp3; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ExecutionException; + +import static io.servicetalk.concurrent.api.Single.succeeded; + +class TestConflictMessage { + @Test + void messageConflict() throws ExecutionException, InterruptedException { + ((TestConflictMessageServiceService) (ctx, request) -> succeeded(TestConflictResp.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void message2Conflict() throws ExecutionException, InterruptedException { + ((TestConflictMessageService2Service) (ctx, request) -> succeeded(TestConflictResp2.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void message3Conflict() throws ExecutionException, InterruptedException { + ((TestConflictMessageService3Service) (ctx, request) -> succeeded(TestConflictResp3.newBuilder().build())) + .closeAsync().toFuture().get(); + } +} diff --git a/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMultiService.java b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMultiService.java index 98f99876a3..3d1ca9b444 100644 --- a/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMultiService.java +++ b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictMultiService.java @@ -16,7 +16,7 @@ package io.servicetalk.grpc.protoc; import io.servicetalk.concurrent.api.Single; -import io.servicetalk.grpc.protoc.test.conflict.multi.service.TestConflictMultiService0.TestConflictMultiServiceService; +import io.servicetalk.grpc.protoc.test.conflict.multi.service.TestConflictMultiService.TestConflictMultiServiceService; import io.servicetalk.grpc.protoc.test.conflict.multi.service.TestReply; import org.junit.jupiter.api.Test; diff --git a/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictService.java b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictService.java index d637403b37..2fa63fee00 100644 --- a/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictService.java +++ b/servicetalk-grpc-protoc/src/test/java/io/servicetalk/grpc/protoc/TestConflictService.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Apple Inc. and the ServiceTalk project authors + * Copyright © 2020, 2022 Apple Inc. and the ServiceTalk project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,74 @@ package io.servicetalk.grpc.protoc; import io.servicetalk.concurrent.api.Single; +import io.servicetalk.grpc.api.GrpcServiceContext; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictMessageService2.TestConflictMessageService2Service; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictMessageService3.TestConflictMessageService3Service; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictResp2; +import io.servicetalk.grpc.protoc.test.conflict.message.TestConflictResp3; import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService.TestConflict.TestConflictService0; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService4OuterClass.TestConflictService4.TestConflictService4Service; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService4OuterClass.TestConflictService4Resp; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService5.TestConflictService50.TestConflictService5Service; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService5.testConflictService5Req; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService5.testConflictService5Resp; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService5.test_conflict_service_5_req; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService5.test_conflict_service_5_resp; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictServiceOuterClassOuterClass.TestConflictServiceOuterClass.TestConflictServiceOuterClassService; +import io.servicetalk.grpc.protoc.test.conflict.service.TestConflictServiceOuterClassOuterClass.TestConflictServiceOuterServiceResp; import org.junit.jupiter.api.Test; import java.util.concurrent.ExecutionException; +import static io.servicetalk.concurrent.api.Single.succeeded; import static io.servicetalk.grpc.protoc.test.conflict.service.TestConflictService.TestReply; class TestConflictService { @Test - void conflictRpcServiceGenerated() throws ExecutionException, InterruptedException { - TestConflictService0 service = (ctx, request) -> Single.succeeded(TestReply.newBuilder().build()); - + void conflictServiceGenerated() throws ExecutionException, InterruptedException { + TestConflictService0 service = (ctx, request) -> succeeded(TestReply.newBuilder().build()); service.closeAsync().toFuture().get(); } + + @Test + void conflict2ServiceGenerated() throws ExecutionException, InterruptedException { + ((TestConflictMessageService2Service) (ctx, request) -> succeeded(TestConflictResp2.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void conflict3ServiceGenerated() throws ExecutionException, InterruptedException { + ((TestConflictMessageService3Service) (ctx, request) -> succeeded(TestConflictResp3.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void conflict4ServiceGenerated() throws ExecutionException, InterruptedException { + ((TestConflictService4Service) (ctx, request) -> succeeded(TestConflictService4Resp.newBuilder().build())) + .closeAsync().toFuture().get(); + } + + @Test + void conflict5ServiceGenerated() throws ExecutionException, InterruptedException { + new TestConflictService5Service() { + @Override + public Single doNothing2( + final GrpcServiceContext ctx, final test_conflict_service_5_req request) { + return succeeded(test_conflict_service_5_resp.newBuilder().build()); + } + + @Override + public Single doNothing( + final GrpcServiceContext ctx, final testConflictService5Req request) { + return succeeded(testConflictService5Resp.newBuilder().build()); + } + }.closeAsync().toFuture().get(); + } + + @Test + void conflictOuterServiceGenerated() throws ExecutionException, InterruptedException { + ((TestConflictServiceOuterClassService) (ctx, request) -> + succeeded(TestConflictServiceOuterServiceResp.newBuilder().build())).closeAsync().toFuture().get(); + } } diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum.proto new file mode 100644 index 0000000000..261db8bd14 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum.proto @@ -0,0 +1,41 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test file name conflicts with a top level enum -> generate code into the right location +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.enums"; + +// No java_outer_classname provided to make sure the inferred outer classname doesn't clash +// with the generated TestConflictMultiService inner interface + +service TestConflictEnumService { + rpc DoNothing (TestConflictEnumReq) returns (TestConflictEnumResp); + // This name will conflict with internal generated interface. + rpc DoNothingRpc (TestConflictEnumReq) returns (TestConflictEnumResp); +} + +enum TestConflictEnum { // This name conflicts with the file name! + A = 0; +} + +message DoNothingRpc {} // This name will conflict with internal generated interface. + +message TestConflictEnumReq { + TestConflictEnum enum = 1; +} + +message TestConflictEnumResp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum2.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum2.proto new file mode 100644 index 0000000000..6e5b1853ee --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum2.proto @@ -0,0 +1,34 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test file name conflicts with a top level enum -> generate code into the right location +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.enums"; + +service TestConflictEnum2Service { + rpc DoNothing (TestConflictEnum2Req) returns (TestConflictEnum2Resp); +} + +enum TestConflictEnum2 { // This name conflicts with the file name! + A2 = 0; +} + +message TestConflictEnum2Req { + TestConflictEnum2 enum = 1; +} + +message TestConflictEnum2Resp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum3.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum3.proto new file mode 100644 index 0000000000..e992d7948d --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum3.proto @@ -0,0 +1,36 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test file name conflicts with a top level enum -> generate code into the right location +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.enums"; + +service TestConflictEnum3Service { + rpc DoNothing (TestConflictEnum3Req) returns (TestConflictEnum3Resp); +} + +// todo(scott): make first char lowercase +// https://github.com/protocolbuffers/protobuf/issues/9653 +enum TestConflictEnum3 { // This name conflicts with the file name! + A3 = 0; +} + +message TestConflictEnum3Req { + TestConflictEnum3 enum = 1; +} + +message TestConflictEnum3Resp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum_inside.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum_inside.proto new file mode 100644 index 0000000000..dbeb871088 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_enum_inside.proto @@ -0,0 +1,33 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test file name conflicts with a top level enum -> generate code into the right location +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.enums"; + +service TestConflictEnumInside { + rpc DoNothing (TestConflictEnumInsideReq) returns (TestConflictEnumInsideResp); +} + +message TestConflictEnumInsideReq { + enum TestConflictEnumInside { // This name conflicts with the file name! + A2 = 0; + } + TestConflictEnumInside enum = 1; +} + +message TestConflictEnumInsideResp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_message.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_message.proto new file mode 100644 index 0000000000..554b6a97d2 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_message.proto @@ -0,0 +1,30 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test file name conflicts with a top level message -> generate code into the right location +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.message"; + +// No java_outer_classname provided to make sure the inferred outer classname doesn't clash +// with the generated TestConflictMultiService inner interface + +service TestConflictMessageService { + rpc DoNothing (TestConflictMessage) returns (TestConflictResp); +} + +message TestConflictMessage {} // This name conflicts with the file name! +message TestConflictResp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_message2.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_message2.proto new file mode 100644 index 0000000000..9246fd2206 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_message2.proto @@ -0,0 +1,29 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.message"; + +// No java_outer_classname provided to make sure the inferred outer classname doesn't clash +// with the generated type names. + +service TestConflictMessageService2 { + rpc DoNothing (TestConflictMessage2) returns (TestConflictResp2); +} + +message TestConflictMessage2 {} // This name conflicts with the file name! +message TestConflictResp2 {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_message3.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_message3.proto new file mode 100644 index 0000000000..afe9c08490 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_message3.proto @@ -0,0 +1,31 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.message"; + +// No java_outer_classname provided to make sure the inferred outer classname doesn't clash +// with the generated type names. + +service TestConflictMessageService3 { + rpc DoNothing (TestConflictMessage3) returns (TestConflictResp3); +} + +// todo(scott): make first char lowercase +// https://github.com/protocolbuffers/protobuf/issues/9653 +message TestConflictMessage3 {} // This name conflicts with the file name! +message TestConflictResp3 {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_service2.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service2.proto new file mode 100644 index 0000000000..2e59db1688 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service2.proto @@ -0,0 +1,26 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.service"; + +service TestConflictService2 { + rpc DoNothing (TestConflictService2Req) returns (TestConflictService2Resp); +} + +message TestConflictService2Req {} +message TestConflictService2Resp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_service3.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service3.proto new file mode 100644 index 0000000000..c194badb3c --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service3.proto @@ -0,0 +1,26 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.service"; + +service TestConflictService3 { + rpc DoNothing (TestConflictService3Req) returns (TestConflictService3Resp); +} + +message TestConflictService3Req {} +message TestConflictService3Resp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_service4.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service4.proto new file mode 100644 index 0000000000..f9a3d4ec67 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service4.proto @@ -0,0 +1,26 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.service"; + +service TestConflictService4 { + rpc DoNothing (TestConflictService4Service) returns (TestConflictService4Resp); +} + +message TestConflictService4Service {} // Conflicts with the name of the generated type. +message TestConflictService4Resp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_service5.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service5.proto new file mode 100644 index 0000000000..430d3fbcc4 --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service5.proto @@ -0,0 +1,29 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.service"; + +service testConflictService5 { + rpc DoNothing (testConflictService5Req) returns (testConflictService5Resp); + rpc DoNothing2 (test_conflict_service_5_req) returns (test_conflict_service_5_resp); +} + +message testConflictService5Req {} +message test_conflict_service_5_req {} +message testConflictService5Resp {} +message test_conflict_service_5_resp {} \ No newline at end of file diff --git a/servicetalk-grpc-protoc/src/test/proto/test_conflict_service_outer_class.proto b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service_outer_class.proto new file mode 100644 index 0000000000..09419882bd --- /dev/null +++ b/servicetalk-grpc-protoc/src/test/proto/test_conflict_service_outer_class.proto @@ -0,0 +1,26 @@ +// +// Copyright © 2022 Apple Inc. and the ServiceTalk project authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = false; +option java_package = "io.servicetalk.grpc.protoc.test.conflict.service"; + +service TestConflictServiceOuterClass { + rpc DoNothing (TestConflictServiceOuterServiceReq) returns (TestConflictServiceOuterServiceResp); +} + +message TestConflictServiceOuterServiceReq {} +message TestConflictServiceOuterServiceResp {} \ No newline at end of file