Skip to content

Commit 1a510ed

Browse files
Alexandre Dutraolim7t
authored andcommitted
JAVA-636: Allow @column annotations on getters/setters as well as fields
This commit also includes a refactoring of the mapper internals: - ColumnMapper renamed to PropertyMapper; - No more factory patterns to create mappers; - ReflectionX classes removed and merged into their parent classes; - QueryType class cleanup.
1 parent 068bf46 commit 1a510ed

31 files changed

Lines changed: 835 additions & 656 deletions

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [improvement] JAVA-1212: Don't retry non-idempotent statements by default.
1212
- [improvement] JAVA-1192: Make EventDebouncer settings updatable at runtime.
1313
- [new feature] JAVA-541: Add polymorphism support to object mapper.
14+
- [new feature] JAVA-636: Allow @Column annotations on getters/setters as well as fields.
1415

1516
Merged from 3.0.x branch:
1617

clirr-ignores.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
-->
1414
<differences>
1515

16+
<difference>
17+
<differenceType>8001</differenceType> <!-- class removed -->
18+
<className>com/datastax/driver/mapping/ColumnMapper$Kind</className>
19+
<justification>False positive, the enclosing class is package-private so this was never exposed</justification>
20+
</difference>
21+
22+
1623
<difference>
1724
<differenceType>1001</differenceType> <!-- decreased visibility -->
1825
<className>com/datastax/driver/mapping/ColumnMapper$Kind</className>

driver-core/src/main/java/com/datastax/driver/core/ClusteringOrder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ public enum ClusteringOrder {
2525

2626
ASC, DESC;
2727

28-
}
28+
}

driver-mapping/src/main/java/com/datastax/driver/mapping/AccessorMapper.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,35 @@
1919
import com.google.common.util.concurrent.Futures;
2020
import com.google.common.util.concurrent.ListenableFuture;
2121

22+
import java.lang.reflect.Proxy;
2223
import java.util.ArrayList;
2324
import java.util.List;
2425

