Skip to content

Commit c1840a0

Browse files
authored
Issue #108: Opened constructor and fixed NPE (#115)
Issue #108: Opened constructor and fixed NPE In some use cases it is required to pass in all three parameters into `DynamoDBTemplate` - therefore made the internal constructor public (that was used by all other constructors anyway) Also passing in a combination of `null`/non-`null` parameters could lead to NPEs down the road - ie. by calling `getOverrideTableName`. The constructor now initalizes all fields with non-`null` objects and does not relay on AWS constructors to pick some proper default configs.
1 parent b7f52d8 commit c1840a0

File tree

6 files changed

+65
-32
lines changed

6 files changed

+65
-32
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.class
22
.project
3+
.metadata
34
target
45
*.iml
56
.idea

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
<action dev="derjust" issue="103" type="add" date="2018-01-07">
1414
Update Marshaller to use DynamoDBTypeConverter (while keeping old inheritance intact)
1515
</action>
16+
<action dev="derjust" issue="108" type="fix" date="2018-01-14">
17+
Opened constructor and fixed NPE in case of missing DynamoDBConfig
18+
</action>
1619
</release>
1720
<release version="5.0.1" date="2018-01-06" description="Maintenance release">
1821
<action dev="derjust" issue="68" type="fix" date="2017-12-01" >

src/main/java/org/socialsignin/spring/data/dynamodb/core/DynamoDBTemplate.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.context.ApplicationContext;
2626
import org.springframework.context.ApplicationContextAware;
2727
import org.springframework.context.ApplicationEventPublisher;
28+
import org.springframework.util.Assert;
2829

2930
import java.util.List;
3031
import java.util.Map;
@@ -36,36 +37,45 @@ public class DynamoDBTemplate implements DynamoDBOperations, ApplicationContextA
3637
private final DynamoDBMapperConfig dynamoDBMapperConfig;
3738
private ApplicationEventPublisher eventPublisher;
3839

40+
/** Convenient constructor to use the default {@link DynamoDBMapper#DynamoDBMapper(AmazonDynamoDB)} */
3941
public DynamoDBTemplate(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig dynamoDBMapperConfig)
4042
{
4143
this(amazonDynamoDB, dynamoDBMapperConfig, null);
4244
}
4345

46+
/** Convenient constructor to use the {@link DynamoDBMapperConfig.DEFAULT} */
47+
4448
public DynamoDBTemplate(AmazonDynamoDB amazonDynamoDB, DynamoDBMapper dynamoDBMapper)
4549
{
4650
this(amazonDynamoDB, null, dynamoDBMapper);
4751
}
4852

53+
/** Convenient construcotr to thse the {@link DynamoDBMapperConfig.DEFAULT} and default {@link DynamoDBMapper#DynamoDBMapper(AmazonDynamoDB)} */
4954
public DynamoDBTemplate(AmazonDynamoDB amazonDynamoDB)
5055
{
5156
this(amazonDynamoDB, null, null);
5257
}
5358

54-
DynamoDBTemplate(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig dynamoDBMapperConfig, DynamoDBMapper dynamoDBMapper) {
55-
this.amazonDynamoDB = amazonDynamoDB;
56-
if (dynamoDBMapper == null && dynamoDBMapperConfig == null) {
57-
this.dynamoDBMapperConfig = DynamoDBMapperConfig.DEFAULT;
58-
this.dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB);
59-
// Mapper must be null as it could not have been constructed without a Config
60-
assert dynamoDBMapper == null;
61-
} else {
62-
this.dynamoDBMapperConfig = dynamoDBMapperConfig;
63-
if (dynamoDBMapper == null) {
64-
this.dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB, dynamoDBMapperConfig);
65-
} else {
66-
this.dynamoDBMapper = dynamoDBMapper;
67-
}
68-
}
59+
/** Initializes a new {@code DynamoDBTemplate}.
60+
* The following combinations are valid:
61+
* @param amazonDynamoDB must not be {@code null}
62+
* @param dynamoDBMapperConfig can be {@code null} - {@link DynamoDBMapperConfig.DEFAULT} is used if {@code null} is passed in
63+
* @param dynamoDBMapper can be {@code null} - {@link DynamoDBMapper#DynamoDBMapper(AmazonDynamoDB, DynamoDBMapperConfig)} is used if {@code null} is passed in */
64+
public DynamoDBTemplate(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig dynamoDBMapperConfig, DynamoDBMapper dynamoDBMapper) {
65+
Assert.notNull(amazonDynamoDB, "amazonDynamoDB must not be null!");
66+
this.amazonDynamoDB = amazonDynamoDB;
67+
68+
if (dynamoDBMapperConfig == null) {
69+
this.dynamoDBMapperConfig = DynamoDBMapperConfig.DEFAULT;
70+
} else {
71+
this.dynamoDBMapperConfig = dynamoDBMapperConfig;
72+
}
73+
74+
if (dynamoDBMapper == null) {
75+
this.dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB, dynamoDBMapperConfig);
76+
} else {
77+
this.dynamoDBMapper = dynamoDBMapper;
78+
}
6979
}
7080

