Skip to content

Commit 82abf6d

Browse files
authored
Added debug-level logging for BeanTableSchema and ImmutableTableSchema. (#3006)
Enabling 'software.amazon.awssdk.enhanced.dynamodb.beans' debug logging should make it easier to debug why certain properties are being loaded or ignored. The following bean: ```java @DynamoDbBean public class SimpleBean { private String id; private Integer integerAttribute; @DynamoDbPartitionKey public String getId() { return this.id; } public void setId(String id) { this.id = id; } public Integer getIntegerAttribute() { return integerAttribute; } public void setIntegerAttribute(Integer integerAttribute) { this.integerAttribute = integerAttribute; } } ``` Generates the following log messages: ``` 14:53:27.222 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Creating bean schema 14:53:27.245 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Constructor: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean() 14:53:27.373 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Adding Converter: software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider 14:53:27.373 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Constructor: public software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider() 14:53:27.376 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Ignoring bean property class because it has no write (set) method. 14:53:27.383 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Property id read method: public java.lang.String software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean.getId() 14:53:27.385 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Property id write method: public void software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean.setId(java.lang.String) 14:53:27.400 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Property integerAttribute read method: public java.lang.Integer software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean.getIntegerAttribute() 14:53:27.400 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean - Property integerAttribute write method: public void software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.SimpleBean.setIntegerAttribute(java.lang.Integer) 14:53:27.406 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Converter for EnhancedType(java.lang.String): software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.StringAttributeConverter 14:53:27.419 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Converter for EnhancedType(java.lang.Integer): software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.IntegerAttributeConverter ``` The following immutable: ```java @DynamoDbImmutable(builder = FlattenedBeanImmutable.Builder.class) public class FlattenedBeanImmutable { private final String id; private final String attribute1; private final AbstractBean abstractBean; private FlattenedBeanImmutable(Builder b) { this.id = b.id; this.attribute1 = b.attribute1; this.abstractBean = b.abstractBean; } @DynamoDbPartitionKey public String getId() { return this.id; } public String getAttribute1() { return attribute1; } @DynamoDbFlatten public AbstractBean getAbstractBean() { return abstractBean; } public static final class Builder { private String id; private String attribute1; private AbstractBean abstractBean; public Builder setId(String id) { this.id = id; return this; } public Builder setAttribute1(String attribute1) { this.attribute1 = attribute1; return this; } public Builder setAbstractBean(AbstractBean abstractBean) { this.abstractBean = abstractBean; return this; } public FlattenedBeanImmutable build() { return new FlattenedBeanImmutable(this); } } } ``` Generates the following log messages: ``` 14:50:43.995 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable - Creating immutable schema 14:50:44.062 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder - Constructor: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder() 14:50:44.134 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable - Adding Converter: software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider 14:50:44.134 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Constructor: public software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider() 14:50:44.141 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable - Property id read method: public java.lang.String software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable.getId() 14:50:44.142 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder - Property id write method: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder.setId(java.lang.String) 14:50:44.158 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable - Property attribute1 read method: public java.lang.String software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable.getAttribute1() 14:50:44.158 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder - Property attribute1 write method: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder.setAttribute1(java.lang.String) 14:50:44.166 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean - Creating bean schema 14:50:44.175 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean - Constructor: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean() 14:50:44.178 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean - Adding Converter: software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider 14:50:44.178 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Constructor: public software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider() 14:50:44.182 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean - Property attribute2 read method: public java.lang.String software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean.getAttribute2() 14:50:44.183 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean - Property attribute2 write method: public void software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean.setAttribute2(java.lang.String) 14:50:44.185 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean - Ignoring bean property class because it has no write (set) method. 14:50:44.189 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Converter for EnhancedType(java.lang.String): software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.StringAttributeConverter 14:50:44.205 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable - Property abstractBean read method: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable.getAbstractBean() 14:50:44.206 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.beans - software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder - Property abstractBean write method: public software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.FlattenedBeanImmutable$Builder.setAbstractBean(software.amazon.awssdk.enhanced.dynamodb.mapper.testbeans.AbstractBean) 14:50:44.206 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Converter for EnhancedType(java.lang.String): software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.StringAttributeConverter 14:50:44.209 [main] DEBUG software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider - Converter for EnhancedType(java.lang.String): software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.StringAttributeConverter ```
1 parent 84b2470 commit 82abf6d

File tree

8 files changed

+167
-18
lines changed

8 files changed

+167
-18
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "Amazon DynamoDB Enhanced Client",
3+
"contributor": "",
4+
"type": "feature",
5+
"description": "Added logging to 'software.amazon.awssdk.enhanced.dynamodb.beans', which will assist when debugging the behavior of BeanTableSchema and ImmutableTableSchema."
6+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DefaultAttributeConverterProvider.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,16 @@ public <T> AttributeConverter<T> converterFor(EnhancedType<T> type) {
139139
*/
140140
@SuppressWarnings("unchecked")
141141
private <T> Optional<AttributeConverter<T>> findConverter(EnhancedType<T> type) {
142-
log.debug(() -> "Loading converter for " + type + ".");
142+
Optional<AttributeConverter<T>> converter = findConverterInternal(type);
143+
if (converter.isPresent()) {
144+
log.debug(() -> "Converter for " + type + ": " + converter.get().getClass().getTypeName());
145+
} else {
146+
log.debug(() -> "No converter available for " + type);
147+
}
148+
return converter;
149+
}
143150

151+
private <T> Optional<AttributeConverter<T>> findConverterInternal(EnhancedType<T> type) {
144152
AttributeConverter<T> converter = (AttributeConverter<T>) converterCache.get(type);
145153
if (converter != null) {
146154
return Optional.of(converter);

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/TableSchema.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ static <T> ImmutableTableSchema<T> fromImmutableClass(Class<T> immutableClass) {
108108
* This is a moderately expensive operation, and should be performed sparingly. This is usually done once at
109109
* application startup.
110110
*
111+
* If this table schema is not behaving as you expect, enable debug logging for
112+
* 'software.amazon.awssdk.enhanced.dynamodb.beans'.
113+
*
111114
* @param annotatedClass A class that has been annotated with DynamoDb enhanced client annotations.
112115
* @param <T> The type of the item this {@link TableSchema} will map records to.
113116
* @return An initialized {@link TableSchema}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.enhanced.dynamodb.internal;
17+
18+
import software.amazon.awssdk.annotations.SdkInternalApi;
19+
import software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema;
20+
import software.amazon.awssdk.enhanced.dynamodb.mapper.ImmutableTableSchema;
21+
import software.amazon.awssdk.utils.Logger;
22+
23+
@SdkInternalApi
24+
public class DynamoDbEnhancedLogger {
25+
/**
26+
* Logger used for to assist customers in debugging {@link BeanTableSchema} and {@link ImmutableTableSchema} loading.
27+
*/
28+
public static final Logger BEAN_LOGGER = Logger.loggerFor("software.amazon.awssdk.enhanced.dynamodb.beans");
29+
30+
private DynamoDbEnhancedLogger() {
31+
}
32+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/mapper/BeanTableSchema.java

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515

1616
package software.amazon.awssdk.enhanced.dynamodb.mapper;
1717

18+
import static software.amazon.awssdk.enhanced.dynamodb.internal.DynamoDbEnhancedLogger.BEAN_LOGGER;
19+
1820
import java.beans.BeanInfo;
1921
import java.beans.IntrospectionException;
2022
import java.beans.Introspector;
2123
import java.beans.PropertyDescriptor;
2224
import java.lang.annotation.Annotation;
25+
import java.lang.reflect.Constructor;
2326
import java.lang.reflect.InvocationTargetException;
2427
import java.lang.reflect.Method;
2528
import java.lang.reflect.Modifier;
@@ -96,6 +99,8 @@
9699
* Creating an {@link BeanTableSchema} is a moderately expensive operation, and should be performed sparingly. This is
97100
* usually done once at application startup.
98101
*
102+
* If this table schema is not behaving as you expect, enable debug logging for 'software.amazon.awssdk.enhanced.dynamodb.beans'.
103+
*
99104
* @param <T> The type of object that this {@link TableSchema} maps to.
100105
*/
101106
@SdkPublicApi
@@ -122,6 +127,7 @@ public static <T> BeanTableSchema<T> create(Class<T> beanClass) {
122127
}
123128

124129
private static <T> BeanTableSchema<T> create(Class<T> beanClass, MetaTableSchemaCache metaTableSchemaCache) {
130+
debugLog(beanClass, () -> "Creating bean schema");
125131
// Fetch or create a new reference to this yet-to-be-created TableSchema in the cache
126132
MetaTableSchema<T> metaTableSchema = metaTableSchemaCache.getOrCreate(beanClass);
127133

@@ -158,7 +164,8 @@ private static <T> StaticTableSchema<T> createStaticTableSchema(Class<T> beanCla
158164
DynamoDbBean dynamoDbBean = beanClass.getAnnotation(DynamoDbBean.class);
159165

160166
if (dynamoDbBean == null) {
161-
throw new IllegalArgumentException("A DynamoDb bean class must be annotated with @DynamoDbBean");
167+
throw new IllegalArgumentException("A DynamoDb bean class must be annotated with @DynamoDbBean, but " +
168+
beanClass.getTypeName() + " was not.");
162169
}
163170

164171
BeanInfo beanInfo;
@@ -174,12 +181,12 @@ private static <T> StaticTableSchema<T> createStaticTableSchema(Class<T> beanCla
174181
StaticTableSchema.Builder<T> builder = StaticTableSchema.builder(beanClass)
175182
.newItemSupplier(newObjectSupplier);
176183

177-
builder.attributeConverterProviders(createConverterProvidersFromAnnotation(dynamoDbBean));
184+
builder.attributeConverterProviders(createConverterProvidersFromAnnotation(beanClass, dynamoDbBean));
178185

179186
List<StaticAttribute<T, ?>> attributes = new ArrayList<>();
180187

181188
Arrays.stream(beanInfo.getPropertyDescriptors())
182-
.filter(BeanTableSchema::isMappableProperty)
189+
.filter(p -> isMappableProperty(beanClass, p))
183190
.forEach(propertyDescriptor -> {
184191
DynamoDbFlatten dynamoDbFlatten = getPropertyAnnotation(propertyDescriptor, DynamoDbFlatten.class);
185192

@@ -221,12 +228,14 @@ private static AttributeConfiguration resolveAttributeConfiguration(PropertyDesc
221228
.build();
222229
}
223230

224-
private static List<AttributeConverterProvider> createConverterProvidersFromAnnotation(DynamoDbBean dynamoDbBean) {
231+
private static List<AttributeConverterProvider> createConverterProvidersFromAnnotation(Class<?> beanClass,
232+
DynamoDbBean dynamoDbBean) {
225233
Class<? extends AttributeConverterProvider>[] providerClasses = dynamoDbBean.converterProviders();
226234

227235
return Arrays.stream(providerClasses)
228-
.map(c -> (AttributeConverterProvider) newObjectSupplierForClass(c).get())
229-
.collect(Collectors.toList());
236+
.peek(c -> debugLog(beanClass, () -> "Adding Converter: " + c.getTypeName()))
237+
.map(c -> (AttributeConverterProvider) newObjectSupplierForClass(c).get())
238+
.collect(Collectors.toList());
230239
}
231240

232241
private static <T> StaticAttribute.Builder<T, ?> staticAttributeBuilder(PropertyDescriptor propertyDescriptor,
@@ -358,7 +367,9 @@ private static void addTagsToAttribute(StaticAttribute.Builder<?, ?> attributeBu
358367

359368
private static <R> Supplier<R> newObjectSupplierForClass(Class<R> clazz) {
360369
try {
361-
return ObjectConstructor.create(clazz, clazz.getConstructor());
370+
Constructor<R> constructor = clazz.getConstructor();
371+
debugLog(clazz, () -> "Constructor: " + constructor);
372+
return ObjectConstructor.create(clazz, constructor);
362373
} catch (NoSuchMethodException e) {
363374
throw new IllegalArgumentException(
364375
String.format("Class '%s' appears to have no default constructor thus cannot be used with the " +
@@ -368,12 +379,14 @@ private static <R> Supplier<R> newObjectSupplierForClass(Class<R> clazz) {
368379

369380
private static <T, R> Function<T, R> getterForProperty(PropertyDescriptor propertyDescriptor, Class<T> beanClass) {
370381
Method readMethod = propertyDescriptor.getReadMethod();
382+
debugLog(beanClass, () -> "Property " + propertyDescriptor.getDisplayName() + " read method: " + readMethod);
371383
return BeanAttributeGetter.create(beanClass, readMethod);
372384
}
373385

374386
private static <T, R> BiConsumer<T, R> setterForProperty(PropertyDescriptor propertyDescriptor,
375387
Class<T> beanClass) {
376388
Method writeMethod = propertyDescriptor.getWriteMethod();
389+
debugLog(beanClass, () -> "Property " + propertyDescriptor.getDisplayName() + " write method: " + writeMethod);
377390
return BeanAttributeSetter.create(beanClass, writeMethod);
378391
}
379392

@@ -386,10 +399,27 @@ private static String attributeNameForProperty(PropertyDescriptor propertyDescri
386399
return propertyDescriptor.getName();
387400
}
388401

389-
private static boolean isMappableProperty(PropertyDescriptor propertyDescriptor) {
390-
return propertyDescriptor.getReadMethod() != null
391-
&& propertyDescriptor.getWriteMethod() != null
392-
&& getPropertyAnnotation(propertyDescriptor, DynamoDbIgnore.class) == null;
402+
private static boolean isMappableProperty(Class<?> beanClass, PropertyDescriptor propertyDescriptor) {
403+
404+
if (propertyDescriptor.getReadMethod() == null) {
405+
debugLog(beanClass, () -> "Ignoring bean property " + propertyDescriptor.getDisplayName() + " because it has no "
406+
+ "read (get/is) method.");
407+
return false;
408+
}
409+
410+
if (propertyDescriptor.getWriteMethod() == null) {
411+
debugLog(beanClass, () -> "Ignoring bean property " + propertyDescriptor.getDisplayName() + " because it has no "
412+
+ "write (set) method.");
413+
return false;
414+
}
415+
416+
if (getPropertyAnnotation(propertyDescriptor, DynamoDbIgnore.class) != null) {
417+
debugLog(beanClass, () -> "Ignoring bean property " + propertyDescriptor.getDisplayName() + " because it has "
418+
+ "@DynamoDbIgnore.");
419+
return false;
420+
}
421+
422+
return true;
393423
}
394424

395425
private static <R extends Annotation> R getPropertyAnnotation(PropertyDescriptor propertyDescriptor,
@@ -401,6 +431,9 @@ private static <R extends Annotation> R getPropertyAnnotation(PropertyDescriptor
401431
return getterAnnotation;
402432
}
403433

434+
// TODO: It's a common mistake that superclasses might have annotations that the child classes do not inherit, but the
435+
// customer expects them to be inherited. We should either allow inheriting those annotations, allow specifying an
436+
// annotation to inherit them, or log when this situation happens.
404437
return setterAnnotation;
405438
}
406439

@@ -409,5 +442,9 @@ private static List<? extends Annotation> propertyAnnotations(PropertyDescriptor
409442
Arrays.stream(propertyDescriptor.getWriteMethod().getAnnotations()))
410443
.collect(Collectors.toList());
411444
}
445+
446+
private static void debugLog(Class<?> beanClass, Supplier<String> logMessage) {
447+
BEAN_LOGGER.debug(() -> beanClass.getTypeName() + " - " + logMessage.get());
448+
}
412449
}
413450

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/mapper/ImmutableTableSchema.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515

1616
package software.amazon.awssdk.enhanced.dynamodb.mapper;
1717

18+
import static software.amazon.awssdk.enhanced.dynamodb.internal.DynamoDbEnhancedLogger.BEAN_LOGGER;
19+
1820
import java.lang.annotation.Annotation;
21+
import java.lang.reflect.Constructor;
1922
import java.lang.reflect.InvocationTargetException;
2023
import java.lang.reflect.Method;
2124
import java.lang.reflect.Modifier;
@@ -96,6 +99,8 @@
9699
* Creating an {@link ImmutableTableSchema} is a moderately expensive operation, and should be performed sparingly. This is
97100
* usually done once at application startup.
98101
*
102+
* If this table schema is not behaving as you expect, enable debug logging for 'software.amazon.awssdk.enhanced.dynamodb.beans'.
103+
*
99104
* @param <T> The type of object that this {@link TableSchema} maps to.
100105
*/
101106
@SdkPublicApi
@@ -123,6 +128,8 @@ public static <T> ImmutableTableSchema<T> create(Class<T> immutableClass) {
123128

124129
private static <T> ImmutableTableSchema<T> create(Class<T> immutableClass,
125130
MetaTableSchemaCache metaTableSchemaCache) {
131+
debugLog(immutableClass, () -> "Creating immutable schema");
132+
126133
// Fetch or create a new reference to this yet-to-be-created TableSchema in the cache
127134
MetaTableSchema<T> metaTableSchema = metaTableSchemaCache.getOrCreate(immutableClass);
128135

@@ -175,7 +182,7 @@ private static <T, B> StaticImmutableTableSchema<T, B> createStaticImmutableTab
175182
.newItemBuilder(newBuilderSupplier, buildFunction);
176183

177184
builder.attributeConverterProviders(
178-
createConverterProvidersFromAnnotation(immutableClass.getAnnotation(DynamoDbImmutable.class)));
185+
createConverterProvidersFromAnnotation(immutableClass, immutableClass.getAnnotation(DynamoDbImmutable.class)));
179186

180187
List<ImmutableAttribute<T, B, ?>> attributes = new ArrayList<>();
181188

@@ -210,14 +217,15 @@ private static <T, B> StaticImmutableTableSchema<T, B> createStaticImmutableTab
210217
return builder.build();
211218
}
212219

213-
private static List<AttributeConverterProvider> createConverterProvidersFromAnnotation(
214-
DynamoDbImmutable dynamoDbImmutable) {
220+
private static List<AttributeConverterProvider> createConverterProvidersFromAnnotation(Class<?> immutableClass,
221+
DynamoDbImmutable dynamoDbImmutable) {
215222

216223
Class<? extends AttributeConverterProvider>[] providerClasses = dynamoDbImmutable.converterProviders();
217224

218225
return Arrays.stream(providerClasses)
219-
.map(c -> (AttributeConverterProvider) newObjectSupplierForClass(c).get())
220-
.collect(Collectors.toList());
226+
.peek(c -> debugLog(immutableClass, () -> "Adding Converter: " + c.getTypeName()))
227+
.map(c -> (AttributeConverterProvider) newObjectSupplierForClass(c).get())
228+
.collect(Collectors.toList());
221229
}
222230

223231
private static <T, B> ImmutableAttribute.Builder<T, B, ?> immutableAttributeBuilder(
@@ -359,7 +367,9 @@ private static <T, R> Supplier<R> newObjectSupplier(ImmutableInfo<T> immutableIn
359367

360368
private static <R> Supplier<R> newObjectSupplierForClass(Class<R> clazz) {
361369
try {
362-
return ObjectConstructor.create(clazz, clazz.getConstructor());
370+
Constructor<R> constructor = clazz.getConstructor();
371+
debugLog(clazz, () -> "Constructor: " + constructor);
372+
return ObjectConstructor.create(clazz, constructor);
363373
} catch (NoSuchMethodException e) {
364374
throw new IllegalArgumentException(
365375
String.format("Builder class '%s' appears to have no default constructor thus cannot be used with " +
@@ -370,12 +380,14 @@ private static <R> Supplier<R> newObjectSupplierForClass(Class<R> clazz) {
370380
private static <T, R> Function<T, R> getterForProperty(ImmutablePropertyDescriptor propertyDescriptor,
371381
Class<T> immutableClass) {
372382
Method readMethod = propertyDescriptor.getter();
383+
debugLog(immutableClass, () -> "Property " + propertyDescriptor.name() + " read method: " + readMethod);
373384
return BeanAttributeGetter.create(immutableClass, readMethod);
374385
}
375386

376387
private static <T, R> BiConsumer<T, R> setterForProperty(ImmutablePropertyDescriptor propertyDescriptor,
377388
Class<T> builderClass) {
378389
Method writeMethod = propertyDescriptor.setter();
390+
debugLog(builderClass, () -> "Property " + propertyDescriptor.name() + " write method: " + writeMethod);
379391
return BeanAttributeSetter.create(builderClass, writeMethod);
380392
}
381393

@@ -419,5 +431,8 @@ private static AttributeConfiguration resolveAttributeConfiguration(ImmutablePro
419431
.build();
420432
}
421433

434+
private static void debugLog(Class<?> beanClass, Supplier<String> logMessage) {
435+
BEAN_LOGGER.debug(() -> beanClass.getTypeName() + " - " + logMessage.get());
436+
}
422437
}
423438

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License").
5+
# You may not use this file except in compliance with the License.
6+
# A copy of the License is located at
7+
#
8+
# http://aws.amazon.com/apache2.0
9+
#
10+
# or in the "license" file accompanying this file. This file is distributed
11+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
# express or implied. See the License for the specific language governing
13+
# permissions and limitations under the License.
14+
#
15+
16+
status = warn
17+
18+
appender.console.type = Console
19+
appender.console.name = ConsoleAppender
20+
appender.console.layout.type = PatternLayout
21+
appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n%throwable
22+
23+
rootLogger.level = debug
24+
rootLogger.appenderRef.stdout.ref = ConsoleAppender

services-custom/pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,28 @@
4343
</dependency>
4444
</dependencies>
4545
</dependencyManagement>
46+
47+
<dependencies>
48+
<dependency>
49+
<groupId>org.apache.logging.log4j</groupId>
50+
<artifactId>log4j-api</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.apache.logging.log4j</groupId>
55+
<artifactId>log4j-core</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.apache.logging.log4j</groupId>
60+
<artifactId>log4j-slf4j-impl</artifactId>
61+
<scope>test</scope>
62+
</dependency>
63+
<dependency>
64+
<groupId>org.slf4j</groupId>
65+
<artifactId>jcl-over-slf4j</artifactId>
66+
<scope>test</scope>
67+
<version>${slf4j.version}</version>
68+
</dependency>
69+
</dependencies>
4670
</project>

0 commit comments

Comments
 (0)