Spring 5 comes with a reactive implementation for spring data mongo , before the i was able to extend my mongo repository with QuerydslPredicateExecutor
@Repository
public interface AccountRepo extends MongoRepository<Account,String>
,QuerydslPredicateExecutor<Account>
if i try this
@Repository
public interface AccountRepo extends
ReactiveMongoRepository<Account,String>,
QuerydslPredicateExecutor<Account>
my application does not start it because :
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property exists found for type Account!
is there a way around this
here is the account class
package com.devop.models;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
@Data
public class Account {
@Id
String id;
String accountName;
String accountNumber;
String schemeCode;
String openDate;
String accountCategory;
String accountCurrency = "Naira";
String accountSecondaryCategory;
String receiveSmsAlert;
String recieveEmailAlert;
String cifId;
}
here is the interface AccountRepo
package com.devop.mongoRepo;
import com.devop.models.Account;
import org.springframework.data.mongodb.repository.*;
import org.springframework.data.mongodb.repository.support*;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Repository
public interface AccountRepo extends
ReactiveMongoRepository<Account,String>
,QuerydslPredicateExecutor<Account> {
Flux<Account> findAccountByAccountNameContains(String accountName);
Mono<Account> findAccountByAccountNumberEquals(String accountNumber);
}
You could use ReactiveQuerydslPredicateExecutor
. See example for more information https://github.com/spring-projects/spring-data-examples/tree/master/mongodb/querydsl
I found a workaround solution
using a Custom ReactiveMongoRepositoryFactoryBean
and ReactiveMongoRepositoryFactory
, it could help someone else that is struggling with that
First you need to use repositoryFactoryBeanClass in the reactive annotation.
@EnableReactiveMongoRepositories(repositoryFactoryBeanClass = CustomReactiveMongoRepositoryFactoryBean.class)
@Configuration
public class ReactiveMongoDbHack {
}
CustomReactiveMongoRepositoryFactoryBean class
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactoryBean;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
public class CustomReactiveMongoRepositoryFactoryBean extends ReactiveMongoRepositoryFactoryBean {
public CustomReactiveMongoRepositoryFactoryBean(Class repositoryInterface) {
super(repositoryInterface);
}
@Override
protected RepositoryFactorySupport getFactoryInstance(ReactiveMongoOperations operations) {
return new CustomReactiveMongoRepositoryFactory(operations);
}
}
CustomReactiveMongoRepositoryFactory class
import static org.springframework.data.querydsl.QuerydslUtils.QUERY_DSL_PRESENT;
public class CustomReactiveMongoRepositoryFactory extends ReactiveMongoRepositoryFactory {
private static MongoOperations operations;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
public CustomReactiveMongoRepositoryFactory(ReactiveMongoOperations operations) {
super(operations);
this.mappingContext = operations.getConverter().getMappingContext();
}
//TODO Must set MongoOperations(MongoTemplate)
public static void setOperations(MongoOperations operations) {
CustomReactiveMongoRepositoryFactory.operations = operations;
}
@Override
protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
RepositoryComposition.RepositoryFragments fragments = RepositoryComposition.RepositoryFragments.empty();
boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
if (isQueryDslRepository) {
MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType(),
metadata);
fragments = fragments.append(RepositoryFragment.implemented(
getTargetRepositoryViaReflection(QuerydslMongoPredicateExecutor.class, entityInformation, operations)));
}
return fragments;
}
private <T, ID> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass,
@Nullable RepositoryMetadata metadata) {
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(domainClass);
return MongoEntityInformationSupport.<T, ID> entityInformationFor(entity,
metadata != null ? metadata.getIdType() : null);
}
}
MongoEntityInformationSupport class copied from spring-data-mongodb
import org.springframework.data.domain.Persistable;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.MappingMongoEntityInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Support class responsible for creating {@link MongoEntityInformation} instances for a given
* {@link MongoPersistentEntity}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.10
*/
final class MongoEntityInformationSupport {
private MongoEntityInformationSupport() {}
/**
* Factory method for creating {@link MongoEntityInformation}.
*
* @param entity must not be {@literal null}.
* @param idType can be {@literal null}.
* @return never {@literal null}.
*/
@SuppressWarnings("unchecked")
static <T, ID> MongoEntityInformation<T, ID> entityInformationFor(MongoPersistentEntity<?> entity,
@Nullable Class<?> idType) {
Assert.notNull(entity, "Entity must not be null!");
MappingMongoEntityInformation<T, ID> entityInformation = new MappingMongoEntityInformation<T, ID>(
(MongoPersistentEntity<T>) entity, (Class<ID>) idType);
return ClassUtils.isAssignable(Persistable.class, entity.getType())
? new PersistableMongoEntityInformation<>(entityInformation) : entityInformation;
}
}
PersistableMongoEntityInformation class also copied from spring-data-mongodb
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Persistable;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
/**
* {@link MongoEntityInformation} implementation wrapping an existing {@link MongoEntityInformation} considering
* {@link Persistable} types by delegating {@link #isNew(Object)} and {@link #getId(Object)} to the corresponding
* {@link Persistable#isNew()} and {@link Persistable#getId()} implementations.
*
* @author Christoph Strobl
* @author Oliver Gierke
* @since 1.10
*/
@RequiredArgsConstructor
class PersistableMongoEntityInformation<T, ID> implements MongoEntityInformation<T, ID> {
private final @NonNull MongoEntityInformation<T, ID> delegate;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.MongoEntityInformation#getCollectionName()
*/
@Override
public String getCollectionName() {
return delegate.getCollectionName();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.MongoEntityInformation#getIdAttribute()
*/
@Override
public String getIdAttribute() {
return delegate.getIdAttribute();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.EntityInformation#isNew(java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public boolean isNew(T t) {
if (t instanceof Persistable) {
return ((Persistable<ID>) t).isNew();
}
return delegate.isNew(t);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public ID getId(T t) {
if (t instanceof Persistable) {
return ((Persistable<ID>) t).getId();
}
return delegate.getId(t);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.PersistentEntityInformation#getIdType()
*/
@Override
public Class<ID> getIdType() {
return delegate.getIdType();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.EntityMetadata#getJavaType()
*/
@Override
public Class<T> getJavaType() {
return delegate.getJavaType();
}
}
Then your Reactive Repository with Query DSL would work.
public interface AssetRepository extends ReactiveCrudRepository<Asset, String>, QuerydslPredicateExecutor<Asset> {
}
PS: It must need to set MongoOperations at CustomReactiveMongoRepositoryFactory.setOperations
, what I did was to use the auto config classes(MongoAutoConfiguration and MongoDataAutoConfiguration) for Mongo then using @PostConstruct
in a method to set it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.