17
17
18
18
package software .amazon .smithy .go .codegen ;
19
19
20
+ import java .util .List ;
20
21
import java .util .Map ;
22
+ import java .util .Optional ;
21
23
import java .util .logging .Logger ;
22
24
import software .amazon .smithy .codegen .core .CodegenException ;
23
25
import software .amazon .smithy .codegen .core .Symbol ;
32
34
import software .amazon .smithy .model .node .NumberNode ;
33
35
import software .amazon .smithy .model .node .ObjectNode ;
34
36
import software .amazon .smithy .model .node .StringNode ;
37
+ import software .amazon .smithy .model .shapes .MapShape ;
35
38
import software .amazon .smithy .model .shapes .MemberShape ;
36
39
import software .amazon .smithy .model .shapes .Shape ;
37
40
import software .amazon .smithy .model .shapes .ShapeType ;
38
41
import software .amazon .smithy .model .shapes .SimpleShape ;
39
42
import software .amazon .smithy .model .shapes .StructureShape ;
40
43
import software .amazon .smithy .model .shapes .UnionShape ;
41
44
import software .amazon .smithy .model .traits .EnumTrait ;
45
+ import software .amazon .smithy .model .traits .HttpPrefixHeadersTrait ;
42
46
import software .amazon .smithy .model .traits .StreamingTrait ;
47
+ import software .amazon .smithy .model .traits .Trait ;
48
+ import software .amazon .smithy .utils .ListUtils ;
49
+ import software .amazon .smithy .utils .OptionalUtils ;
50
+ import software .amazon .smithy .utils .SmithyBuilder ;
43
51
44
52
/**
45
53
* Generates a shape type declaration based on the parameters provided.
46
54
*/
47
55
public final class ShapeValueGenerator {
48
56
private static final Logger LOGGER = Logger .getLogger (ShapeValueGenerator .class .getName ());
49
57
50
- protected final Model model ;
51
- protected final SymbolProvider symbolProvider ;
52
- protected final GoPointableIndex pointableIndex ;
58
+ private final Model model ;
59
+ private final SymbolProvider symbolProvider ;
60
+ private final GoPointableIndex pointableIndex ;
61
+ private final Config config ;
53
62
54
63
/**
55
64
* Initializes a shape value generator.
@@ -58,9 +67,21 @@ public final class ShapeValueGenerator {
58
67
* @param symbolProvider the symbol provider.
59
68
*/
60
69
public ShapeValueGenerator (Model model , SymbolProvider symbolProvider ) {
70
+ this (model , symbolProvider , Config .builder ().build ());
71
+ }
72
+
73
+ /**
74
+ * Initializes a shape value generator.
75
+ *
76
+ * @param model the Smithy model references.
77
+ * @param symbolProvider the symbol provider.
78
+ * @param config the shape value generator config.
79
+ */
80
+ public ShapeValueGenerator (Model model , SymbolProvider symbolProvider , Config config ) {
61
81
this .model = model ;
62
82
this .symbolProvider = symbolProvider ;
63
83
this .pointableIndex = GoPointableIndex .of (model );
84
+ this .config = config ;
64
85
}
65
86
66
87
/**
@@ -79,7 +100,8 @@ public void writePointableStructureShapeValueInline(GoWriter writer, StructureSh
79
100
// not within the context of a member shape reference.
80
101
Symbol symbol = symbolProvider .toSymbol (shape );
81
102
writer .write ("&$T{" , symbol );
82
- params .accept (new ShapeValueNodeVisitor (writer , this , shape ));
103
+ params .accept (new ShapeValueNodeVisitor (writer , this , shape , ListUtils .copyOf (shape .getAllTraits ().values ()),
104
+ config ));
83
105
writer .writeInline ("}" );
84
106
}
85
107
@@ -149,7 +171,8 @@ protected void structDeclShapeValue(GoWriter writer, MemberShape member, Node pa
149
171
150
172
String addr = CodegenUtils .asAddressIfAddressable (model , pointableIndex , member , "" );
151
173
writer .write ("$L$T{" , addr , symbol );
152
- params .accept (new ShapeValueNodeVisitor (writer , this , model .expectShape (member .getTarget ())));
174
+ params .accept (new ShapeValueNodeVisitor (writer , this , model .expectShape (member .getTarget ()),
175
+ ListUtils .copyOf (member .getAllTraits ().values ()), config ));
153
176
writer .writeInline ("}" );
154
177
}
155
178
@@ -197,7 +220,8 @@ protected void unionDeclShapeValue(GoWriter writer, MemberShape member, ObjectNo
197
220
*/
198
221
protected void listDeclShapeValue (GoWriter writer , MemberShape member , Node params ) {
199
222
writer .write ("$P{" , symbolProvider .toSymbol (member ));
200
- params .accept (new ShapeValueNodeVisitor (writer , this , model .expectShape (member .getTarget ())));
223
+ params .accept (new ShapeValueNodeVisitor (writer , this , model .expectShape (member .getTarget ()),
224
+ ListUtils .copyOf (member .getAllTraits ().values ()), config ));
201
225
writer .writeInline ("}" );
202
226
}
203
227
@@ -210,7 +234,8 @@ protected void listDeclShapeValue(GoWriter writer, MemberShape member, Node para
210
234
*/
211
235
protected void mapDeclShapeValue (GoWriter writer , MemberShape member , Node params ) {
212
236
writer .write ("$P{" , symbolProvider .toSymbol (member ));
213
- params .accept (new ShapeValueNodeVisitor (writer , this , model .expectShape (member .getTarget ())));
237
+ params .accept (new ShapeValueNodeVisitor (writer , this , model .expectShape (member .getTarget ()),
238
+ ListUtils .copyOf (member .getAllTraits ().values ()), config ));
214
239
writer .writeInline ("}" );
215
240
}
216
241
@@ -327,17 +352,58 @@ protected void writeScalarValueInline(GoWriter writer, MemberShape member, Node
327
352
break ;
328
353
}
329
354
330
- params .accept (new ShapeValueNodeVisitor (writer , this , target ));
355
+ params .accept (new ShapeValueNodeVisitor (writer , this , target ,
356
+ ListUtils .copyOf (member .getAllTraits ().values ()), config ));
331
357
writer .writeInline (closing );
332
358
}
333
359
360
+ /**
361
+ * Configuration that determines how shapes values are generated.
362
+ */
363
+ public static final class Config {
364
+ private final boolean normalizeHttpPrefixHeaderKeys ;
365
+
366
+ private Config (Builder builder ) {
367
+ normalizeHttpPrefixHeaderKeys = builder .normalizeHttpPrefixHeaderKeys ;
368
+ }
369
+
370
+ public static Builder builder () {
371
+ return new Builder ();
372
+ }
373
+
374
+ /**
375
+ * Returns whether maps with the httpPrefixHeader trait should have their keys normalized.
376
+ *
377
+ * @return whether to normalize http prefix header keys
378
+ */
379
+ public boolean isNormalizeHttpPrefixHeaderKeys () {
380
+ return normalizeHttpPrefixHeaderKeys ;
381
+ }
382
+
383
+ public static final class Builder implements SmithyBuilder <Config > {
384
+ private boolean normalizeHttpPrefixHeaderKeys ;
385
+
386
+ public Builder normalizeHttpPrefixHeaderKeys (boolean normalizeHttpPrefixHeaderKeys ) {
387
+ this .normalizeHttpPrefixHeaderKeys = normalizeHttpPrefixHeaderKeys ;
388
+ return this ;
389
+ }
390
+
391
+ @ Override
392
+ public Config build () {
393
+ return new Config (this );
394
+ }
395
+ }
396
+ }
397
+
334
398
/**
335
399
* NodeVisitor to walk shape value declarations with node values.
336
400
*/
337
401
private final class ShapeValueNodeVisitor implements NodeVisitor <Void > {
338
- GoWriter writer ;
339
- ShapeValueGenerator valueGen ;
340
- Shape currentShape ;
402
+ private final GoWriter writer ;
403
+ private final ShapeValueGenerator valueGen ;
404
+ private final Shape currentShape ;
405
+ private final List <Trait > traits ;
406
+ private final Config config ;
341
407
342
408
/**
343
409
* Initializes shape value visitor.
@@ -347,9 +413,42 @@ private final class ShapeValueNodeVisitor implements NodeVisitor<Void> {
347
413
* @param shape the shape that visiting is relative to.
348
414
*/
349
415
private ShapeValueNodeVisitor (GoWriter writer , ShapeValueGenerator valueGen , Shape shape ) {
416
+ this (writer , valueGen , shape , ListUtils .of ());
417
+ }
418
+
419
+ /**
420
+ * Initializes shape value visitor.
421
+ *
422
+ * @param writer writer to write generated code with.
423
+ * @param valueGen shape value generator.
424
+ * @param shape the shape that visiting is relative to.
425
+ * @param traits the traits applied to the target shape by a MemberShape.
426
+ */
427
+ private ShapeValueNodeVisitor (GoWriter writer , ShapeValueGenerator valueGen , Shape shape , List <Trait > traits ) {
428
+ this (writer , valueGen , shape , traits , Config .builder ().build ());
429
+ }
430
+
431
+ /**
432
+ * Initializes shape value visitor.
433
+ *
434
+ * @param writer writer to write generated code with.
435
+ * @param valueGen shape value generator.
436
+ * @param shape the shape that visiting is relative to.
437
+ * @param traits the traits applied to the target shape by a MemberShape.
438
+ * @param config the shape value generator config.
439
+ */
440
+ private ShapeValueNodeVisitor (
441
+ GoWriter writer ,
442
+ ShapeValueGenerator valueGen ,
443
+ Shape shape ,
444
+ List <Trait > traits ,
445
+ Config config
446
+ ) {
350
447
this .writer = writer ;
351
448
this .valueGen = valueGen ;
352
449
this .currentShape = shape ;
450
+ this .traits = traits ;
451
+ this .config = config ;
353
452
}
354
453
355
454
/**
@@ -395,10 +494,18 @@ public Void objectNode(ObjectNode node) {
395
494
break ;
396
495
397
496
case MAP :
398
- member = this .currentShape .asMapShape ().get ().getValue ();
497
+ MapShape mapShape = this .currentShape .asMapShape ().get ();
498
+
499
+ String keyValue = keyNode .getValue ();
500
+ if (config .isNormalizeHttpPrefixHeaderKeys ()) {
501
+ keyValue = OptionalUtils .or (getTrait (HttpPrefixHeadersTrait .class ),
502
+ () -> mapShape .getTrait (HttpPrefixHeadersTrait .class ))
503
+ .map (httpPrefixHeadersTrait -> keyNode .getValue ().toLowerCase ())
504
+ .orElse (keyValue );
505
+ }
399
506
400
- writer .write ("$S: " , keyNode . getValue () );
401
- valueGen .writeMemberValueInline (writer , member , valueNode );
507
+ writer .write ("$S: " , keyValue );
508
+ valueGen .writeMemberValueInline (writer , mapShape . getValue () , valueNode );
402
509
writer .write ("," );
403
510
break ;
404
511
@@ -523,6 +630,15 @@ private void writeInlineBigIntegerInit(GoWriter writer, Object value) {
523
630
+ "}()" ,
524
631
value , value );
525
632
}
633
+
634
+ private <T extends Trait > Optional <T > getTrait (Class <T > traitClass ) {
635
+ for (Trait trait : traits ) {
636
+ if (traitClass .isInstance (trait )) {
637
+ return Optional .of ((T ) trait );
638
+ }
639
+ }
640
+ return Optional .empty ();
641
+ }
526
642
}
527
643
528
644
}
0 commit comments