25-
abstract class AccessorMapper<T> {
26+
class AccessorMapper<T> {
2627

27-
public final Class<T> daoClass;
28-
protected final List<MethodMapper> methods;
28+
final Class<T> daoClass;
29+
final List<MethodMapper> methods;
30+
private final Class<T>[] proxyClasses;
31+
private final AccessorInvocationHandler<T> handler;
2932

30-
protected AccessorMapper(Class<T> daoClass, List<MethodMapper> methods) {
33+
@SuppressWarnings({"unchecked", "rawtypes"})
34+
AccessorMapper(Class<T> daoClass, List<MethodMapper> methods) {
3135
this.daoClass = daoClass;
3236
this.methods = methods;
37+
this.proxyClasses = (Class<T>[]) new Class[]{daoClass};
38+
this.handler = new AccessorInvocationHandler<T>(this);
3339
}
3440

35-
abstract T createProxy();
41+
@SuppressWarnings("unchecked")
42+
T createProxy() {
43+
try {
44+
return (T) Proxy.newProxyInstance(daoClass.getClassLoader(), proxyClasses, handler);
45+
} catch (Exception e) {
46+
throw new RuntimeException("Cannot create instance for Accessor interface " + daoClass.getName());
47+
}
48+
}
3649

37-
public void prepare(MappingManager manager) {
50+
void prepare(MappingManager manager) {
3851
List<ListenableFuture<PreparedStatement>> statements = new ArrayList<ListenableFuture<PreparedStatement>>(methods.size());
3952

4053
for (MethodMapper method : methods)
@@ -49,7 +62,4 @@ public void prepare(MappingManager manager) {
4962
}
5063
}
5164

52-
interface Factory {
53-
public <T> AccessorMapper<T> create(Class<T> daoClass, List<MethodMapper> methods);
54-
}
5565
}

driver-mapping/src/main/java/com/datastax/driver/mapping/AccessorReflectionMapper.java

Lines changed: 0 additions & 55 deletions
This file was deleted.

driver-mapping/src/main/java/com/datastax/driver/mapping/AnnotationChecks.java

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ private static void validateAnnotations(Class<?> clazz, Class<? extends Annotati
6161
/**
6262
* Checks that a field is only annotated with the given mapping annotations, and that its "frozen" annotations are valid.
6363
*/
64-
static void validateAnnotations(MappedProperty<?> property, Class<? extends Annotation>... allowed) {
65-
Class<? extends Annotation> invalid = validateAnnotations(property.annotations(), allowed);
64+
static void validateAnnotations(PropertyMapper property, Class<? extends Annotation>... allowed) {
65+
Class<? extends Annotation> invalid = validateAnnotations(property.getAnnotations(), allowed);
6666
if (invalid != null)
6767
throw new IllegalArgumentException(String.format("Annotation @%s is not allowed on property %s",
6868
invalid.getSimpleName(),
@@ -88,41 +88,37 @@ private static boolean contains(Object[] array, Object target) {
8888
return false;
8989
}
9090

91-
private static void checkValidPrimaryKey(MappedProperty<?> property) {
91+
private static void checkValidPrimaryKey(PropertyMapper property) {
9292
if (property.isPartitionKey() && property.isClusteringColumn())
93-
throw new IllegalArgumentException("Property " + property.name() + " cannot have both the @PartitionKey and @ClusteringColumn annotations");
93+
throw new IllegalArgumentException("Property " + property + " cannot have both the @PartitionKey and @ClusteringColumn annotations");
9494
}
9595

96-
private static void checkValidComputed(MappedProperty<?> property) {
96+
private static void checkValidComputed(PropertyMapper property) {
9797
if (property.isComputed()) {
9898
Computed computed = property.annotation(Computed.class);
9999
if (computed.value().isEmpty()) {
100-
throw new IllegalArgumentException(String.format("Property %s: attribute 'value' of annotation @Computed is mandatory for computed properties", property.name()));
100+
throw new IllegalArgumentException(String.format("Property %s: attribute 'value' of annotation @Computed is mandatory for computed properties", property));
101101
}
102102
if (property.hasAnnotation(Column.class)) {
103103
throw new IllegalArgumentException("Cannot use @Column and @Computed on the same property");
104104
}
105105
}
106106
}
107107

108-
static <T> void validatePrimaryKeyOnUDT(MappedProperty<T> property) {
109-
switch (property.kind()) {
110-
case PARTITION_KEY:
111-
throw new IllegalArgumentException("Annotation @PartitionKey is not allowed in a class annotated by @UDT");
112-
case CLUSTERING_COLUMN:
113-
throw new IllegalArgumentException("Annotation @ClusteringColumn is not allowed in a class annotated by @UDT");
114-
default:
115-
break;
116-
}
108+
static void validatePrimaryKeyOnUDT(PropertyMapper property) {
109+
if (property.isPartitionKey())
110+
throw new IllegalArgumentException("Annotation @PartitionKey is not allowed in a class annotated by @UDT");
111+
else if (property.isClusteringColumn())
112+
throw new IllegalArgumentException("Annotation @ClusteringColumn is not allowed in a class annotated by @UDT");
117113
}
118114

119-
static <T> void validateOrder(List<MappedProperty<T>> properties, String annotation) {
115+
static void validateOrder(List<PropertyMapper> properties, String annotation) {
120116
for (int i = 0; i < properties.size(); i++) {
121-
MappedProperty<?> property = properties.get(i);
122-
int pos = property.position();
117+
PropertyMapper property = properties.get(i);
118+
int pos = property.getPosition();
123119
if (pos != i)
124-
throw new IllegalArgumentException(String.format("Invalid ordering value %d for annotation %s of column %s, was expecting %d",
125-
pos, annotation, property.name(), i));
120+
throw new IllegalArgumentException(String.format("Invalid ordering value %d for annotation %s of property %s, was expecting %d",
121+
pos, annotation, property, i));
126122
}
127123
}
128124
}

0 commit comments

Comments
 (0)