1

I am trying out AWS DynamoDB for the first time. I downloaded the AWS SDK and installed in Eclipse. I set up the sample Java DynamoDB "Store and Query" project that was supplied by AWS. I ran it as a simple java application on Eclipse and it executed with no problems. I created a new Spring-Boot project and copy-pasted the application plus added the necessary Spring-Boot parameters. The Spring-Boot version fails with a "java.lang.ClassNotFoundException" in the very first line of the main() code. A java.lang.ClassNotFoundException occurs during the execution of the AmazoneDynamoDBClientBuilder in init(). Specifically, it fails in the AmazonDynamoDBClientBuilder class in the init() method. The code is clean and builds without error. I will say that I had a hard time selecting the right jars from Maven Central. The DynamoDB code was very picky about having the latest jar releases.

Attached is a listing of the code,

package com.belcan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.HashMap;
import java.util.Map;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;
import com.amazonaws.services.dynamodbv2.model.TableDescription;
import com.amazonaws.services.dynamodbv2.util.TableUtils;

@SpringBootApplication
public class DynamoTest1Application {

    /*
     * Before running the code:
     *      Fill in your AWS access credentials in the provided credentials
     *      file template, and be sure to move the file to the default location
     *      (C:\\Users\\Stephen\\.aws\\credentials) where the sample code will load the
     *      credentials from.
     *      https://console.aws.amazon.com/iam/home?#security_credential
     *
     * WARNING:
     *      To avoid accidental leakage of your credentials, DO NOT keep
     *      the credentials file in your source directory.
     */

    static AmazonDynamoDB dynamoDB;

    /**
     * The only information needed to create a client are security credentials
     * consisting of the AWS Access Key ID and Secret Access Key. All other
     * configuration, such as the service endpoints, are performed
     * automatically. Client parameters, such as proxies, can be specified in an
     * optional ClientConfiguration object when constructing a client.
     *
     * @see com.amazonaws.auth.BasicAWSCredentials
     * @see com.amazonaws.auth.ProfilesConfigFile
     * @see com.amazonaws.ClientConfiguration
     */

