Skip to content

Commit c306af1

Browse files
committed
Add code example links to individual method documentation
1 parent 05f060e commit c306af1

3 files changed

Lines changed: 5293 additions & 0 deletions

File tree

codegen/src/main/java/software/amazon/awssdk/codegen/docs/OperationDocProvider.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Collections;
2323
import java.util.List;
2424
import java.util.stream.Collectors;
25+
import software.amazon.awssdk.codegen.internal.DocumentationUtils;
2526
import software.amazon.awssdk.codegen.model.intermediate.DocumentationModel;
2627
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2728
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -86,6 +87,11 @@ String getDocs() {
8687
if (!crosslink.isEmpty()) {
8788
docBuilder.see(crosslink);
8889
}
90+
91+
String codeExampleLink = DocumentationUtils.createLinkToCodeExample(model.getMetadata(), opModel.getOperationName());
92+
if (!codeExampleLink.isEmpty()) {
93+
docBuilder.see(codeExampleLink);
94+
}
8995
return docBuilder.build().replace("$", "&#36");
9096
}
9197

codegen/src/main/java/software/amazon/awssdk/codegen/internal/DocumentationUtils.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,20 @@
2020
import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Request;
2121
import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Response;
2222

23+
import com.fasterxml.jackson.databind.JsonNode;
24+
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import java.io.IOException;
26+
import java.io.InputStream;
2327
import java.util.Arrays;
28+
import java.util.HashMap;
2429
import java.util.HashSet;
30+
import java.util.Locale;
31+
import java.util.Map;
2532
import java.util.Set;
2633
import java.util.regex.Pattern;
2734
import software.amazon.awssdk.codegen.model.intermediate.Metadata;
2835
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
36+
import software.amazon.awssdk.utils.Logger;
2937

3038
public final class DocumentationUtils {
3139

@@ -54,6 +62,9 @@ public final class DocumentationUtils {
5462
"iot", "data.iot", "machinelearning", "rekognition", "s3", "sdb", "swf"
5563
));
5664
private static final Pattern COMMENT_DELIMITER = Pattern.compile("\\*\\/");
65+
66+
private static final Logger log = Logger.loggerFor(DocumentationUtils.class);
67+
private static Map<String, String> exampleUrlMap;
5768

5869
private DocumentationUtils() {
5970
}
@@ -140,6 +151,32 @@ public static String createLinkToServiceDocumentation(Metadata metadata, ShapeMo
140151
: "";
141152
}
142153

154+
/**
155+
* Create a link to a code example for the given operation.
156+
*
157+
* @param metadata the service metadata containing service name information
158+
* @param operationName the name of the operation to find an example for
159+
* @return a '@see also' HTML link to the code example, or empty string if no example found
160+
*/
161+
public static String createLinkToCodeExample(Metadata metadata, String operationName) {
162+
try {
163+
String serviceKey = mapServiceNameToExampleKey(metadata.getServiceName());
164+
String targetExampleId = serviceKey + "_" + operationName;
165+
166+
Map<String, String> urlMap = getExampleUrlMap();
167+
String url = urlMap.get(targetExampleId);
168+
169+
if (url != null) {
170+
return String.format("<a href=\"%s\" target=\"_top\">Code Example</a>", url);
171+
}
172+
173+
return "";
174+
} catch (Exception e) {
175+
log.debug(() -> "Failed to create code example link for " + metadata.getServiceName() + "." + operationName, e);
176+
return "";
177+
}
178+
}
179+
143180
public static String removeFromEnd(String string, String stringToRemove) {
144181
return string.endsWith(stringToRemove) ? string.substring(0, string.length() - stringToRemove.length()) : string;
145182
}
@@ -177,4 +214,73 @@ public static String defaultFluentReturn() {
177214
public static String defaultExistenceCheck() {
178215
return DEFAULT_EXISTENCE_CHECK;
179216
}
217+
218+
/**
219+
* Maps service names from codegen format (e.g., "AutoScaling") to example-meta.json keys (e.g., "auto-scaling").
220+
*/
221+
private static String mapServiceNameToExampleKey(String serviceName) {
222+
if (serviceName == null) {
223+
return "";
224+
}
225+
226+
return serviceName
227+
.replaceAll("([a-z0-9])([A-Z])", "$1-$2")
228+
.toLowerCase(Locale.ROOT);
229+
}
230+
231+
/**
232+
* Gets the cached example URL map for fast operation ID -> URL lookups.
233+
*/
234+
private static Map<String, String> getExampleUrlMap() {
235+
if (exampleUrlMap == null) {
236+
exampleUrlMap = buildExampleUrlMap();
237+
}
238+
return exampleUrlMap;
239+
}
240+
241+
/**
242+
* Builds a flat lookup map from example-meta.json: operation ID -> URL
243+
*/
244+
private static Map<String, String> buildExampleUrlMap() {
245+
Map<String, String> urlMap = new HashMap<>();
246+
247+
try (InputStream inputStream = DocumentationUtils.class.getClassLoader()
248+
.getResourceAsStream("software/amazon/awssdk/codegen/example-meta.json")) {
249+
250+
if (inputStream == null) {
251+
log.debug(() -> "example-meta.json not found in classpath");
252+
return urlMap;
253+
}
254+
255+
ObjectMapper objectMapper = new ObjectMapper();
256+
JsonNode root = objectMapper.readTree(inputStream);
257+
258+
JsonNode servicesNode = root.get("services");
259+
if (servicesNode != null) {
260+
for (JsonNode serviceNode : servicesNode) {
261+
JsonNode examplesNode = serviceNode.get("examples");
262+
if (examplesNode != null && examplesNode.isArray()) {
263+
for (JsonNode example : examplesNode) {
264+
JsonNode idNode = example.get("id");
265+
JsonNode urlNode = example.get("url");
266+
267+
if (idNode != null && urlNode != null) {
268+
String id = idNode.asText();
269+
String url = urlNode.asText();
270+
if (!id.isEmpty() && !url.isEmpty()) {
271+
urlMap.put(id, url);
272+
}
273+
}
274+
}
275+
}
276+
}
277+
}
278+
279+
return urlMap;
280+
281+
} catch (IOException e) {
282+
log.warn(() -> "Failed to load example-meta.json", e);
283+
return urlMap;
284+
}
285+
}
180286
}

0 commit comments

Comments
 (0)