Amazon CodeWhisperer —stepping on the accelerator ;-)

Mani
10 min readMay 17, 2023
A water lily from our terrace garden — Sanjaynagar, Bengaluru

From the FAQs— Amazon CodeWhisperer is an generative artificial intelligence (AI) based coding companion which generates real-time single-line or full function code suggestions in your integrated development environment (IDE) to help you more quickly build software. The code suggestions provided by CodeWhisperer are based on a large language models (LLMs) trained on billions of lines of code, including Amazon and open-source code.

As always, these are my personal opinions in this blog, please consult the product page for the most recent and authoritative word on Amazon CodeWhisperer — https://aws.amazon.com/codewhisperer/

I had written a blog around Amazon CodeWhisperer when it was in a public preview sometime back. It was my first time around with a general purpose, AI-powered code generator and I had played around with it using kid gloves ..

On April 13th 2023, Amazon CodeWhisperer became generally available !! The following are some of the key features (a small list, not the complete list) which I like now:

  1. The list of programming languages is much, much more than what was supported during preview— Python, Java, JavaScript, TypeScript, and C#, CodeWhisperer can now also generate code suggestions for Go, Rust, Kotlin, Scala, Ruby, PHP, SQL, C, C++, and Shell Scripting
  2. Available in two editions — Individual free to use for generating code (wow !!!!) and Professional (paid) with enterprise administration capabilities
  3. The FAQ at https://aws.amazon.com/codewhisperer/faqs/ has extensive details, which will probably all your questions. I loved the section on Responsible AI -
CodeWhisperer FAQ — https://aws.amazon.com/codewhisperer/faqs/

TL DR;

While I have seen many blogs for programming languages like Javascript, Python with Amazon Code Whisperer, I have not seen too many blogs/how-to’s with Java. My goal in this blog is to use CodeWhisperer (CW) to generate code for a real-world scenario and not just generate toy stuff — a Java Springboot application which interacts with DynamoDB, which I will then build+deploy to Amazon Elastic Container service with AWS Fargate , with an code editor, IntelliJ IDEA Community Edition. I also try to do a stretch goal of generating infra-as-code to provision AWS resources using CDK, with Amazon Code Whisperer !! Read the blog for more details !!

Lets get started !!

Using CodeWhisperer to generate a Java Springboot container application

My goal is to create a Java Springboot app which calls a Amazon DynamoDB table and displays the data from that table, and I also did not want to step out of code editor (too much to other websites !!) while coding 🙂

I used IntelliJ IDEA with the AWS toolkit installed for this blog, you can find more detailed instructions at https://docs.aws.amazon.com/codewhisperer/latest/userguide/whisper-setup-indv-devs.html

Tip #1: Make sure that the CW plugin is connected .. If the connection is broken, please reestablish the connection

IntelliJ Codewhisperer connection status

Tip #2: CW now also seems to give suggestions to add Java imports as well

CW — comments

The first step (which helped me to get started) is to create a skeleton Java Springboot class using IntelliJ, please test to ensure that your build file works and that you have the right libraries and the build compiles. I used Gradle for my build and my gradle build file looked like this:

build.gradle

Now that we have the basics completed, lets start adding the comments and start building the application .. There are two ways to generate code, either you do them step by step with specific comments or generate bigger chunks of code by giving multi-step instructions as Java comments. My preference is for the former, as I can nudge CW in the right direction ..

Java Springboot app calling Amazon DynamoDB

Ok, while this is good, I also want to display the customer list on the console .. so, I go to the appropriate line and invoke CW .. and I get the desired code.

The generated code seems to expect a Java class called “Customer”, so I created a dummy “Customer” class and added this comment to generate the code:

//generate code for customer class with name and cellphone string fields

and I got this generated code ..

Customer class

At this point, I tried to compile this code and got the following error with lots and lots of missing imports:

gradle error

So, I tried to coax CW to add the required imports with this comment ..

Tip #3 — generating java imports

// add imports required to compile

and it was able to add the imports to some extent .. and I had to manually add some of the other Java imports which were not included.

java imports

One of the nice features of using CW, is to generate test data !!

Tip #4 — Generate test data

generating test data to load my dynamodb table

I am very impressed, CodeWhisperer even gave me an options with “Indian” sounding names for loading the test data in DynamoDB 😃 !!

I am done with the application and I finally tested this locally, by calling localhost:8080/loadcustomerdata and localhost:8080/getcustomers and it worked !!!! Yippee !!

