Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
- [new feature] JAVA-1157: Allow asynchronous paging of Mapper Result.
- [improvement] JAVA-1212: Don't retry non-idempotent statements by default.
- [improvement] JAVA-1192: Make EventDebouncer settings updatable at runtime.
- [new feature] JAVA-541: Add polymorphism support to object mapper.
- [new feature] JAVA-636: Allow @Column annotations on getters/setters as well as fields.
- [new feature] JAVA-984: Allow non-void setters in object mapping.

Merged from 3.0.x branch:

Expand Down
7 changes: 7 additions & 0 deletions clirr-ignores.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
-->
<differences>

<difference>
<differenceType>8001</differenceType> <!-- class removed -->
<className>com/datastax/driver/mapping/ColumnMapper$Kind</className>
<justification>False positive, the enclosing class is package-private so this was never exposed</justification>
</difference>


<difference>
<differenceType>1001</differenceType> <!-- decreased visibility -->
<className>com/datastax/driver/mapping/ColumnMapper$Kind</className>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ public enum ClusteringOrder {

ASC, DESC;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,35 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

abstract class AccessorMapper<T> {
class AccessorMapper<T> {

public final Class<T> daoClass;
protected final List<MethodMapper> methods;
final Class<T> daoClass;
final List<MethodMapper> methods;
private final Class<T>[] proxyClasses;
private final AccessorInvocationHandler<T> handler;

protected AccessorMapper(Class<T> daoClass, List<MethodMapper> methods) {
@SuppressWarnings({"unchecked", "rawtypes"})
AccessorMapper(Class<T> daoClass, List<MethodMapper> methods) {
this.daoClass = daoClass;
this.methods = methods;
this.proxyClasses = (Class<T>[]) new Class[]{daoClass};
this.handler = new AccessorInvocationHandler<T>(this);
}

abstract T createProxy();
@SuppressWarnings("unchecked")
T createProxy() {
try {
return (T) Proxy.newProxyInstance(daoClass.getClassLoader(), proxyClasses, handler);
} catch (Exception e) {
throw new RuntimeException("Cannot create instance for Accessor interface " + daoClass.getName());
}
}

public void prepare(MappingManager manager) {
void prepare(MappingManager manager) {
List<ListenableFuture<PreparedStatement>> statements = new ArrayList<ListenableFuture<PreparedStatement>>(methods.size());

for (MethodMapper method : methods)
Expand All @@ -49,7 +62,4 @@ public void prepare(MappingManager manager) {
}
}

interface Factory {
public <T> AccessorMapper<T> create(Class<T> daoClass, List<MethodMapper> methods);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@
*/
package com.datastax.driver.mapping;

import com.datastax.driver.mapping.annotations.Column;
import com.datastax.driver.mapping.annotations.Computed;
import com.datastax.driver.mapping.annotations.Table;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

/**
* Various checks on mapping annotations.
Expand All @@ -36,59 +40,75 @@ class AnnotationChecks {
static <T extends Annotation> T getTypeAnnotation(Class<T> annotation, Class<?> annotatedClass) {
T instance = annotatedClass.getAnnotation(annotation);
if (instance == null)
throw new IllegalArgumentException(String.format("@%s annotation was not found on type %s",
annotation.getSimpleName(), annotatedClass.getName()));
throw new IllegalArgumentException(String.format("@%s annotation was not found on %s",
annotation.getSimpleName(), annotatedClass));

// Check that no other mapping annotations are present
validateAnnotations(annotatedClass, annotation);

return instance;
}

@SuppressWarnings("unchecked")
private static void validateAnnotations(Class<?> clazz, Class<? extends Annotation> allowed) {
@SuppressWarnings("unchecked")
Class<? extends Annotation> invalid = validateAnnotations(clazz.getAnnotations(), allowed);
Collection<Annotation> classAnnotations = new HashSet<Annotation>();
Collections.addAll(classAnnotations, clazz.getAnnotations());
Class<? extends Annotation> invalid = validateAnnotations(classAnnotations, Collections.singleton(allowed));
if (invalid != null)
throw new IllegalArgumentException(String.format("Cannot have both @%s and @%s on type %s",
throw new IllegalArgumentException(String.format("Cannot have both @%s and @%s on %s",
allowed.getSimpleName(), invalid.getSimpleName(),
clazz.getName()));
clazz));
}

/**
* Checks that a field is only annotated with the given mapping annotations, and that its "frozen" annotations are valid.
*/
static void validateAnnotations(Field field, String classDescription, Class<? extends Annotation>... allowed) {
Class<? extends Annotation> invalid = validateAnnotations(field.getAnnotations(), allowed);
if (invalid != null)
throw new IllegalArgumentException(String.format("Annotation @%s is not allowed on field %s of %s %s",
static void validateAnnotations(PropertyMapper property, Collection<? extends Class<? extends Annotation>> allowed) {
Class<? extends Annotation> invalid = validateAnnotations(property.getAnnotations(), allowed);
if (invalid != null) {
throw new IllegalArgumentException(String.format("Annotation @%s is not allowed on property '%s'",
invalid.getSimpleName(),
field.getName(), classDescription,
field.getDeclaringClass().getName()));

checkValidComputed(field);
property));
}
checkValidPrimaryKey(property);
checkValidComputed(property);
}

// Returns the offending annotation if there is one
private static Class<? extends Annotation> validateAnnotations(Annotation[] annotations, Class<? extends Annotation>... allowed) {
private static Class<? extends Annotation> validateAnnotations(Collection<Annotation> annotations, Collection<? extends Class<? extends Annotation>> allowed) {
for (Annotation annotation : annotations) {
Class<? extends Annotation> actual = annotation.annotationType();
if (actual.getPackage().equals(MAPPING_PACKAGE) && !contains(allowed, actual))
if (actual.getPackage().equals(MAPPING_PACKAGE) && !allowed.contains(actual))
return actual;
}
return null;
}

private static boolean contains(Object[] array, Object target) {
for (Object element : array)
if (element.equals(target))
return true;
return false;
private static void checkValidPrimaryKey(PropertyMapper property) {
if (property.isPartitionKey() && property.isClusteringColumn())
throw new IllegalArgumentException(String.format("Property '%s' cannot be annotated with both @PartitionKey and @ClusteringColumn", property));
}

private static void checkValidComputed(PropertyMapper property) {
if (property.isComputed()) {
Computed computed = property.annotation(Computed.class);
if (computed.value().isEmpty()) {
throw new IllegalArgumentException(String.format("Property '%s': attribute 'value' of annotation @Computed is mandatory for computed properties", property));
}
if (property.hasAnnotation(Column.class)) {
throw new IllegalArgumentException(String.format("Property '%s' cannot be annotated with both @Column and @Computed", property));
}
}
}

static void checkValidComputed(Field field) {
Computed computed = field.getAnnotation(Computed.class);
if (computed != null && computed.value().isEmpty()) {
throw new IllegalArgumentException(String.format("Field %s: attribute 'value' of annotation @Computed is mandatory for computed fields", field.getName()));
static void validateOrder(List<PropertyMapper> properties, String annotation) {
for (int i = 0; i < properties.size(); i++) {
PropertyMapper property = properties.get(i);
int pos = property.position;
if (pos != i)
throw new IllegalArgumentException(String.format("Invalid ordering value %d for annotation %s of property '%s', was expecting %d",
pos, annotation, property, i));
}
}
}
Loading