DATACASS-465 - Polishing.
Remove FrozenIndicator from public API. Refactor to recursive type to reflect property type declaration nature. Rename to FrozenIndicator. Update documentation. Original pull request: #172.
This commit is contained in:
@@ -88,8 +88,9 @@ public interface ColumnType {
|
||||
* @return
|
||||
*/
|
||||
static CassandraColumnType listOf(CassandraColumnType componentType) {
|
||||
return listOf(componentType, FrozenInfo.NOT_FROZEN);
|
||||
return listOf(componentType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a List {@link ColumnType} given its {@link CassandraColumnType component type}.
|
||||
*
|
||||
@@ -97,9 +98,9 @@ public interface ColumnType {
|
||||
* @param frozen
|
||||
* @return
|
||||
*/
|
||||
static CassandraColumnType listOf(CassandraColumnType componentType, FrozenInfo frozen) {
|
||||
static CassandraColumnType listOf(CassandraColumnType componentType, boolean frozen) {
|
||||
return new DefaultCassandraColumnType(ClassTypeInformation.LIST,
|
||||
() -> DataTypes.listOf(componentType.getDataType(), frozen.self), componentType);
|
||||
() -> DataTypes.listOf(componentType.getDataType(), frozen), componentType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,18 +125,19 @@ public interface ColumnType {
|
||||
* @return
|
||||
*/
|
||||
static CassandraColumnType setOf(CassandraColumnType componentType) {
|
||||
return setOf(componentType, FrozenInfo.NOT_FROZEN);
|
||||
return setOf(componentType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Set {@link ColumnType} given its {@link CassandraColumnType component type}.
|
||||
*
|
||||
* @param componentType must not be {@literal null}.
|
||||
* @param frozen must not be {@literal null}.
|
||||
* @param frozen
|
||||
* @return
|
||||
*/
|
||||
static CassandraColumnType setOf(CassandraColumnType componentType, FrozenInfo frozen) {
|
||||
return new DefaultCassandraColumnType(ClassTypeInformation.SET, () -> DataTypes.setOf(componentType.getDataType(),frozen.self),
|
||||
componentType);
|
||||
static CassandraColumnType setOf(CassandraColumnType componentType, boolean frozen) {
|
||||
return new DefaultCassandraColumnType(ClassTypeInformation.SET,
|
||||
() -> DataTypes.setOf(componentType.getDataType(), frozen), componentType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||
import org.springframework.data.cassandra.core.mapping.Frozen;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -63,21 +62,6 @@ public interface ColumnTypeResolver {
|
||||
*/
|
||||
CassandraColumnType resolve(TypeInformation<?> typeInformation);
|
||||
|
||||
/**
|
||||
* Resolve a {@link CassandraColumnType} from {@link TypeInformation}. Considers potentially registered custom
|
||||
* converters and simple type rules.
|
||||
*
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
* @param frozen must not be {@literal null}.
|
||||
* @return
|
||||
* @see org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder
|
||||
* @see CassandraCustomConversions
|
||||
* @throws org.springframework.dao.InvalidDataAccessApiUsageException
|
||||
*/
|
||||
default CassandraColumnType resolve(TypeInformation<?> typeInformation, FrozenInfo frozen) {
|
||||
return resolve(typeInformation, FrozenInfo.NOT_FROZEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a {@link CassandraColumnType} from a {@link CassandraType} annotation.
|
||||
*
|
||||
|
||||
@@ -27,7 +27,8 @@ import java.util.stream.StreamSupport;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
@@ -98,8 +99,6 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
||||
|
||||
Assert.notNull(property, "Property must not be null");
|
||||
|
||||
FrozenInfo frozen = getFrozenInfo(property);
|
||||
|
||||
if (property.isAnnotationPresent(CassandraType.class)) {
|
||||
|
||||
CassandraType annotation = property.getRequiredAnnotation(CassandraType.class);
|
||||
@@ -128,48 +127,51 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
||||
}
|
||||
|
||||
TypeInformation<?> typeInformation = property.getTypeInformation();
|
||||
return resolve(typeInformation, frozen);
|
||||
return resolve(typeInformation, getFrozenInfo(property));
|
||||
}
|
||||
|
||||
private FrozenInfo getFrozenInfo(CassandraPersistentProperty property) {
|
||||
private FrozenIndicator getFrozenInfo(CassandraPersistentProperty property) {
|
||||
|
||||
FrozenInfo frozen = FrozenInfo.frozen(property.isAnnotationPresent(Frozen.class));
|
||||
AnnotatedType annotatedType = property.findAnnotatedType(Frozen.class);
|
||||
|
||||
if (annotatedType == null) {
|
||||
return FrozenIndicator.NOT_FROZEN;
|
||||
}
|
||||
|
||||
return getFrozenIndicator(annotatedType);
|
||||
}
|
||||
|
||||
private FrozenIndicator getFrozenIndicator(AnnotatedType annotatedType) {
|
||||
|
||||
FrozenIndicator frozen = FrozenIndicator.frozen(isFrozen(annotatedType));
|
||||
|
||||
if (annotatedType instanceof AnnotatedParameterizedType) {
|
||||
|
||||
AnnotatedParameterizedType apt = (AnnotatedParameterizedType) annotatedType;
|
||||
AnnotatedType[] annotatedTypes = apt.getAnnotatedActualTypeArguments();
|
||||
|
||||
if (annotatedTypes.length > 0) {
|
||||
|
||||
AnnotatedType type1 = annotatedTypes[0];
|
||||
frozen = frozen.withFirstTypeParameter(type1.isAnnotationPresent(Frozen.class));
|
||||
if (annotatedTypes.length > 1) {
|
||||
|
||||
AnnotatedType type2 = annotatedTypes[1];
|
||||
frozen = frozen.withSecondTypeParameter(type2.isAnnotationPresent(Frozen.class));
|
||||
}
|
||||
for (AnnotatedType type : annotatedTypes) {
|
||||
frozen.addNested(getFrozenIndicator(type));
|
||||
}
|
||||
}
|
||||
|
||||
return frozen;
|
||||
}
|
||||
|
||||
private boolean isFrozen(AnnotatedType type) {
|
||||
return AnnotatedElementUtils.hasAnnotation(type, Frozen.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.ColumnTypeResolver#resolve(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public CassandraColumnType resolve(TypeInformation<?> typeInformation) {
|
||||
return resolve(typeInformation, FrozenInfo.NOT_FROZEN);
|
||||
return resolve(typeInformation, FrozenIndicator.NOT_FROZEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.ColumnTypeResolver#resolve(org.springframework.data.util.TypeInformation, org.springframework.data.cassandra.core.convert.FrozenInfo)
|
||||
*/
|
||||
@Override
|
||||
public CassandraColumnType resolve(TypeInformation<?> typeInformation, FrozenInfo frozen) {
|
||||
private CassandraColumnType resolve(TypeInformation<?> typeInformation, FrozenIndicator frozen) {
|
||||
|
||||
return getCustomWriteTarget(typeInformation).map(it -> {
|
||||
return createCassandraTypeDescriptor(tryResolve(it), ClassTypeInformation.from(it));
|
||||
@@ -389,24 +391,23 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
||||
return new DefaultCassandraColumnType(typeInformation, dataType);
|
||||
}
|
||||
|
||||
private CassandraColumnType createCassandraTypeDescriptor(TypeInformation<?> typeInformation, FrozenInfo frozen) {
|
||||
private CassandraColumnType createCassandraTypeDescriptor(TypeInformation<?> typeInformation,
|
||||
FrozenIndicator frozen) {
|
||||
|
||||
if (List.class.isAssignableFrom(typeInformation.getType())) {
|
||||
|
||||
FrozenInfo elementFrozen = frozen.forFirstTypeParameter();
|
||||
return ColumnType.listOf(resolve(typeInformation.getRequiredComponentType(), elementFrozen), frozen);
|
||||
return ColumnType.listOf(resolve(typeInformation.getRequiredComponentType(), frozen.getFrozen(0)),
|
||||
frozen.isFrozen());
|
||||
}
|
||||
|
||||
if (Set.class.isAssignableFrom(typeInformation.getType())) {
|
||||
|
||||
FrozenInfo elementFrozen = frozen.forFirstTypeParameter();
|
||||
return ColumnType.setOf(resolve(typeInformation.getRequiredComponentType(), elementFrozen), frozen);
|
||||
return ColumnType.setOf(resolve(typeInformation.getRequiredComponentType(), frozen.getFrozen(0)),
|
||||
frozen.isFrozen());
|
||||
}
|
||||
|
||||
if (typeInformation.isMap()) {
|
||||
|
||||
FrozenInfo frozenKey = frozen.forFirstTypeParameter();
|
||||
FrozenInfo frozenValue = frozen.forSecondTypeParameter();
|
||||
FrozenIndicator frozenKey = frozen.getFrozen(0);
|
||||
FrozenIndicator frozenValue = frozen.getFrozen(1);
|
||||
|
||||
return ColumnType.mapOf(resolve(typeInformation.getRequiredComponentType(), frozenKey),
|
||||
resolve(typeInformation.getRequiredMapValueType(), frozenValue));
|
||||
@@ -417,7 +418,7 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
||||
if (persistentEntity != null) {
|
||||
|
||||
if (persistentEntity.isUserDefinedType()) {
|
||||
return new DefaultCassandraColumnType(typeInformation, getUserType(persistentEntity, frozen.self));
|
||||
return new DefaultCassandraColumnType(typeInformation, getUserType(persistentEntity, frozen.isFrozen()));
|
||||
}
|
||||
|
||||
if (persistentEntity.isTupleType()) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Information about if a type or its elements should be frozen or not.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
class FrozenIndicator {
|
||||
|
||||
public static final FrozenIndicator NOT_FROZEN = new FrozenIndicator();
|
||||
|
||||
private final boolean frozen;
|
||||
private final List<FrozenIndicator> nested = new ArrayList<>();
|
||||
|
||||
public static FrozenIndicator frozen(boolean frozen) {
|
||||
return new FrozenIndicator(frozen);
|
||||
}
|
||||
|
||||
private FrozenIndicator() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
private FrozenIndicator(boolean frozen) {
|
||||
this.frozen = frozen;
|
||||
}
|
||||
|
||||
public void addNested(FrozenIndicator frozenIndicator) {
|
||||
this.nested.add(frozenIndicator);
|
||||
}
|
||||
|
||||
boolean isFrozen() {
|
||||
return frozen;
|
||||
}
|
||||
|
||||
FrozenIndicator getFrozen(int parameterIndex) {
|
||||
return parameterIndex < this.nested.size() ? this.nested.get(parameterIndex) : NOT_FROZEN;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
/**
|
||||
* Information about if a type or its elements should be frozen or not.
|
||||
*/
|
||||
public class FrozenInfo {
|
||||
|
||||
public static final FrozenInfo NOT_FROZEN = new FrozenInfo();
|
||||
|
||||
final boolean self;
|
||||
final boolean firstTypeParameter;
|
||||
final boolean secondTypeParameter;
|
||||
|
||||
public static FrozenInfo frozen(boolean frozen) {
|
||||
return new FrozenInfo(frozen);
|
||||
}
|
||||
|
||||
private FrozenInfo() {
|
||||
this(false, false, false);
|
||||
}
|
||||
|
||||
private FrozenInfo(boolean selfFrozen) {
|
||||
this(selfFrozen, false, false);
|
||||
}
|
||||
|
||||
private FrozenInfo(boolean self, boolean firstTypeParameter, boolean secondTypeParameter) {
|
||||
|
||||
this.self = self;
|
||||
this.firstTypeParameter = firstTypeParameter;
|
||||
this.secondTypeParameter = secondTypeParameter;
|
||||
}
|
||||
|
||||
FrozenInfo withFirstTypeParameter(boolean firstTypeParameter) {
|
||||
return new FrozenInfo(self, firstTypeParameter, secondTypeParameter);
|
||||
}
|
||||
|
||||
FrozenInfo withSecondTypeParameter(boolean secondTypeParameter) {
|
||||
return new FrozenInfo(self, firstTypeParameter, secondTypeParameter);
|
||||
}
|
||||
|
||||
FrozenInfo forFirstTypeParameter() {
|
||||
return new FrozenInfo(firstTypeParameter);
|
||||
}
|
||||
|
||||
FrozenInfo forSecondTypeParameter() {
|
||||
return new FrozenInfo(secondTypeParameter);
|
||||
}
|
||||
}
|
||||
@@ -22,15 +22,16 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specifies a type as "frozen".
|
||||
* Indicates that a persistent property should use a {@code frozen} column type.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @see <a href="https://express-cassandra.readthedocs.io/en/stable/advanced/#frozen-collections">Documentation about frozen collections</a>
|
||||
* @see <a href="https://express-cassandra.readthedocs.io/en/stable/advanced/#frozen-collections">Documentation about
|
||||
* frozen collections</a>
|
||||
* @since 3.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = {ElementType.TYPE_USE, ElementType.FIELD, ElementType.METHOD})
|
||||
@Target(value = { ElementType.TYPE_USE, ElementType.FIELD, ElementType.METHOD })
|
||||
public @interface Frozen {
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
* Unit tests for {@link DefaultColumnTypeResolver}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class ColumnTypeResolverUnitTests {
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ This chapter summarizes changes and new features for each release.
|
||||
|
||||
* Upgrade to Cassandra Driver version 4. See the <<cassandra.migration.2.x-to-3.x,2.x to 3.x migration guide for details>>.
|
||||
* Support for `NamingStrategy`.
|
||||
* Support for frozen collections and UDT columns in schema creation.
|
||||
|
||||
[[new-features.2-2-0]]
|
||||
== What's new in Spring Data for Apache Cassandra 2.2
|
||||
|
||||
@@ -377,6 +377,8 @@ Describes the index to be created at session initialization.
|
||||
Allows SASI index creation during session initialization.
|
||||
* `@CassandraType`: Applied at the field level to specify a Cassandra data type.
|
||||
Types are derived from the property declaration by default.
|
||||
* `@Frozen`: Applied at the field level to class-types and parametrized types.
|
||||
Declares a frozen UDT column or frozen collection like `List<@Frozen UserDefinedPersonType>`.
|
||||
* `@UserDefinedType`: Applied at the type level to specify a Cassandra User-defined Data Type (UDT).
|
||||
Types are derived from the declaration by default.
|
||||
* `@Tuple`: Applied at the type level to use a type as a mapped tuple.
|
||||
|
||||
Reference in New Issue
Block a user