11package com .github .wassertim .dynamodb .toolkit .generation ;
22
3- import java .io .PrintWriter ;
4-
3+ import com .palantir .javapoet .*;
54import com .github .wassertim .dynamodb .toolkit .analysis .TypeInfo ;
5+ import software .amazon .awssdk .services .dynamodb .model .AttributeValue ;
6+ import java .util .*;
7+ import java .util .stream .Collectors ;
8+ import javax .lang .model .element .Modifier ;
69
710/**
11+ * JavaPoet-based convenience methods generator for mapper classes.
812 * Generates convenience methods for mapper classes to reduce boilerplate code.
913 * Provides common patterns like converting lists of DynamoDB items to domain objects.
1014 */
1115public class ConvenienceMethodGenerator {
1216
1317 /**
14- * Generates convenience methods for common DynamoDB operations.
18+ * Generates convenience methods for common DynamoDB operations using JavaPoet .
1519 */
16- public void generateConvenienceMethods (PrintWriter writer , TypeInfo typeInfo ) {
20+ public List < MethodSpec > generateConvenienceMethods (TypeInfo typeInfo ) {
1721 String className = typeInfo .getClassName ();
22+ ClassName attributeValue = ClassName .get (AttributeValue .class );
23+ ClassName domainClass = ClassName .bestGuess (className );
1824
19- writer .println (" // Convenience methods for reducing boilerplate" );
20- writer .println ();
25+ List <MethodSpec > methods = new ArrayList <>();
26+ methods .add (generateFromDynamoDbItemMethod (className , domainClass , attributeValue ));
27+ methods .add (generateFromDynamoDbItemsMethod (className , domainClass , attributeValue ));
28+ methods .add (generateToDynamoDbItemMethod (className , domainClass , attributeValue ));
29+ methods .add (generateToDynamoDbItemsMethod (className , domainClass , attributeValue ));
30+ return methods ;
31+ }
2132
22- generateFromDynamoDbItemMethod (writer , className );
23- generateFromDynamoDbItemsMethod (writer , className );
24- generateToDynamoDbItemMethod (writer , className );
25- generateToDynamoDbItemsMethod (writer , className );
33+ private MethodSpec generateFromDynamoDbItemMethod (String className , ClassName domainClass , ClassName attributeValue ) {
34+ return MethodSpec .methodBuilder ("fromDynamoDbItem" )
35+ .addModifiers (Modifier .PUBLIC )
36+ .returns (ParameterizedTypeName .get (ClassName .get ("java.util" , "Optional" ), domainClass ))
37+ .addParameter (ParameterizedTypeName .get (
38+ ClassName .get (Map .class ),
39+ ClassName .get (String .class ),
40+ attributeValue ), "item" )
41+ .addJavadoc ("Convenience method to convert a single DynamoDB item to a domain object.\n " )
42+ .addJavadoc ("Handles the common pattern of mapping GetItemResponse.item() to domain objects.\n " )
43+ .addJavadoc ("\n " )
44+ .addJavadoc ("@param item DynamoDB item from GetItemResponse.item()\n " )
45+ .addJavadoc ("@return Optional of $L object, empty if item is null or conversion fails\n " , className )
46+ .beginControlFlow ("if (item == null || item.isEmpty())" )
47+ .addStatement ("return $T.empty()" , ClassName .get ("java.util" , "Optional" ))
48+ .endControlFlow ()
49+ .addStatement ("$T result = fromDynamoDbAttributeValue($T.builder().m(item).build())" ,
50+ domainClass , attributeValue )
51+ .addStatement ("return $T.ofNullable(result)" , ClassName .get ("java.util" , "Optional" ))
52+ .build ();
2653 }
2754
28- private void generateFromDynamoDbItemMethod (PrintWriter writer , String className ) {
29- writer .println (" /**" );
30- writer .println (" * Convenience method to convert a single DynamoDB item to a domain object." );
31- writer .println (" * Handles the common pattern of mapping GetItemResponse.item() to domain objects." );
32- writer .println (" *" );
33- writer .println (" * @param item DynamoDB item from GetItemResponse.item()" );
34- writer .println (" * @return Optional of " + className + " object, empty if item is null or conversion fails" );
35- writer .println (" */" );
36- writer .println (" public java.util.Optional<" + className + "> fromDynamoDbItem(Map<String, AttributeValue> item) {" );
37- writer .println (" if (item == null || item.isEmpty()) {" );
38- writer .println (" return java.util.Optional.empty();" );
39- writer .println (" }" );
40- writer .println (" " + className + " result = fromDynamoDbAttributeValue(AttributeValue.builder().m(item).build());" );
41- writer .println (" return java.util.Optional.ofNullable(result);" );
42- writer .println (" }" );
43- writer .println ();
55+ private MethodSpec generateFromDynamoDbItemsMethod (String className , ClassName domainClass , ClassName attributeValue ) {
56+ return MethodSpec .methodBuilder ("fromDynamoDbItems" )
57+ .addModifiers (Modifier .PUBLIC )
58+ .returns (ParameterizedTypeName .get (ClassName .get (List .class ), domainClass ))
59+ .addParameter (ParameterizedTypeName .get (
60+ ClassName .get (List .class ),
61+ ParameterizedTypeName .get (
62+ ClassName .get (Map .class ),
63+ ClassName .get (String .class ),
64+ attributeValue )), "items" )
65+ .addJavadoc ("Convenience method to convert a list of DynamoDB items to domain objects.\\ n" )
66+ .addJavadoc ("Handles the common pattern of mapping QueryResponse.items() to domain objects.\\ n" )
67+ .addJavadoc ("\\ n" )
68+ .addJavadoc ("@param items List of DynamoDB items from QueryResponse.items() or ScanResponse.items()\\ n" )
69+ .addJavadoc ("@return List of $L objects, filtering out any null results\\ n" , className )
70+ .beginControlFlow ("if (items == null || items.isEmpty())" )
71+ .addStatement ("return new $T<>()" , ClassName .get ("java.util" , "ArrayList" ))
72+ .endControlFlow ()
73+ .addStatement ("return items.stream()" )
74+ .addStatement (" .map(item -> $T.builder().m(item).build())" , attributeValue )
75+ .addStatement (" .map(this::fromDynamoDbAttributeValue)" )
76+ .addStatement (" .filter($T::nonNull)" , ClassName .get (Objects .class ))
77+ .addStatement (" .collect($T.toList())" , ClassName .get (Collectors .class ))
78+ .build ();
4479 }
4580
46- private void generateFromDynamoDbItemsMethod ( PrintWriter writer , String className ) {
47- writer . println ( " /**" );
48- writer . println ( " * Convenience method to convert a list of DynamoDB items to domain objects." );
49- writer . println ( " * Handles the common pattern of mapping QueryResponse.items() to domain objects." );
50- writer . println ( " *" );
51- writer . println ( " * @param items List of DynamoDB items from QueryResponse.items() or ScanResponse.items()" );
52- writer . println ( " * @return List of " + className + " objects, filtering out any null results" );
53- writer . println ( " */" );
54- writer . println ( " public List<" + className + "> fromDynamoDbItems(List<Map<String, AttributeValue>> items) {" );
55- writer . println ( " if (items == null || items.isEmpty()) {" );
56- writer . println ( " return new ArrayList<>();" );
57- writer . println ( " }" );
58- writer . println ( " return items.stream()" );
59- writer . println ( " .map(item -> AttributeValue.builder().m(item).build())" );
60- writer . println ( " .map(this::fromDynamoDbAttributeValue)" );
61- writer . println ( " .filter(Objects::nonNull)" );
62- writer . println ( " .collect(Collectors.toList());" );
63- writer . println ( " }" );
64- writer . println ();
81+ private MethodSpec generateToDynamoDbItemMethod ( String className , ClassName domainClass , ClassName attributeValue ) {
82+ return MethodSpec . methodBuilder ( "toDynamoDbItem" )
83+ . addModifiers ( Modifier . PUBLIC )
84+ . returns ( ParameterizedTypeName . get (
85+ ClassName . get ( Map . class ),
86+ ClassName . get ( String . class ),
87+ attributeValue ))
88+ . addParameter ( domainClass , "object" )
89+ . addJavadoc ( "Convenience method to convert a single domain object to a DynamoDB item. \\ n" )
90+ . addJavadoc ( "Useful for PutItem operations. \\ n" )
91+ . addJavadoc ( " \\ n" )
92+ . addJavadoc ( "@param object The $L object to convert \\ n" , className )
93+ . addJavadoc ( "@ return DynamoDB item (Map<String, AttributeValue>), or null if input is null or conversion fails \\ n" )
94+ . beginControlFlow ( "if (object == null)" )
95+ . addStatement ( "return null" )
96+ . endControlFlow ()
97+ . addStatement ( "$T av = toDynamoDbAttributeValue(object)" , attributeValue )
98+ . addStatement ( "return av != null ? av.m() : null" )
99+ . build ();
65100 }
66101
67- private void generateToDynamoDbItemMethod (PrintWriter writer , String className ) {
68- writer .println (" /**" );
69- writer .println (" * Convenience method to convert a single domain object to a DynamoDB item." );
70- writer .println (" * Useful for PutItem operations." );
71- writer .println (" *" );
72- writer .println (" * @param object The " + className + " object to convert" );
73- writer .println (" * @return DynamoDB item (Map<String, AttributeValue>), or null if input is null or conversion fails" );
74- writer .println (" */" );
75- writer .println (" public Map<String, AttributeValue> toDynamoDbItem(" + className + " object) {" );
76- writer .println (" if (object == null) {" );
77- writer .println (" return null;" );
78- writer .println (" }" );
79- writer .println (" AttributeValue av = toDynamoDbAttributeValue(object);" );
80- writer .println (" return av != null ? av.m() : null;" );
81- writer .println (" }" );
82- writer .println ();
102+ private MethodSpec generateToDynamoDbItemsMethod (String className , ClassName domainClass , ClassName attributeValue ) {
103+ return MethodSpec .methodBuilder ("toDynamoDbItems" )
104+ .addModifiers (Modifier .PUBLIC )
105+ .returns (ParameterizedTypeName .get (
106+ ClassName .get (List .class ),
107+ ParameterizedTypeName .get (
108+ ClassName .get (Map .class ),
109+ ClassName .get (String .class ),
110+ attributeValue )))
111+ .addParameter (ParameterizedTypeName .get (ClassName .get (List .class ), domainClass ), "objects" )
112+ .addJavadoc ("Convenience method to convert a list of domain objects to DynamoDB items.\\ n" )
113+ .addJavadoc ("Useful for batch operations like batchWriteItem.\\ n" )
114+ .addJavadoc ("\\ n" )
115+ .addJavadoc ("@param objects List of $L objects to convert\\ n" , className )
116+ .addJavadoc ("@return List of DynamoDB items (Map<String, AttributeValue>), filtering out any null results\\ n" )
117+ .beginControlFlow ("if (objects == null || objects.isEmpty())" )
118+ .addStatement ("return new $T<>()" , ClassName .get ("java.util" , "ArrayList" ))
119+ .endControlFlow ()
120+ .addStatement ("return objects.stream()" )
121+ .addStatement (" .map(this::toDynamoDbAttributeValue)" )
122+ .addStatement (" .filter($T::nonNull)" , ClassName .get (Objects .class ))
123+ .addStatement (" .map(av -> av.m())" )
124+ .addStatement (" .filter(map -> map != null && !map.isEmpty())" )
125+ .addStatement (" .collect($T.toList())" , ClassName .get (Collectors .class ))
126+ .build ();
83127 }
84128
85- private void generateToDynamoDbItemsMethod (PrintWriter writer , String className ) {
86- writer .println (" /**" );
87- writer .println (" * Convenience method to convert a list of domain objects to DynamoDB items." );
88- writer .println (" * Useful for batch operations like batchWriteItem." );
89- writer .println (" *" );
90- writer .println (" * @param objects List of " + className + " objects to convert" );
91- writer .println (" * @return List of DynamoDB items (Map<String, AttributeValue>), filtering out any null results" );
92- writer .println (" */" );
93- writer .println (" public List<Map<String, AttributeValue>> toDynamoDbItems(List<" + className + "> objects) {" );
94- writer .println (" if (objects == null || objects.isEmpty()) {" );
95- writer .println (" return new ArrayList<>();" );
96- writer .println (" }" );
97- writer .println (" return objects.stream()" );
98- writer .println (" .map(this::toDynamoDbAttributeValue)" );
99- writer .println (" .filter(Objects::nonNull)" );
100- writer .println (" .map(av -> av.m())" );
101- writer .println (" .filter(map -> map != null && !map.isEmpty())" );
102- writer .println (" .collect(Collectors.toList());" );
103- writer .println (" }" );
104- writer .println ();
129+ /**
130+ * @deprecated Use generateConvenienceMethods(TypeInfo) instead
131+ */
132+ @ Deprecated
133+ public void generateConvenienceMethods (java .io .PrintWriter writer , TypeInfo typeInfo ) {
134+ List <MethodSpec > methods = generateConvenienceMethods (typeInfo );
135+ for (MethodSpec method : methods ) {
136+ String [] lines = method .toString ().split ("\\ n" );
137+ for (String line : lines ) {
138+ if (!line .trim ().isEmpty ()) {
139+ writer .println (" " + line );
140+ } else {
141+ writer .println ();
142+ }
143+ }
144+ }
105145 }
106146}
0 commit comments