20
20
import com .google .api .generator .gapic .model .Message ;
21
21
import com .google .api .generator .gapic .model .MethodArgument ;
22
22
import com .google .api .generator .gapic .model .ResourceName ;
23
+ import com .google .common .annotations .VisibleForTesting ;
23
24
import com .google .common .base .Preconditions ;
25
+ import com .google .common .collect .Lists ;
24
26
import com .google .protobuf .Descriptors .MethodDescriptor ;
25
27
import java .util .ArrayList ;
26
28
import java .util .Arrays ;
@@ -56,40 +58,89 @@ public static List<List<MethodArgument>> parseMethodSignatures(
56
58
Message inputMessage = messageTypes .get (methodInputTypeName );
57
59
58
60
// Example from Expand in echo.proto:
59
- // Input: ["content,error", "content,error,info"].
60
- // Output: [["content", "error"], ["content", "error", "info"]].
61
+ // stringSigs: ["content,error", "content,error,info"].
61
62
for (String stringSig : stringSigs ) {
62
- List <MethodArgument > arguments = new ArrayList <>();
63
- for (String argumentName : stringSig .split (METHOD_SIGNATURE_DELIMITER )) {
64
- List <TypeNode > argumentTypePath =
65
- new ArrayList <>(
66
- parseTypeFromArgumentName (
67
- argumentName ,
68
- servicePackage ,
69
- inputMessage ,
70
- messageTypes ,
71
- resourceNames ,
72
- patternsToResourceNames ,
73
- outputArgResourceNames ));
63
+ List <String > argumentNames = new ArrayList <>();
64
+ Map <String , List <MethodArgument >> argumentNameToOverloads = new HashMap <>();
74
65
66
+ // stringSig.split: ["content", "error"].
67
+ for (String argumentName : stringSig .split (METHOD_SIGNATURE_DELIMITER )) {
68
+ // For resource names, this will be empty.
69
+ List <TypeNode > argumentTypePathAcc = new ArrayList <>();
70
+ // There should be more than one type returned only when we encounter a reousrce name.
71
+ List <TypeNode > argumentTypes =
72
+ parseTypeFromArgumentName (
73
+ argumentName ,
74
+ servicePackage ,
75
+ inputMessage ,
76
+ messageTypes ,
77
+ resourceNames ,
78
+ patternsToResourceNames ,
79
+ argumentTypePathAcc ,
80
+ outputArgResourceNames );
75
81
int dotLastIndex = argumentName .lastIndexOf (DOT );
76
82
String actualArgumentName =
77
83
dotLastIndex < 0 ? argumentName : argumentName .substring (dotLastIndex + 1 );
84
+ argumentNames .add (actualArgumentName );
85
+ argumentNameToOverloads .put (
86
+ actualArgumentName ,
87
+ argumentTypes .stream ()
88
+ .map (
89
+ type ->
90
+ MethodArgument .builder ()
91
+ .setName (actualArgumentName )
92
+ .setType (type )
93
+ .setIsResourceNameHelper (
94
+ argumentTypes .size () > 1 && !type .equals (TypeNode .STRING ))
95
+ .setNestedTypes (argumentTypePathAcc )
96
+ .build ())
97
+ .collect (Collectors .toList ()));
98
+ }
99
+ signatures .addAll (flattenMethodSignatureVariants (argumentNames , argumentNameToOverloads ));
100
+ }
101
+ return signatures ;
102
+ }
78
103
79
- int typeLastIndex = argumentTypePath .size () - 1 ;
80
- TypeNode argumentType = argumentTypePath .get (typeLastIndex );
81
- argumentTypePath .remove (typeLastIndex );
104
+ @ VisibleForTesting
105
+ static List <List <MethodArgument >> flattenMethodSignatureVariants (
106
+ List <String > argumentNames , Map <String , List <MethodArgument >> argumentNameToOverloads ) {
107
+ Preconditions .checkState (
108
+ argumentNames .size () == argumentNameToOverloads .size (),
109
+ String .format (
110
+ "Cardinality of argument names %s do not match that of overloaded types %s" ,
111
+ argumentNames , argumentNameToOverloads ));
112
+ for (String name : argumentNames ) {
113
+ Preconditions .checkNotNull (
114
+ argumentNameToOverloads .get (name ),
115
+ String .format ("No corresponding overload types found for argument %s" , name ));
116
+ }
117
+ return flattenMethodSignatureVariants (argumentNames , argumentNameToOverloads , 0 );
118
+ }
82
119
83
- arguments .add (
84
- MethodArgument .builder ()
85
- .setName (actualArgumentName )
86
- .setType (argumentType )
87
- .setNestedTypes (argumentTypePath )
88
- .build ());
120
+ private static List <List <MethodArgument >> flattenMethodSignatureVariants (
121
+ List <String > argumentNames ,
122
+ Map <String , List <MethodArgument >> argumentNameToOverloads ,
123
+ int depth ) {
124
+ List <List <MethodArgument >> methodArgs = new ArrayList <>();
125
+ if (depth >= argumentNames .size () - 1 ) {
126
+ for (MethodArgument methodArg : argumentNameToOverloads .get (argumentNames .get (depth ))) {
127
+ methodArgs .add (Lists .newArrayList (methodArg ));
89
128
}
90
- signatures . add ( arguments ) ;
129
+ return methodArgs ;
91
130
}
92
- return signatures ;
131
+
132
+ List <List <MethodArgument >> subsequentArgs =
133
+ flattenMethodSignatureVariants (argumentNames , argumentNameToOverloads , depth + 1 );
134
+ for (MethodArgument methodArg : argumentNameToOverloads .get (argumentNames .get (depth ))) {
135
+ for (List <MethodArgument > subsequentArg : subsequentArgs ) {
136
+ // Use a new list to avoid appending all subsequent elements (in upcoming loop iterations)
137
+ // to the same list.
138
+ List <MethodArgument > appendedArgs = new ArrayList <>(subsequentArg );
139
+ appendedArgs .add (0 , methodArg );
140
+ methodArgs .add (appendedArgs );
141
+ }
142
+ }
143
+ return methodArgs ;
93
144
}
94
145
95
146
private static List <TypeNode > parseTypeFromArgumentName (
@@ -99,35 +150,33 @@ private static List<TypeNode> parseTypeFromArgumentName(
99
150
Map <String , Message > messageTypes ,
100
151
Map <String , ResourceName > resourceNames ,
101
152
Map <String , ResourceName > patternsToResourceNames ,
153
+ List <TypeNode > argumentTypePathAcc ,
102
154
Set <ResourceName > outputArgResourceNames ) {
103
- return parseTypeFromArgumentName (
104
- argumentName ,
105
- servicePackage ,
106
- inputMessage ,
107
- messageTypes ,
108
- resourceNames ,
109
- patternsToResourceNames ,
110
- outputArgResourceNames ,
111
- new ArrayList <>());
112
- }
113
155
114
- private static List <TypeNode > parseTypeFromArgumentName (
115
- String argumentName ,
116
- String servicePackage ,
117
- Message inputMessage ,
118
- Map <String , Message > messageTypes ,
119
- Map <String , ResourceName > resourceNames ,
120
- Map <String , ResourceName > patternsToResourceNames ,
121
- Set <ResourceName > outputArgResourceNames ,
122
- List <TypeNode > typeAcc ) {
123
156
int dotIndex = argumentName .indexOf (DOT );
124
- // TODO(miraleung): Fake out resource names here.
125
157
if (dotIndex < 1 ) {
126
158
Field field = inputMessage .fieldMap ().get (argumentName );
127
159
Preconditions .checkNotNull (
128
- field , String .format ("Field %s not found, %s" , argumentName , inputMessage .fieldMap ()));
129
- return Arrays .asList (field .type ());
160
+ field ,
161
+ String .format (
162
+ "Field %s not found from input message %s values %s" ,
163
+ argumentName , inputMessage .name (), inputMessage .fieldMap ().keySet ()));
164
+ if (!field .hasResourceReference ()) {
165
+ return Arrays .asList (field .type ());
166
+ }
167
+
168
+ // Parse the resource name tyeps.
169
+ List <ResourceName > resourceNameArgs =
170
+ ResourceReferenceParser .parseResourceNames (
171
+ field .resourceReference (), servicePackage , resourceNames , patternsToResourceNames );
172
+ outputArgResourceNames .addAll (resourceNameArgs );
173
+ List <TypeNode > allFieldTypes = new ArrayList <>();
174
+ allFieldTypes .add (TypeNode .STRING );
175
+ allFieldTypes .addAll (
176
+ resourceNameArgs .stream ().map (r -> r .type ()).collect (Collectors .toList ()));
177
+ return allFieldTypes ;
130
178
}
179
+
131
180
Preconditions .checkState (
132
181
dotIndex < argumentName .length () - 1 ,
133
182
String .format (
@@ -137,16 +186,6 @@ private static List<TypeNode> parseTypeFromArgumentName(
137
186
138
187
// Must be a sub-message for a type's subfield to be valid.
139
188
Field firstField = inputMessage .fieldMap ().get (firstFieldName );
140
- if (firstField .hasResourceReference ()) {
141
- List <ResourceName > resourceNameArgs =
142
- ResourceReferenceParser .parseResourceNames (
143
- firstField .resourceReference (),
144
- servicePackage ,
145
- resourceNames ,
146
- patternsToResourceNames );
147
- outputArgResourceNames .addAll (resourceNameArgs );
148
- return resourceNameArgs .stream ().map (r -> r .type ()).collect (Collectors .toList ());
149
- }
150
189
151
190
Preconditions .checkState (
152
191
!firstField .isRepeated (),
@@ -164,17 +203,16 @@ private static List<TypeNode> parseTypeFromArgumentName(
164
203
String .format (
165
204
"Message type %s for field reference %s invalid" , firstFieldTypeName , firstFieldName ));
166
205
167
- List <TypeNode > newAcc = new ArrayList <>(typeAcc );
168
- newAcc .add (firstFieldType );
206
+ argumentTypePathAcc .add (firstFieldType );
169
207
return parseTypeFromArgumentName (
170
208
remainingArgumentName ,
171
209
servicePackage ,
172
210
firstFieldMessage ,
173
211
messageTypes ,
174
212
resourceNames ,
175
213
patternsToResourceNames ,
176
- outputArgResourceNames ,
177
- newAcc );
214
+ argumentTypePathAcc ,
215
+ outputArgResourceNames );
178
216
}
179
217
180
218
private static Map <String , ResourceName > createPatternResourceNameMap (
0 commit comments