DefaultCouchbaseTypeMapper uses TypeAlias annotation if present.

DefaultCouchbaseTypeMapper uses TypeAlias annotation if present.
Test case also uncovered that TypeAlias was being ignored for
string queries.

Closes #1119.
Original pull request: #1120.

Co-authored-by: mikereiche <michael.reiche@couchbase.com>
This commit is contained in:
Michael Reiche
2021-04-06 08:13:50 -07:00
committed by GitHub
parent 9b848f6254
commit 5a04711a6d
5 changed files with 79 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors
* Copyright 2012-2021 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.
@@ -16,10 +16,13 @@
package org.springframework.data.couchbase.core.convert;
import java.util.Collections;
import org.springframework.data.convert.DefaultTypeMapper;
import org.springframework.data.convert.TypeAliasAccessor;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.mapping.Alias;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.util.TypeInformation;
/**
@@ -27,6 +30,7 @@ import org.springframework.data.util.TypeInformation;
*
* @author Michael Nitschinger
* @author Mark Paluch
* @author Michael Reiche
*/
public class DefaultCouchbaseTypeMapper extends DefaultTypeMapper<CouchbaseDocument> implements CouchbaseTypeMapper {
@@ -43,7 +47,8 @@ public class DefaultCouchbaseTypeMapper extends DefaultTypeMapper<CouchbaseDocum
* @param typeKey the typeKey to use.
*/
public DefaultCouchbaseTypeMapper(final String typeKey) {
super(new CouchbaseDocumentTypeAliasAccessor(typeKey));
super(new CouchbaseDocumentTypeAliasAccessor(typeKey), (MappingContext) null,
Collections.singletonList(new TypeAwareTypeInformationMapper()));
this.typeKey = typeKey;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2012-2021 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.couchbase.core.convert;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.convert.SimpleTypeInformationMapper;
import org.springframework.data.mapping.Alias;
import org.springframework.data.util.TypeInformation;
/**
* TypeAwareTypeInformationMapper - leverages @TypeAlias
*
* @author Michael Reiche
*/
public class TypeAwareTypeInformationMapper extends SimpleTypeInformationMapper {
@Override
public Alias createAliasFor(TypeInformation<?> type) {
TypeAlias[] typeAlias = type.getType().getAnnotationsByType(TypeAlias.class);
if (typeAlias.length == 1) {
return Alias.of(typeAlias[0].value());
}
return super.createAliasFor(type);
}
}

View File

@@ -27,6 +27,7 @@ import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.QueryCriteria;
import org.springframework.data.couchbase.core.query.StringQuery;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.Alias;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.NamedQueries;
@@ -36,6 +37,8 @@ import org.springframework.data.repository.query.QueryMethodEvaluationContextPro
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import com.couchbase.client.java.json.JsonArray;
@@ -81,8 +84,15 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
} else {
throw new IllegalArgumentException("query has no inline Query or named Query not found");
}
Class javaType = getType();
String typeValue = javaType.getName();
TypeInformation<?> typeInfo = ClassTypeInformation.from(javaType);
Alias alias = couchbaseConverter.getTypeAlias(typeInfo);
if (alias != null && alias.isPresent()) {
typeValue = alias.toString();
}
this.queryParser = new StringBasedN1qlQueryParser(queryString, queryMethod, bucketName, couchbaseConverter,
getTypeField(), getTypeValue(), accessor, spelExpressionParser, evaluationContextProvider);
getTypeField(), typeValue, accessor, spelExpressionParser, evaluationContextProvider);
this.parser = spelExpressionParser;
this.parsedExpression = this.queryParser.parsedExpression;
}
@@ -95,8 +105,8 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
return couchbaseConverter.getTypeKey();
}
protected String getTypeValue() {
return getQueryMethod().getEntityInformation().getJavaType().getName();
protected Class getType() {
return getQueryMethod().getEntityInformation().getJavaType();
}
@Override

View File

@@ -18,6 +18,7 @@ package org.springframework.data.couchbase.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.couchbase.core.mapping.Document;
/**
@@ -27,6 +28,7 @@ import org.springframework.data.couchbase.core.mapping.Document;
* @author Michael Reiche
*/
@Document
@TypeAlias("airport")
public class Airport extends ComparableEntity {
@Id String id;

View File

@@ -43,6 +43,8 @@ import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.couchbase.CouchbaseClientFactory;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.query.N1QLExpression;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.QueryCriteria;
import org.springframework.data.couchbase.domain.Address;
import org.springframework.data.couchbase.domain.Airport;
@@ -170,6 +172,20 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
}
}
@Test
void findByTypeAlias() {
Airport vie = null;
try {
vie = new Airport("airports::vie", "vie", "loww");
vie = airportRepository.save(vie);
List<Airport> airports = couchbaseTemplate.findByQuery(Airport.class)
.matching(new Query(QueryCriteria.where(N1QLExpression.x("_class")).is("airport"))).all();
assertFalse(airports.isEmpty(), "should have found aiport");
} finally {
airportRepository.delete(vie);
}
}
@Test
void findByEnum() {
Airport vie = null;
@@ -204,6 +220,7 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
airportRepository.saveAll(
Arrays.stream(iatas).map((iata) -> new Airport("airports::" + iata, iata, iata.toLowerCase(Locale.ROOT)))
.collect(Collectors.toSet()));
couchbaseTemplate.findByQuery(Airport.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
Long count = airportRepository.countFancyExpression(asList("JFK"), asList("jfk"), false);
assertEquals(1, count);