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.internal;
17 
18 import static software.amazon.awssdk.codegen.model.service.ShapeType.List;
19 import static software.amazon.awssdk.codegen.model.service.ShapeType.Map;
20 import static software.amazon.awssdk.codegen.model.service.ShapeType.Structure;
21 
22 import java.io.InputStream;
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25 import java.time.Instant;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
31 import software.amazon.awssdk.codegen.model.service.Shape;
32 import software.amazon.awssdk.codegen.naming.NamingStrategy;
33 import software.amazon.awssdk.core.SdkBytes;
34 import software.amazon.awssdk.core.document.Document;
35 
36 /**
37  * Used to determine the Java types for the service model.
38  */
39 public class TypeUtils {
40     public static final class TypeKey {
41         public static final String LIST_INTERFACE = "listInterface";
42 
43         public static final String LIST_DEFAULT_IMPL = "listDefaultImpl";
44 
45         public static final String MAP_INTERFACE = "mapInterface";
46 
47         public static final String MAP_DEFAULT_IMPL = "mapDefaultImpl";
48     }
49 
50     private static final Map<String, String> DATA_TYPE_MAPPINGS = new HashMap<>();
51 
52     private static final Map<String, String> MARSHALLING_TYPE_MAPPINGS = new HashMap<>();
53 
54     static {
55         DATA_TYPE_MAPPINGS.put("string", String.class.getSimpleName());
56         DATA_TYPE_MAPPINGS.put("boolean", Boolean.class.getSimpleName());
57         DATA_TYPE_MAPPINGS.put("int", Integer.class.getSimpleName());
58         DATA_TYPE_MAPPINGS.put("any", Object.class.getSimpleName());
59         DATA_TYPE_MAPPINGS.put("integer", Integer.class.getSimpleName());
60         DATA_TYPE_MAPPINGS.put("double", Double.class.getSimpleName());
61         DATA_TYPE_MAPPINGS.put("short", Short.class.getSimpleName());
62         DATA_TYPE_MAPPINGS.put("long", Long.class.getSimpleName());
63         DATA_TYPE_MAPPINGS.put("float", Float.class.getSimpleName());
64         DATA_TYPE_MAPPINGS.put("byte", Byte.class.getSimpleName());
65         DATA_TYPE_MAPPINGS.put("timestamp", Instant.class.getName());
66         DATA_TYPE_MAPPINGS.put("blob", SdkBytes.class.getName());
67         DATA_TYPE_MAPPINGS.put("stream", InputStream.class.getName());
68         DATA_TYPE_MAPPINGS.put("bigdecimal", BigDecimal.class.getName());
69         DATA_TYPE_MAPPINGS.put("biginteger", BigInteger.class.getName());
70         DATA_TYPE_MAPPINGS.put("list", List.class.getSimpleName());
71         DATA_TYPE_MAPPINGS.put("map", Map.class.getSimpleName());
72         DATA_TYPE_MAPPINGS.put("document", Document.class.getName());
DATA_TYPE_MAPPINGS.put(TypeKey.LIST_INTERFACE, List.class.getName())73         DATA_TYPE_MAPPINGS.put(TypeKey.LIST_INTERFACE, List.class.getName());
DATA_TYPE_MAPPINGS.put(TypeKey.LIST_DEFAULT_IMPL, ArrayList.class.getName())74         DATA_TYPE_MAPPINGS.put(TypeKey.LIST_DEFAULT_IMPL, ArrayList.class.getName());
DATA_TYPE_MAPPINGS.put(TypeKey.MAP_INTERFACE, Map.class.getName())75         DATA_TYPE_MAPPINGS.put(TypeKey.MAP_INTERFACE, Map.class.getName());
DATA_TYPE_MAPPINGS.put(TypeKey.MAP_DEFAULT_IMPL, HashMap.class.getName())76         DATA_TYPE_MAPPINGS.put(TypeKey.MAP_DEFAULT_IMPL, HashMap.class.getName());
77 
78         MARSHALLING_TYPE_MAPPINGS.put("String", "STRING");
79         MARSHALLING_TYPE_MAPPINGS.put("Integer", "INTEGER");
80         MARSHALLING_TYPE_MAPPINGS.put("Long", "LONG");
81         MARSHALLING_TYPE_MAPPINGS.put("Float", "FLOAT");
82         MARSHALLING_TYPE_MAPPINGS.put("Double", "DOUBLE");
83         MARSHALLING_TYPE_MAPPINGS.put("Instant", "INSTANT");
84         MARSHALLING_TYPE_MAPPINGS.put("SdkBytes", "SDK_BYTES");
85         MARSHALLING_TYPE_MAPPINGS.put("Boolean", "BOOLEAN");
86         MARSHALLING_TYPE_MAPPINGS.put("BigDecimal", "BIG_DECIMAL");
87         MARSHALLING_TYPE_MAPPINGS.put("InputStream", "STREAM");
88         MARSHALLING_TYPE_MAPPINGS.put("Short", "SHORT");
MARSHALLING_TYPE_MAPPINGS.put(null, "NULL")89         MARSHALLING_TYPE_MAPPINGS.put(null, "NULL");
90         MARSHALLING_TYPE_MAPPINGS.put("Document", "DOCUMENT");
91     }
92 
93     private final NamingStrategy namingStrategy;
94 
TypeUtils(NamingStrategy namingStrategy)95     public TypeUtils(NamingStrategy namingStrategy) {
96         this.namingStrategy = namingStrategy;
97     }
98 
getMarshallingType(String simpleType)99     public static String getMarshallingType(String simpleType) {
100         return MARSHALLING_TYPE_MAPPINGS.get(simpleType);
101     }
102 
isSimple(String type)103     public static boolean isSimple(String type) {
104         return DATA_TYPE_MAPPINGS.containsKey(type) || DATA_TYPE_MAPPINGS.containsValue(type);
105     }
106 
getDataTypeMapping(String type)107     public static String getDataTypeMapping(String type) {
108         return DATA_TYPE_MAPPINGS.get(type);
109     }
110 
111     /**
112      * Returns the default Java type of the specified shape.
113      */
getJavaDataType(Map<String, Shape> shapes, String shapeName)114     public String getJavaDataType(Map<String, Shape> shapes, String shapeName) {
115         return getJavaDataType(shapes, shapeName, null);
116     }
117 
118     /**
119      * Returns the Java type of the specified shape with potential customization (such as
120      * auto-construct list or map).
121      */
getJavaDataType(Map<String, Shape> shapes, String shapeName, CustomizationConfig customConfig)122     public String getJavaDataType(Map<String, Shape> shapes, String shapeName,
123                                   CustomizationConfig customConfig) {
124 
125         if (shapeName == null || shapeName.trim().isEmpty()) {
126             throw new IllegalArgumentException(
127                     "Cannot derive shape type. Shape name cannot be null or empty");
128         }
129 
130         Shape shape = shapes.get(shapeName);
131 
132         if (shape == null) {
133             throw new IllegalArgumentException(
134                     "Cannot derive shape type. No shape information available for " + shapeName);
135         }
136 
137         String shapeType = shape.getType();
138 
139         if (shape.isDocument()) {
140             return DATA_TYPE_MAPPINGS.get("document");
141         }
142 
143         if (Structure.getName().equals(shapeType)) {
144             return namingStrategy.getShapeClassName(shapeName);
145         } else if (List.getName().equals(shapeType)) {
146             String listContainerType = DATA_TYPE_MAPPINGS.get(TypeKey.LIST_INTERFACE);
147             return listContainerType + "<" +
148                     getJavaDataType(shapes, shape.getListMember().getShape()) + ">";
149         } else if (Map.getName().equals(shapeType)) {
150             String mapContainerType = DATA_TYPE_MAPPINGS.get(TypeKey.MAP_INTERFACE);
151             return mapContainerType + "<" +
152                     getJavaDataType(shapes, shape.getMapKeyType().getShape()) + "," +
153                     getJavaDataType(shapes, shape.getMapValueType().getShape()) + ">";
154         } else {
155 
156             if (shape.isStreaming()) {
157                 return DATA_TYPE_MAPPINGS.get("stream");
158             }
159 
160             // scalar type.
161             String dataType = DATA_TYPE_MAPPINGS.get(shapeType);
162             if (dataType == null) {
163                 throw new RuntimeException(
164                         "Equivalent Java data type cannot be found for data type : " + shapeType);
165             }
166             return dataType;
167         }
168     }
169 }
170