From e87125436ab2bc4d7f91f71d14b4a213c3bcf362 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 25 May 2023 14:24:44 +0200 Subject: [PATCH] Polishing. Add missing generics. Inline superfluous methods. See #1384 --- .../convert/MappingCassandraConverter.java | 39 +-- .../query/AbstractCassandraQuery.java | 17 +- .../query/AbstractReactiveCassandraQuery.java | 21 +- .../CassandraRepositoryQuerySupport.java | 7 + .../data/cassandra/Attachment.java | 324 ++++++++++++++++++ 5 files changed, 348 insertions(+), 60 deletions(-) create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/Attachment.java diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java index 968f50640..671de6b1e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java @@ -39,12 +39,15 @@ import org.springframework.data.cassandra.core.mapping.*; import org.springframework.data.cassandra.core.mapping.Embedded.OnEmpty; import org.springframework.data.convert.CustomConversions; +import org.springframework.data.mapping.AccessOptions; import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; +import org.springframework.data.mapping.PersistentPropertyPath; +import org.springframework.data.mapping.PersistentPropertyPathAccessor; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator; @@ -283,6 +286,7 @@ private Class transformClassToBeanClassLoaderClass(Class entity) { } @Override + @SuppressWarnings("unchecked") public R project(EntityProjection projection, Row row) { if (!projection.isProjection()) { @@ -665,7 +669,7 @@ private void writeWhereFromObject(Object source, Where sink, CassandraPersistent ? getMappingContext().getRequiredPersistentEntity(compositeIdProperty) : entity; - writeWhere(MapId.class.cast(id), sink, whereEntity); + writeWhere((MapId) id, sink, whereEntity); return; } @@ -725,18 +729,6 @@ private void writeWhere(MapId id, Where sink, CassandraPersistentEntity entit } } - private void writeWhere(ConvertingPropertyAccessor accessor, Where sink, CassandraPersistentEntity entity) { - - Assert.isTrue(entity.isCompositePrimaryKey(), - () -> String.format("Entity [%s] is not a composite primary key", entity.getName())); - - for (CassandraPersistentProperty property : entity) { - TypeCodec codec = getCodec(property); - Object value = accessor.getProperty(property, codec.getJavaType().getRawType()); - sink.put(property.getRequiredColumnName(), value); - } - } - private void writeTupleValue(ConvertingPropertyAccessor propertyAccessor, TupleValue tupleValue, CassandraPersistentEntity entity) { @@ -863,7 +855,7 @@ private Class getTargetType(CassandraPersistentProperty property) { */ @Nullable @SuppressWarnings("unchecked") - private T getWriteValue(CassandraPersistentProperty property, ConvertingPropertyAccessor propertyAccessor) { + private T getWriteValue(CassandraPersistentProperty property, ConvertingPropertyAccessor propertyAccessor) { ColumnType cassandraTypeDescriptor = cassandraTypeResolver.resolve(property); @@ -914,7 +906,7 @@ private Object getWriteValue(@Nullable Object value, ColumnType columnType) { return writeMapInternal((Map) value, columnType); } - TypeInformation type = TypeInformation.of((Class) value.getClass()); + TypeInformation type = TypeInformation.of((Class) value.getClass()); TypeInformation actualType = type.getRequiredActualType(); BasicCassandraPersistentEntity entity = getMappingContext().getPersistentEntity(actualType.getType()); @@ -989,7 +981,6 @@ private Object writeMapInternal(Map source, ColumnType type) { * @param requestedTargetType must not be {@literal null}. * @see org.springframework.data.cassandra.core.mapping.CassandraType */ - @SuppressWarnings("unchecked") @Nullable private Object getPotentiallyConvertedSimpleValue(@Nullable Object value, @Nullable Class requestedTargetType) { @@ -1237,7 +1228,7 @@ public T getParameterValue(Parameter paramet * Extension of {@link SpELExpressionParameterValueProvider} to recursively trigger value conversion on the raw * resolved SpEL value. */ - private class ConverterAwareSpELExpressionParameterValueProvider + private static class ConverterAwareSpELExpressionParameterValueProvider extends SpELExpressionParameterValueProvider { private final ConversionContext context; @@ -1450,16 +1441,8 @@ private CassandraPersistentProperty getPersistentProperty(String name, TypeInfor } } - private static class PropertyTranslatingPropertyAccessor implements PersistentPropertyPathAccessor { - - private final PersistentPropertyAccessor delegate; - private final PersistentPropertyTranslator propertyTranslator; - - private PropertyTranslatingPropertyAccessor(PersistentPropertyAccessor delegate, - PersistentPropertyTranslator propertyTranslator) { - this.delegate = delegate; - this.propertyTranslator = propertyTranslator; - } + private record PropertyTranslatingPropertyAccessor (PersistentPropertyAccessor delegate, + PersistentPropertyTranslator propertyTranslator) implements PersistentPropertyPathAccessor { static PersistentPropertyAccessor create(PersistentPropertyAccessor delegate, PersistentPropertyTranslator propertyTranslator) { @@ -1566,7 +1549,7 @@ static class MapPersistentPropertyAccessor implements PersistentPropertyAccessor Map map = new LinkedHashMap<>(); @Override - public void setProperty(PersistentProperty persistentProperty, Object o) { + public void setProperty(PersistentProperty persistentProperty, @Nullable Object o) { map.put(persistentProperty.getName(), o); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java index 4d80f983c..097ccdee3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java @@ -17,8 +17,6 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.data.cassandra.core.CassandraOperations; -import org.springframework.data.cassandra.core.convert.CassandraConverter; -import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; import org.springframework.data.cassandra.repository.query.CassandraQueryExecution.CollectionExecution; import org.springframework.data.cassandra.repository.query.CassandraQueryExecution.ExistsExecution; import org.springframework.data.cassandra.repository.query.CassandraQueryExecution.ResultProcessingConverter; @@ -31,7 +29,6 @@ import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.ResultProcessor; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.cql.Statement; @@ -56,7 +53,7 @@ public abstract class AbstractCassandraQuery extends CassandraRepositoryQuerySup */ public AbstractCassandraQuery(CassandraQueryMethod queryMethod, CassandraOperations operations) { - super(queryMethod, toMappingContext(operations)); + super(queryMethod, operations.getConverter().getMappingContext()); this.operations = operations; } @@ -81,7 +78,7 @@ public Object execute(Object[] parameters) { Statement statement = createQuery(parameterAccessor); CassandraQueryExecution queryExecution = getExecution(parameterAccessor, - new ResultProcessingConverter(resultProcessor, toMappingContext(getOperations()), getEntityInstantiators())); + new ResultProcessingConverter(resultProcessor, getMappingContext(), getEntityInstantiators())); Class resultType = resolveResultType(resultProcessor); @@ -170,14 +167,4 @@ private CassandraQueryExecution getExecutionToWrap(CassandraParameterAccessor pa */ protected abstract boolean isModifyingQuery(); - private static CassandraConverter toConverter(CassandraOperations operations) { - - Assert.notNull(operations, "CassandraOperations must not be null"); - - return operations.getConverter(); - } - - private static CassandraMappingContext toMappingContext(CassandraOperations operations) { - return toConverter(operations).getMappingContext(); - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractReactiveCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractReactiveCassandraQuery.java index 2ff8df085..d9f3851fa 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractReactiveCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractReactiveCassandraQuery.java @@ -22,8 +22,6 @@ import org.springframework.data.cassandra.ReactiveResultSet; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.ReactiveCassandraOperations; -import org.springframework.data.cassandra.core.convert.CassandraConverter; -import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; import org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryExecution.CollectionExecution; import org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryExecution.ExistsExecution; import org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryExecution.ResultProcessingConverter; @@ -33,7 +31,6 @@ import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.ResultProcessor; -import org.springframework.util.Assert; import com.datastax.oss.driver.api.core.cql.SimpleStatement; @@ -58,7 +55,7 @@ public abstract class AbstractReactiveCassandraQuery extends CassandraRepository */ public AbstractReactiveCassandraQuery(ReactiveCassandraQueryMethod method, ReactiveCassandraOperations operations) { - super(method, getRequiredMappingContext(operations)); + super(method, operations.getConverter().getMappingContext()); this.operations = operations; } @@ -83,8 +80,8 @@ private Publisher executeLater(ReactiveCassandraParameterAccessor parame Mono statement = createQuery(parameterAccessor); ResultProcessor resultProcessor = getQueryMethod().getResultProcessor().withDynamicProjection(parameterAccessor); - ReactiveCassandraQueryExecution queryExecution = getExecution(parameterAccessor, new ResultProcessingConverter( - resultProcessor, getRequiredMappingContext(getReactiveCassandraOperations()), getEntityInstantiators())); + ReactiveCassandraQueryExecution queryExecution = getExecution(parameterAccessor, + new ResultProcessingConverter(resultProcessor, getMappingContext(), getEntityInstantiators())); Class resultType = resolveResultType(resultProcessor); @@ -94,7 +91,7 @@ private Publisher executeLater(ReactiveCassandraParameterAccessor parame private Class resolveResultType(ResultProcessor resultProcessor) { CassandraReturnedType returnedType = new CassandraReturnedType(resultProcessor.getReturnedType(), - getRequiredConverter(getReactiveCassandraOperations()).getCustomConversions()); + getReactiveCassandraOperations().getConverter().getCustomConversions()); return returnedType.getResultType(); } @@ -173,14 +170,4 @@ private ReactiveCassandraQueryExecution getExecutionToWrap(CassandraParameterAcc */ protected abstract boolean isModifyingQuery(); - private static CassandraConverter getRequiredConverter(ReactiveCassandraOperations operations) { - - Assert.notNull(operations, "ReactiveCassandraOperations must not be null"); - - return operations.getConverter(); - } - - private static CassandraMappingContext getRequiredMappingContext(ReactiveCassandraOperations operations) { - return getRequiredConverter(operations).getMappingContext(); - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraRepositoryQuerySupport.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraRepositoryQuerySupport.java index 87641ffb1..48142f4d9 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraRepositoryQuerySupport.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraRepositoryQuerySupport.java @@ -49,6 +49,8 @@ public abstract class CassandraRepositoryQuerySupport implements RepositoryQuery private final QueryStatementCreator queryStatementCreator; + private final MappingContext, CassandraPersistentProperty> mappingContext; + /** * Create a new {@link AbstractCassandraQuery} from the given {@link CassandraQueryMethod} and * {@link CassandraOperations}. @@ -78,6 +80,7 @@ public CassandraRepositoryQuerySupport(CassandraQueryMethod queryMethod, this.queryMethod = queryMethod; this.instantiators = new EntityInstantiators(); this.queryStatementCreator = new QueryStatementCreator(queryMethod, mappingContext); + this.mappingContext = mappingContext; } @Override @@ -93,6 +96,10 @@ protected QueryStatementCreator getQueryStatementCreator() { return this.queryStatementCreator; } + protected MappingContext, CassandraPersistentProperty> getMappingContext() { + return mappingContext; + } + class CassandraReturnedType { private final ReturnedType returnedType; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/Attachment.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/Attachment.java new file mode 100644 index 000000000..94137a3b8 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/Attachment.java @@ -0,0 +1,324 @@ +/* + * Copyright 2023 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; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.cassandra.core.cql.PrimaryKeyType; +import org.springframework.data.cassandra.core.mapping.CassandraType; +import org.springframework.data.cassandra.core.mapping.Column; +import org.springframework.data.cassandra.core.mapping.PrimaryKey; +import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass; +import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; +import org.springframework.data.cassandra.core.mapping.Table; +import org.springframework.data.cassandra.core.mapping.UserDefinedType; + +import java.util.Date; + +@lombok.Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Table(Attachment.TABLE_NAME) +public class Attachment { + + public static final String TABLE_NAME = "attachment"; + + public static final String PARENT_ID = "parent_id"; + public static final String DATA = "data"; + @Getter + @Setter + @PrimaryKey + private Key id; + + @Getter + @Setter + @CassandraType(type = CassandraType.Name.BIGINT) + @Column(PARENT_ID) + private Long parentId; + + @Getter + @Setter + @Column(DATA) + private AttachmentData data; + + @lombok.Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + @PrimaryKeyClass + public static class Key { + + public static final String MESSAGE_ID = "message_id"; + public static final String ATTACHMENT_ID = "attachment_id"; + + /** + * ID сообщения. + * + * {@code GEPS.ATTACHMENT.MESSAGE_ID} + */ + @PrimaryKeyColumn(value = MESSAGE_ID, type = PrimaryKeyType.PARTITIONED, ordinal = 0) + private long messageId; + + /** + * ID вложения. + * + * {@code GEPS.ATTACHMENT.ATTACHMENT_ID} + */ + @PrimaryKeyColumn(value = ATTACHMENT_ID, type = PrimaryKeyType.CLUSTERED, ordinal = 1) + private long attachmentId; + + } + + @Builder + @AllArgsConstructor + @NoArgsConstructor + @EqualsAndHashCode + @ToString + @UserDefinedType(value = Attachment.AttachmentData.TYPE_NAME) + public static class AttachmentData { + + public static final String TYPE_NAME = "attachment_data"; + + public static final String DT_FILE_NAME = "file_name"; + public static final String DT_FILE_SIZE = "file_size"; + public static final String DT_MIME_TYPE = "mime_type"; + public static final String DT_SPF_BLANK_ID = "spf_blank_id"; + public static final String DT_STATUS = "status"; + public static final String DT_EXTERNAL_LINK = "external_link"; + public static final String DT_CREATE_DATE = "create_date"; + public static final String DT_UPDATE_DATE = "update_date"; + public static final String DT_BASE_DIR_ID = "base_dir_id"; + + /** + * Исходное имя файла вложения. + * + * {@code GEPS.ATTACHMENT_FILE_NAME} + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.VARCHAR) + @Column(DT_FILE_NAME) + private String fileName; + + /** + * Размер файла вложения. + * Может быть не заполнен т.к. размер не известен на этапе добавления сообщения в БД (при скачивании из ИС ПР). + * + * {@code GEPS.ATTACHMENT.FILE_SIZE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.BIGINT) + @Column(DT_FILE_SIZE) + private Long fileSize; + + /** + * MIME-type файла вложения. + * + * {@code GEPS.ATTACHMENT.MIME_TYPE} + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.VARCHAR) + @Column(DT_MIME_TYPE) + private String mimeType; + + /** + * Код бланка сервера печатных форм для создания pdf представления вложения. + * + * {@code GEPS.ATTACHMENT.SPF_BLANK_ID}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.VARCHAR) + @Column(DT_SPF_BLANK_ID) + private String spfBlankId; + + /** + * Статус загрузки вложения. + * {@code GEPS.ATTACHMENT.STATUS}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.ASCII) + @Column(DT_STATUS) + private String status; + + /** + * Ссылка на внешний файл вложения. + * + * {@code GEPS.ATTACHMENT.EXTERNAL_LINK}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.VARCHAR) + @Column(DT_EXTERNAL_LINK) + private String externalLink; + + /** + * ID маппера для сохранения вложений. + * + * {@code GEPS.ATTACHMENT.BASE_DIR_ID}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.SMALLINT) + @Column(DT_BASE_DIR_ID) + private Short baseDirId; + + /** + * Время создания (используется при переносе из Oracle) + * + * {@code GEPS.ATTACHMENT_SIGNATURE.CREATE_DATE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.TIMESTAMP) + @Column(DT_CREATE_DATE) + private Date createDate; + + /** + * Время обновления (используется при переносе из Oracle) + * + * {@code GEPS.ATTACHMENT_SIGNATURE.UPDATE_DATE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.TIMESTAMP) + @Column(DT_UPDATE_DATE) + private Date updateDate; + + } + + @Builder + @AllArgsConstructor + @NoArgsConstructor + @EqualsAndHashCode + @ToString + @UserDefinedType(value = Attachment.AttachmentSignature.TYPE_NAME) + public static class AttachmentSignature { + + public static final String TYPE_NAME = "attachment_signature"; + + public static final String DT_STATUS = "eds_status"; + public static final String DT_START_DATE = "eds_start_date"; + public static final String DT_FINISH_DATE = "eds_finish_date"; + public static final String DT_CREATE_DATE = "create_date"; + public static final String DT_UPDATE_DATE = "update_date"; + public static final String DT_FILE_NAME = "file_name"; + public static final String DT_BASE_DIR_ID = "eds_base_dir"; + + /** + * Статус EDS-верификации вложения. + * GET_DICTIONARY_ELEMENT_MNEMONIC(EDS_STATUS) + * GEPS.ATTACHMENT_SIGNATURE.EDS_STATUS + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NEWEDS-верификации не запускалась
RUNNINGEDS-верификация подписи вложении запущена, продолжается
OKEDS-верификация подписи вложения успешно проведена в ГУЦ СМЭВ3
ERROREDS-верификация завершилась с ошибкой
+ * + * {@code GEPS.ATTACHMENT_SIGNATURE.EDS_STATUS}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.ASCII) + @Column(DT_STATUS) + private String edsStatus; + + /** + * Время запуска EDS-проверки. + * + * {@code GEPS.ATTACHMENT_SIGNATURE.EDS_START_DATE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.TIMESTAMP) + @Column(DT_START_DATE) + private Date edsStartDate; + + /** + * Время завершения EDS-проверки. + * + * {@code GEPS.ATTACHMENT_SIGNATURE.EDS_FINISH_DATE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.TIMESTAMP) + @Column(DT_FINISH_DATE) + private Date edsFinishDate; + + + + /** + * {@code GEPS.ATTACHMENT.CREATE_DATE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.TIMESTAMP) + @Column(DT_CREATE_DATE) + private Date createDate; + + /** + * {@code GEPS.ATTACHMENT.UPDATE_DATE}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.TIMESTAMP) + @Column(DT_UPDATE_DATE) + private Date updateDate; + + /** + * Имя файла eds-подписи вложения. + * + * {@code GEPS.ATTACHMENT_SIGNATURE.FILE_NAME} + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.VARCHAR) + @Column(DT_FILE_NAME) + private String edsFileName; + + /** + * ID маппера для сохранения EDS-подписи вложений. + * + * {@code GEPS.ATTACHMENT_SIGNATURE.EDS_BASE_DIR_ID}. + */ + @Getter + @Setter + @CassandraType(type = CassandraType.Name.SMALLINT) + @Column(DT_BASE_DIR_ID) + private Short edsBaseDirId; + + } + +}