@SuppressWarnings("unchecked")
Class<? extends T> clazz = (Class<? extends T>) object.getClass();
String tableName = getTableName(clazz, config);
Method hashKeyGetter = reflector.getHashKeyGetter(clazz);
AttributeValue hashKeyElement = getHashKeyElement(safeInvoke(hashKeyGetter, object), hashKeyGetter);
AttributeValue rangeKeyElement = null;
Method rangeKeyGetter = reflector.getRangeKeyGetter(clazz);
if ( rangeKeyGetter != null ) {
rangeKeyElement = getRangeKeyElement(safeInvoke(rangeKeyGetter, object), rangeKeyGetter);
}
Key objectKey = new Key().withHashKeyElement(hashKeyElement).withRangeKeyElement(rangeKeyElement);
Map<String, AttributeValueUpdate> updateValues = new HashMap<String, AttributeValueUpdate>();
Map<String, ExpectedAttributeValue> expectedValues = new HashMap<String, ExpectedAttributeValue>();
boolean forcePut = config.getSaveBehavior() == SaveBehavior.CLOBBER;
boolean nonKeyAttributePresent = false;
List<ValueUpdate> inMemoryUpdates = new LinkedList<ValueUpdate>();
/*
* First look at the keys and construct updates for them independently
*/
List<Method> keyGetterMethods = new LinkedList<Method>();
keyGetterMethods.add(hashKeyGetter);
if ( rangeKeyGetter != null ) {
keyGetterMethods.add(rangeKeyGetter);
}
/*
* Determine if there are any auto-assigned keys to assign. If so, force
* a put and assign the keys
*/
if ( !forcePut ) {
for ( Method method : keyGetterMethods ) {
Object getterResult = safeInvoke(method, object);
if ( getterResult == null && reflector.isAssignableKey(method) ) {
forcePut = true;
}
}
}
/*
* If we're doing a put, that means that we need update values for the
* key attributes.
*/
if ( forcePut ) {
for ( Method method : keyGetterMethods ) {
Object getterResult = safeInvoke(method, object);
String attributeName = reflector.getAttributeName(method);
if ( getterResult == null && reflector.isAssignableKey(method) ) {
AttributeValue newVersionValue = getAutoGeneratedKeyAttributeValue(method, getterResult);
updateValues.put(attributeName,
new AttributeValueUpdate().withAction("PUT").withValue(newVersionValue));
inMemoryUpdates.add(new ValueUpdate(method, newVersionValue, object));
if ( config.getSaveBehavior() != SaveBehavior.CLOBBER ) {
// Add an expect clause to make sure that the item
// doesn't already exist, since it's supposed to be new
ExpectedAttributeValue expected = new ExpectedAttributeValue();
expected.setExists(false);
expectedValues.put(attributeName, expected);
}
} else {
AttributeValue currentValue = getSimpleAttributeValue(method, getterResult);
if ( currentValue != null ) {
updateValues.put(attributeName,
new AttributeValueUpdate().withValue(currentValue).withAction("PUT"));
} else {
throw new DynamoDBMappingException("Null value for non-generated key for method " + method);
}
}
}
} else {
/*
* If we don't have the required keys by this point, it's an error
*/
if ( hashKeyElement == null ) {
throw new DynamoDBMappingException("No value provided for hash key for object " + object);
}
if ( rangeKeyGetter != null && rangeKeyElement == null ) {
throw new DynamoDBMappingException("No value provided for range key for object " + object);
}
}
// Look at every getter and construct an update object for it
for ( Method method : reflector.getRelevantGetters(clazz) ) {
// Skip any key methods, since they are handled separately
if ( method.equals(hashKeyGetter) || method.equals(rangeKeyGetter) )
continue;
nonKeyAttributePresent = true;
Object getterResult = safeInvoke(method, object);
String attributeName = reflector.getAttributeName(method);
/*
* If this is a versioned field, update it
*/
if ( reflector.isVersionAttributeGetter(method) ) {
if ( config.getSaveBehavior() != SaveBehavior.CLOBBER ) {
// First establish the expected (current) value for the
// update call
ExpectedAttributeValue expected = new ExpectedAttributeValue();
// For new objects, insist that the value doesn't exist.
// For existing ones, insist it has the old value.
AttributeValue currentValue = getSimpleAttributeValue(method, getterResult);
expected.setExists(currentValue != null);
if ( currentValue != null ) {
expected.setValue(currentValue);
}
expectedValues.put(attributeName, expected);
}
AttributeValue newVersionValue = getVersionAttributeValue(method, getterResult);
updateValues
.put(attributeName, new AttributeValueUpdate().withAction("PUT").withValue(newVersionValue));
inMemoryUpdates.add(new ValueUpdate(method, newVersionValue, object));
}
/*
* Otherwise apply the update value for this attribute.
*/
else {
AttributeValue currentValue = getSimpleAttributeValue(method, getterResult);
if ( currentValue != null ) {
updateValues.put(attributeName, new AttributeValueUpdate().withValue(currentValue)
.withAction("PUT"));
} else if ( config.getSaveBehavior() != SaveBehavior.CLOBBER ) {
updateValues.put(attributeName, new AttributeValueUpdate().withAction("DELETE"));