I have been in touch with the author of Alternator about this issue, and he's as puzzled as I am. The short story: I have written unit tests of code that operates against DynamoDB using the Alternator mocking framework that work fine when I invoke them from within Eclipse, but fail when invoked from maven.
The failure arises from within the AWS SDK itself:
com.amazonaws.AmazonServiceException: [java.lang.Error: property value is null.]
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:679) ~[aws-java-sdk-1.5.5.jar:na]
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:350) ~[aws-java-sdk-1.5.5.jar:na]
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:202) ~[aws-java-sdk-1.5.5.jar:na]
at com.michelboudreau.alternatorv2.AlternatorDBClientV2.invoke(AlternatorDBClientV2.java:225) ~[alternator-0.6.4.jar:na]
at com.michelboudreau.alternatorv2.AlternatorDBClientV2.updateItem(AlternatorDBClientV2.java:99) ~[alternator-0.6.4.jar:na]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$2.executeLowLevelRequest(DynamoDBMapper.java:646) ~[aws-java-sdk-1.5.5.jar:na]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$SaveObjectHandler.execute(DynamoDBMapper.java:767) ~[aws-java-sdk-1.5.5.jar:na]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:658) ~[aws-java-sdk-1.5.5.jar:na]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:488) ~[aws-java-sdk-1.5.5.jar:na]
at com.somoglobal.eventdata.Controller.addDeviceKeys(Controller.java:531) ~[classes/:na]
which as you can see is not hugely useful as the stack trace itself is just showing the stack at the point where the AWS SDK is assembling an exception from the response received through the (mocked) remote service.
The relevant version numbers:
- Maven 3.0.4
- Java 1.7.0_10
- AWS SDK 1.5.5 (although I've also tried 1.5.3 and 1.5.4)
- Eclipse version "Kepler", Build id: 20130614-0229
Burrowing down a bit further, the (slightly elided) pom.xml for the project
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>snip</groupId>
<artifactId>snip</artifactId>
<version>1.14.2-SNAPSHOT</version>
</parent>
<artifactId>snip</artifactId>
<version>1.6.0-SNAPSHOT</version>
<name>snip</name>
<dependencies>
...snip...
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>com.michelboudreau</groupId>
<artifactId>alternator</artifactId>
<version>0.6.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
and the slightly trimmed down test:
package com.xxx;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.joda.time.DateTime;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import com.amazonaws.Request;
import com.amazonaws.handlers.RequestHandler;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
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.ProvisionedThroughputExceededException;
import com.amazonaws.util.TimingInfo;
import com.michelboudreau.alternator.AlternatorDB;
import com.michelboudreau.alternatorv2.AlternatorDBClientV2;
import com.xxx.stuff;
public class ControllerTest {
private static Controller instance;
private static DynamoDBMapper mapper;
private static AlternatorDB db;
private static AlternatorDBClientV2 client;
@BeforeClass
public static void setup() throws Exception {
client = new AlternatorDBClientV2();
mapper = new DynamoDBMapper(client);
db = new AlternatorDB().start();
// code to create dynamodb was here
instance = new Controller(mapper);
}
@AfterClass
public static void tearDown() throws Exception {
db.stop();
}
@Test
public void testAddDeviceKeys() {
Collection<DeviceKey> keys = EventDataModelMapper.getDeviceKeys(ClassFixtures.event);
assertNotNull("keys should not be null", keys);
assertFalse("keys should not be empty", keys.isEmpty());
boolean result = instance.addDeviceKeys(keys);
assertTrue("result should be true", result);
}
}
The code under test is probably not particularly involved in this failure - I've done sufficient debugging tracing to see that it behaves identically during test when invoked directly through Eclipse, and when run from maven.
EDIT
Actually, Alternator might be implicated in this, as the error message in question could be coming out of com.michelboudreau.alternator.validation.ValidatorUtils:
public static <T> List<Error> rejectIfNull(T property) {
List<Error> errors = new ArrayList<Error>();
if (property == null) {
errors.add(new Error("property value is null."));
}
return errors;
}