    private static void init() throws Exception {
        /*
         * The ProfileCredentialsProvider will return your [default]
         * credential profile by reading from the credentials file located at
         * (C:\\Users\\Stephen\\.aws\\credentials).
         */
        System.out.println("Starting Init()");

        ProfileCredentialsProvider credentialsProvider = new ProfileCredentialsProvider();

        try {
            credentialsProvider.getCredentials();
        } catch (Exception e) {
            throw new AmazonClientException(
                    "Init()-1: Cannot load the credentials from the credential profiles file. " +
                    "Please make sure that your credentials file is at the correct " +
                    "location (C:\\Users\\Stephen\\.aws\\credentials), and is in valid format.",
                    e);
        }

        System.out.println("Init()-1 Complete");

        try {

        /****** Fails Right Here!!  Line 86 is ".withCredentials(credentialsProvider)" *****/
        dynamoDB = AmazonDynamoDBClientBuilder.standard()
            .withCredentials(credentialsProvider)
            .build();
        } catch (Exception e) {
            throw new AmazonClientException(
                    "Init()-2: Cannot build client", e);
        }

        System.out.println("Init()-2 Complete");
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(DynamoTest1Application.class, args);

        /***** This is line 98 ****/
        init();

        try {
            String tableName = "my-favorite-movies-table";

            // Create a table with a primary hash key named 'name', which holds a string
            CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
                .withKeySchema(new KeySchemaElement().withAttributeName("name").withKeyType(KeyType.HASH))
                .withAttributeDefinitions(new AttributeDefinition().withAttributeName("name").withAttributeType(ScalarAttributeType.S))
                .withProvisionedThroughput(new ProvisionedThroughput().withReadCapacityUnits(1L).withWriteCapacityUnits(1L));

            // Create table if it does not exist yet
            TableUtils.createTableIfNotExists(dynamoDB, createTableRequest);
            // wait for the table to move into ACTIVE state
            TableUtils.waitUntilActive(dynamoDB, tableName);

            // Describe our new table
            DescribeTableRequest describeTableRequest = new DescribeTableRequest().withTableName(tableName);
            TableDescription tableDescription = dynamoDB.describeTable(describeTableRequest).getTable();
            System.out.println("Table Description: " + tableDescription);

            // Add an item
            Map<String, AttributeValue> item = newItem("Bill & Ted's Excellent Adventure", 1989, "****", "James", "Sara");
            PutItemRequest putItemRequest = new PutItemRequest(tableName, item);
            PutItemResult putItemResult = dynamoDB.putItem(putItemRequest);
            System.out.println("Result: " + putItemResult);

            // Add another item
            item = newItem("Airplane", 1980, "*****", "James", "Billy Bob");
            putItemRequest = new PutItemRequest(tableName, item);
            putItemResult = dynamoDB.putItem(putItemRequest);
            System.out.println("Result: " + putItemResult);

            // Scan items for movies with a year attribute greater than 1985
            HashMap<String, Condition> scanFilter = new HashMap<String, Condition>();
            Condition condition = new Condition()
                .withComparisonOperator(ComparisonOperator.GT.toString())
                .withAttributeValueList(new AttributeValue().withN("1985"));
            scanFilter.put("year", condition);
            ScanRequest scanRequest = new ScanRequest(tableName).withScanFilter(scanFilter);
            ScanResult scanResult = dynamoDB.scan(scanRequest);
            System.out.println("Result: " + scanResult);

        } catch (AmazonServiceException ase) {
            System.out.println("Caught an AmazonServiceException, which means your request made it "
                    + "to AWS, but was rejected with an error response for some reason.");
            System.out.println("Error Message:    " + ase.getMessage());
            System.out.println("HTTP Status Code: " + ase.getStatusCode());
            System.out.println("AWS Error Code:   " + ase.getErrorCode());
            System.out.println("Error Type:       " + ase.getErrorType());
            System.out.println("Request ID:       " + ase.getRequestId());
        } catch (AmazonClientException ace) {
            System.out.println("Caught an AmazonClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with AWS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ace.getMessage());
        }
    }

    private static Map<String, AttributeValue> newItem(String name, int year, String rating, String... fans) {
        Map<String, AttributeValue> item = new HashMap<String, AttributeValue>();
        item.put("name", new AttributeValue(name));
        item.put("year", new AttributeValue().withN(Integer.toString(year)));
        item.put("rating", new AttributeValue(rating));
        item.put("fans", new AttributeValue().withSS(fans));

        return item;
    }

}

I am getting the following errors,

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.8.RELEASE)

2017-11-08 13:44:58.450  INFO 21012 --- [           main] com.belcan.DynamoTest1Application        : Starting DynamoTest1Application on skmi5-7000 with PID 21012 (C:\Users\Stephen\Desktop\BCN\Projects\360Yield\swdev\360yield\360examples\DynamoTest1\bin started by Stephen in C:\Users\Stephen\Desktop\BCN\Projects\360Yield\swdev\360yield\360examples\DynamoTest1)
2017-11-08 13:44:58.456  INFO 21012 --- [           main] com.belcan.DynamoTest1Application        : No active profile set, falling back to default profiles: default
2017-11-08 13:44:58.544  INFO 21012 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@59717824: startup date [Wed Nov 08 13:44:58 EST 2017]; root of context hierarchy
2017-11-08 13:44:59.089  INFO 21012 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-11-08 13:44:59.104  INFO 21012 --- [           main] com.belcan.DynamoTest1Application        : Started DynamoTest1Application in 1.185 seconds (JVM running for 2.316)
Starting Init()
Init()-1 Complete
Exception in thread "main" java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ObjectMapper
    at com.amazonaws.internal.config.InternalConfig.<clinit>(InternalConfig.java:43)
    at com.amazonaws.internal.config.InternalConfig$Factory.<clinit>(InternalConfig.java:304)
    at com.amazonaws.util.VersionInfoUtils.userAgent(VersionInfoUtils.java:142)
    at com.amazonaws.util.VersionInfoUtils.initializeUserAgent(VersionInfoUtils.java:137)
    at com.amazonaws.util.VersionInfoUtils.getUserAgent(VersionInfoUtils.java:100)
    at com.amazonaws.ClientConfiguration.<clinit>(ClientConfiguration.java:65)
    at com.amazonaws.ClientConfigurationFactory.getDefaultConfig(ClientConfigurationFactory.java:46)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientConfigurationFactory.getDefaultConfig(AmazonDynamoDBClientConfigurationFactory.java:31)
    at com.amazonaws.ClientConfigurationFactory.getConfig(ClientConfigurationFactory.java:36)
    at com.amazonaws.client.builder.AwsClientBuilder.resolveClientConfiguration(AwsClientBuilder.java:163)
    at com.amazonaws.client.builder.AwsClientBuilder.access$000(AwsClientBuilder.java:52)
    at com.amazonaws.client.builder.AwsClientBuilder$SyncBuilderParams.<init>(AwsClientBuilder.java:411)
    at com.amazonaws.client.builder.AwsClientBuilder.getSyncClientParams(AwsClientBuilder.java:354)
    at com.amazonaws.client.builder.AwsSyncClientBuilder.build(AwsSyncClientBuilder.java:46)
    at com.belcan.DynamoTest1Application.init(DynamoTest1Application.java:86)
    at com.belcan.DynamoTest1Application.main(DynamoTest1Application.java:98)
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.ObjectMapper
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 16 more
2017-11-08 13:44:59.130  INFO 21012 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@59717824: startup date [Wed Nov 08 13:44:58 EST 2017]; root of context hierarchy
2017-11-08 13:44:59.133  INFO 21012 --- [       Thread-2] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