7181
@Override

src/test/java/org/socialsignin/spring/data/dynamodb/core/DynamoDBTemplateUnitTest.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,66 @@
44
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
55
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
66
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig.TableNameResolver;
7+
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
8+
79
import org.junit.Assert;
810
import org.junit.Before;
11+
import org.junit.Rule;
912
import org.junit.Test;
13+
import org.junit.rules.ExpectedException;
1014
import org.junit.runner.RunWith;
1115
import org.mockito.Mock;
1216
import org.mockito.Mockito;
1317
import org.mockito.junit.MockitoJUnitRunner;
1418
import org.socialsignin.spring.data.dynamodb.domain.sample.Playlist;
1519
import org.socialsignin.spring.data.dynamodb.domain.sample.User;
20+
import org.springframework.context.ApplicationContext;
1621

1722
import java.util.ArrayList;
1823
import java.util.List;
1924

25+
import static org.junit.Assert.assertEquals;
2026
import static org.junit.Assert.assertTrue;
2127

2228
@RunWith(MockitoJUnitRunner.class)
2329
public class DynamoDBTemplateUnitTest {
24-
30+
@Rule
31+
public ExpectedException expectedException = ExpectedException.none();
2532
@Mock
2633
private DynamoDBMapper dynamoDBMapper;
2734
@Mock
2835
private AmazonDynamoDB dynamoDB;
2936
@Mock
3037
private DynamoDBMapperConfig dynamoDBMapperConfig;
38+
@Mock
39+
private ApplicationContext applicationContext;
3140

3241
private DynamoDBTemplate dynamoDBTemplate;
3342

3443
@Before
3544
public void setUp() {
3645
this.dynamoDBTemplate = new DynamoDBTemplate(dynamoDB, dynamoDBMapperConfig, dynamoDBMapper);
46+
this.dynamoDBTemplate.setApplicationContext(applicationContext);
47+
}
48+
49+
@Test
50+
public void testConstructorMandatory() {
51+
expectedException.expect(IllegalArgumentException.class);
52+
expectedException.expectMessage("must not be null!");
53+
new DynamoDBTemplate(null);
54+
}
55+
56+
@Test
57+
public void testConstructorOptionalAllNull() {
58+
dynamoDBTemplate = new DynamoDBTemplate(dynamoDB, null, null);
59+
60+
// check that the defaults are properly initialized - #108
61+
String userTableName = dynamoDBTemplate.getOverriddenTableName(User.class, "UserTable");
62+
assertEquals("user", userTableName);
3763
}
3864

3965
@Test
40-
public void testPreconfiguredDynamoDBMapper() {
66+
public void testConstructorOptionalPreconfiguredDynamoDBMapper() {
4167
// Introduced constructor via #91 should not fail its assert
4268
DynamoDBTemplate usePreconfiguredDynamoDBMapper = new DynamoDBTemplate(dynamoDB, dynamoDBMapper);
4369

src/test/java/org/socialsignin/spring/data/dynamodb/mapping/event/AbstractDynamoDBEventListenerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class AbstractDynamoDBEventListenerTest {
2727
@Mock
2828
private PaginatedScanList<User> sampleScanList;
2929

30-
private AbstractDynamoDBEventListener underTest;
30+
private AbstractDynamoDBEventListener<User> underTest;
3131

3232
@Before
3333
public void setUp() {
@@ -42,7 +42,7 @@ public void setUp() {
4242

4343
@Test
4444
public void testAfterDelete() {
45-
underTest.onApplicationEvent(new AfterDeleteEvent(sampleEntity));
45+
underTest.onApplicationEvent(new AfterDeleteEvent<User>(sampleEntity));
4646

4747
verify(underTest).onAfterDelete(sampleEntity);
4848
verify(underTest, never()).onAfterLoad(any());
@@ -55,7 +55,7 @@ public void testAfterDelete() {
5555

5656
@Test
5757
public void testAfterLoad() {
58-
underTest.onApplicationEvent(new AfterLoadEvent(sampleEntity));
58+
underTest.onApplicationEvent(new AfterLoadEvent<>(sampleEntity));
5959

6060
verify(underTest, never()).onAfterDelete(any());
6161
verify(underTest).onAfterLoad(sampleEntity);
@@ -68,7 +68,7 @@ public void testAfterLoad() {
6868

6969
@Test
7070
public void testAfterQuery() {
71-
underTest.onApplicationEvent(new AfterQueryEvent(sampleQueryList));
71+
underTest.onApplicationEvent(new AfterQueryEvent<User>(sampleQueryList));
7272

7373
verify(underTest, never()).onAfterDelete(any());
7474
verify(underTest, never()).onAfterLoad(any());
@@ -81,7 +81,7 @@ public void testAfterQuery() {
8181

8282
@Test
8383
public void testAfterSave() {
84-
underTest.onApplicationEvent(new AfterSaveEvent(sampleEntity));
84+
underTest.onApplicationEvent(new AfterSaveEvent<>(sampleEntity));
8585

8686
verify(underTest, never()).onAfterDelete(any());
8787
verify(underTest, never()).onAfterLoad(any());
@@ -94,7 +94,7 @@ public void testAfterSave() {
9494

9595
@Test
9696
public void testAfterScan() {
97-
underTest.onApplicationEvent(new AfterScanEvent(sampleScanList));
97+
underTest.onApplicationEvent(new AfterScanEvent<>(sampleScanList));
9898

9999
verify(underTest, never()).onAfterDelete(any());
100100
verify(underTest, never()).onAfterLoad(any());
@@ -107,7 +107,7 @@ public void testAfterScan() {
107107

108108
@Test
109109
public void testBeforeDelete() {
110-
underTest.onApplicationEvent(new BeforeDeleteEvent(sampleEntity));
110+
underTest.onApplicationEvent(new BeforeDeleteEvent<>(sampleEntity));
111111

112112
verify(underTest, never()).onAfterDelete(any());
113113
verify(underTest, never()).onAfterLoad(any());
@@ -120,7 +120,7 @@ public void testBeforeDelete() {
120120

121121
@Test
122122
public void testBeforeSave() {
123-
underTest.onApplicationEvent(new BeforeSaveEvent(sampleEntity));
123+
underTest.onApplicationEvent(new BeforeSaveEvent<>(sampleEntity));
124124

125125
verify(underTest, never()).onAfterDelete(any());
126126
verify(underTest, never()).onAfterLoad(any());

src/test/java/org/socialsignin/spring/data/dynamodb/mapping/event/ValidatingDynamoDBEventListenerTest.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package org.socialsignin.spring.data.dynamodb.mapping.event;
22

3-
import com.amazonaws.services.dynamodbv2.document.Expected;
4-
import net.bytebuddy.pool.TypePool;
5-
import org.hamcrest.core.CombinableMatcher;
6-
import org.hamcrest.core.StringContains;
73
import org.junit.Before;
84
import org.junit.Rule;
95
import org.junit.Test;
@@ -15,13 +11,10 @@
1511

1612
import javax.validation.ConstraintViolation;
1713
import javax.validation.ConstraintViolationException;
18-
import javax.validation.Path;
1914
import javax.validation.Validator;
20-
import javax.validation.metadata.ConstraintDescriptor;
2115

2216
import java.util.HashSet;
2317
import java.util.Set;
24-
import java.util.concurrent.ExecutionException;
2518

2619
import static org.hamcrest.CoreMatchers.allOf;
2720
import static org.hamcrest.CoreMatchers.containsString;

0 commit comments

Comments
 (0)