test data ..

A snippet of the final code, which includes the code generated by CodeWhisperer :

package com.example.demo;


import org.springframework.web.bind.annotation.RequestMapping;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Expression;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;

// add imports required to compile

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;



@SpringBootApplication
@RestController
public class DemoApplication {

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);
}

// 1.) Springboot Function for "/getcustomers" to retrieve all Items from a DynamoDB table called "customers" in AP-SOUTH-1 region and display on the console
@RequestMapping("/getcustomers")
public List<Customer> getCustomers() {
Region region = Region.AP_SOUTH_1;
DynamoDbClient ddb = DynamoDbClient.builder().region(region).build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder().dynamoDbClient(ddb).build();
DynamoDbTable<Customer> mappedTable = enhancedClient.table("customers", TableSchema.fromBean(Customer.class));
List<Customer> customers = new ArrayList<>();
try {
Iterator<Customer> results = mappedTable.scan().items().iterator();
while (results.hasNext()) {
Customer customer = results.next();
customers.add(customer);
System.out.println(customer.toString());

}
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
return customers;


}

// 1.) Springboot Function for "loadcustomerdata" to load some dummy data into a DynamoDB table called "customers" in AP-SOUTH-1 region with name and cellphone fields
@RequestMapping("/loadcustomerdata")
public String loadCustomerData() {
Region region = Region.AP_SOUTH_1;
DynamoDbClient ddb = DynamoDbClient.builder().region(region).build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder().dynamoDbClient(ddb).build();
DynamoDbTable<Customer> mappedTable = enhancedClient.table("customers", TableSchema.fromBean(Customer.class));
Customer customer1 = new Customer("Sachin", "9999999999");
Customer customer2 = new Customer("Rahul", "8888888888");
Customer customer3 = new Customer("Rohit", "7777777777");
Customer customer4 = new Customer("Virat", "6666666666");
Customer customer5 = new Customer("Rohit", "5555555555");
Customer customer6 = new Customer("Rohit", "4444444444");
Customer customer7 = new Customer("Rohit", "3333333333");

// add return statement with a string that says "Data loaded successfully"
try {
mappedTable.putItem(customer1);
mappedTable.putItem(customer2);
mappedTable.putItem(customer3);
mappedTable.putItem(customer4);
mappedTable.putItem(customer5);
mappedTable.putItem(customer6);
mappedTable.putItem(customer7);
return "Data loaded successfully";
}
catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
return null;
}


}

Tip #5: You seem to get better recommendations from CW, if you give more hints like adding java imports before invoking CodeWhisperer.

Troubleshooting tip: I had a few minor issues with closing parenthesis with the generated Java functions, so do watch out for them and add them manually, if required ..

Finally, I used the “Run Security scan” feature of CW and it gave me a couple of suggestions to improve the security posture of the code related to cross-site request forgery ..

Codewhisperer — security scan

The next step is to push this code to Amazon Elastic Container registry as a container image. This part is “out of band” for CodeWhisperer and I did this step manually outside the IDE. These steps are given in the ECR documentation ..

I am also going to introduce yet another new cool tool from AWS for building and pushing container images, instead of using Docker desktop on my Macbook .. I used finch, an open source container client from AWS, instead of Docker CLI for building and pushing the images to Amazon Elastic Container Registry (ECR) ..

But first, I need the all important Dockerfile, which I created manually. I also used Amazon Corretto 17 as the JDK on my Mac as well as in the Dockerfile for the Springboot app.

Dockerfile
---

FROM amazoncorretto:17
ARG JAR_FILE=build/libs/demo-0.0.1-SNAPSHOT.jar
# cd /opt/app
WORKDIR /opt/app
COPY ${JAR_FILE} app.jar
# java -jar /opt/app/app.jar
ENTRYPOINT ["java","-jar","app.jar"]

and the finch commands to push the image to ECR, the AWS commands in the ECR console still specify docker, but I just replaced docker with finch and it works seamlessly to build and push the image !!


aws ecr get-login-password --region ap-south-1 | finch login --username AWS --password-stdin xxxx.dkr.ecr.ap-south-1.amazonaws.com
finch build -t cw-springboot-test .
finch tag cw-springboot-test:latest xxx.dkr.ecr.ap-south-1.amazonaws.com/cw-springboot-test:latest
finch push xxxx.dkr.ecr.ap-south-1.amazonaws.com/cw-springboot-test:latest