You really don't have to dig very far to see the error. The failure occurs on the very first line of code in the main(), the init() method. You can see I put a couple of println's in the method to see how far I am getting. I get past the first part of init(), the credentials retrieval. I am failing with the second part of init(), AmazonDynamoDBClientBuilder where the DynamoDB client is constructed. There seems to be something funky going on with the jars. The original AWS Java code was written for maven. I am using Gradle for Spring Boot. I looked at the original AWS pom.xml file and found that it referenced 2 dependencies,

aws-java-sdk-1.11.225
aws-kinesis-client-1.2.1

I included these 2 in my gradle build. Below are the jars that I am using.

amazon-kinesis-client-1.8.7.jar
aws-java-sdk-1.11.225 (1).jar
aws-java-sdk-core-1.11.226 (1).jar
aws-java-sdk-dynamodb-1.11.226 (2).jar

Any ideas on what is going on? It looks like I am missing a jar or have not attached the correct one. Been working on it for 2 days with no luck. Any help would be great.

1 Answer 1

1

Add this to your gradle.build:

compile("com.fasterxml.jackson.core:jackson-databind:2.9.2")
Sign up to request clarification or add additional context in comments.

6 Comments

This did not quite fix my problem. I added the dependency AlexGera highlighted above but I just got another "ClassNotFoundException" for a different jar. However, it enlighted me to the actual issue. AWS provides support for POJO's and not Spring Boot. The POJO project that AWS builds contains a rather large set of Maven dependencies that are not in the Eclipse Spring Boot build. I have to figure out how to get all of these dependencies in my Eclipse Gradle Spring Boot project. Anyone know how to fix this easily without having to type in 30 or 40 Gradle dependencies?
AWS doesn't provide any support nether for Spring nor for POJOs (What do you mean by this, btw?). All your matter here is just to add correct libraries as a dependencies on the correct building stages. For example in your original error was DynamoDB config trying to read from XML and couldn't find a marshaller lib to go. You can post your next error if you want
Also regarding "The original AWS Java code was written for maven. I am using Gradle for Spring Boot." - it doesn't matter. Code could not be written for Maven or Gradle or Ivy. Gradle uses Maven as an artifact repository under the scene (If not specified other one). Gradle is a building framework and wrap up artifact repository which is Maven
Alex, thank you for your comments and I agree with you on your Maven/Gradle response. I had two issues and the problem is now fixed. First, as you suggested, I was missing a couple of Jackson jars. The second problem was I was not using the latest release of the jars. I added the all the necessary jars at the latest release level and now the project builds and runs properly.
No problem. Good job!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.