Using CodeWhisperer to generate CDK — infra as code

AWS Cloud Development Kit (AWS CDK) accelerates cloud development using common programming languages to model your applications, and we can use the same IDE’s like IntelliJ and programming languages like ypeScript, Python, Java, .NET, and Go (in Developer Preview).

Why not use CW to generate my infra as code to provision my Amazon ECS cluster and deploy the springboot app? This was something that I did not think about initially as one of the reasons to use CodeWhisperer, but I wanted to try this ..

  1. I used the documentation at https://docs.aws.amazon.com/cdk/v2/guide/ecs_example.html to create a skeleton CDK project
  2. Open the newly created project in IntelliJ and kickstart CW to start creating the CDK code for creating the various elements related to my Amazon ECS cluster with AWS Fargate leveraging the container image which we had pushed to the ECR container registry !!
  3. The process for generating the CDK code remains the same via Java comments ..
CoideWhisperer generating CDK code

I have to admit, I have not yet fully played with the possibilities of leveraging Amazon CodeWhisperer with CDK fully, but the possibilities that open up are endless !!

That’s it folks .. I tested the app that was mostly generated using Amazon CodeWhisperer and it worked !! I can say with a fair degree of confidence, CW helped me with probably more than 80% of the application code as well as the CDK — infra as code .. I also became aware of the various other options displayed by CW for doing the same tasks, and I selected what I felt was the best option.

My wish-list for Amazon CodeWhisperer 😃

  1. I hope someday, the supporting configuration files like the gradle config files, pom.xml for maven builds, Dockerfile and others will also get generated by CodeWhisperer
  2. For languages like Java, where imports are needed to compile, a one-click way to generate all imports after the code has been generated will be super useful. I had to nudge CW a little bit in the right direction ..
  3. Also a full lifecycle like code-deploy-test-code with AWS will be super useful and make developers really productive .. Now this work is a little bit manual, and probably out of the purview of CodeWhisperer.

Bill of materials 😺

I used the following:

  1. Programming language — Java 17 and the JDK from Amazon Corretto — FREE
  2. IDE — The community edition from IntelliJ IDEA 2023.1.1 (Community Edition) — FREE
  3. I used Gradle for my springboot application builds and Maven for the CDK build — FREE
  4. Using finch, an open source container client from AWS — FREE
  5. Finally, Amazon CodeWhisperer Individual Tier — FREE ( Check https://aws.amazon.com/codewhisperer/pricing for pricing of the professional tier)
  6. Amazon ECS with AWS Fargate and Amazon DynamoDB

Summary:

The following are my final thoughts:

  1. Amazon CodeWhisperer (CW) can be a great companion and productivity booster for developers. For folks like me, who have good to average skills in one programming language like Java, we can also develop in other languages like Python, JavaScript and other languages supported by CW. The biggest revelation for me, was that I could also use CW for generating infrastructure as code like CDK to provision AWS resources, wow !!! So, a single place to generate application and infrastructure code !!
  2. CW integration with popular IDE’s like IntelliJ, VS code and others is very useful and seamless. CW helped me to stay focussed and not do too much context-switching, which I feel helped my productivity. Using the prompts, in this case Java comments, is key and you will need to get the hang of it to generate the right code ..
  3. Its Free for individual use, for the professional tier, it has priced for the additional enterprise features like org policy management ..
  4. I loved its easy/tight integration with AWS services, and also its built-in security scan and for generating Responsible code (like bias avoidance and reference tracker for open source code)

I highly recommend using Amazon CodeWhisperer, please try it. Let me know, if you need help 🙌

That’s it folks. Thanks, hope you found this blog useful, please do share your comments.

Resources:

  1. Amazon CodeWhisperer product page — https://aws.amazon.com/codewhisperer/
  2. CodeWhisperer workshop (uses Python) — https://catalog.us-east-1.prod.workshops.aws/workshops/a33a5d69-1417-4d5f-acc9-ae5c7fba665b/
  3. Documentation — https://docs.aws.amazon.com/codewhisperer/index.html
  4. Awesome AWS blog which shares some tips and tricks, this is for JavaScript but you can use the same tips for Java too — https://aws.amazon.com/blogs/devops/10-ways-to-build-applications-faster-with-amazon-codewhisperer/

--

--

Mani

Principal Solutions Architect at AWS India, and I blog/post about interesting stuff that I am curious about and which is relevant to developers & customers.